3.0 KiB
SseConnectionRegistry + createConnectionRegistry
(no submodules)
Purpose
SseConnectionRegistry is the multi-index registry for active SSE connections. Engines call add on handshake, remove on disconnect, and the host fans out broadcasts via lookupByTenant / lookupByTopic. Lookups are O(1) by design — the registry keeps a parallel tenantId → Set<conn> and (topic, tenantId) → Set<conn> index so broadcast paths avoid scanning the full connection set.
remove is idempotent: engines can call it from both the graceful-close path and a finaliser without risk of throwing or double-decrementing tenant counts. This matches the shape of WsConnectionRegistry in @suaveplan/api-types/ws so engines that bridge both transports can share lifecycle code.
Features
- O(1) lookup by
tenantIdvialookupByTenant. - O(1) lookup by
(topic, tenantId)vialookupByTopic— cross-tenant fan-out is impossible by construction. countByTenantpowers the per-principal cap check at handshake.add(conn, topics)is mutation-only; topics MUST be supplied ataddtime (nosubscribe(conn, topic)here — topic subscriptions live with the SSE manifest).
Usage: Basic
import { createConnectionRegistry } from "@suaveplan/api-sse/connection-registry/connection-registry";
const reg = createConnectionRegistry();
declare const connection: import("@suaveplan/api-sse/connection/connection").SseConnection;
reg.add(connection, ["orders", "notifications"]);
const audience = reg.lookupByTopic("orders", connection.tenantId);
Usage: Advanced
import { createConnectionRegistry } from "@suaveplan/api-sse/connection-registry/connection-registry";
const reg = createConnectionRegistry();
function broadcast(
tenantId: import("@suaveplan/api-types/tenant").TenantId,
topic: string,
event: import("@suaveplan/api-sse/event/event").SseEvent
) {
return Promise.all(
reg.lookupByTopic(topic, tenantId).map((conn) => conn.send(event))
);
}
// idempotent close
reg.remove(conn);
reg.remove(conn); // does not throw
API Reference
createConnectionRegistry(): SseConnectionRegistryinterface SseConnectionRegistryadd(conn: SseConnection, topics?: readonly string[]): voidremove(conn: SseConnection): void(idempotent)lookupByTenant(tenantId: TenantId): readonly SseConnection[]lookupByTopic(topic: string, tenantId: TenantId): readonly SseConnection[]countByTenant(tenantId: TenantId): numbersize: number
Implementation Notes
The implementation uses a Set per tenant and per (topic, tenantId) key for O(1) add / delete. Topics-per-connection are stashed in a WeakMap so the registry never holds a strong reference past remove — the connection becomes eligible for GC as soon as the engine drops its own handle. The (topic, tenantId) composite key uses a space separator (${tenantId} ${topic}) because branded TenantId cannot contain spaces by construction (resolved at the trust boundary).