opinionated-machine
Version:
Very opinionated DI framework for fastify, built on top of awilix
140 lines (139 loc) • 5.13 kB
TypeScript
import type { SSELogger, SSEMessage } from '../sseTypes.js';
import type { RoomBroadcastOptions, SSERoomAdapter, SSERoomManagerConfig, SSERoomMessageHandler } from './types.js';
/**
* Manages room membership for SSE connections.
*
* Provides Socket.IO-style room support for SSE connections with optional
* cross-node propagation via adapters (e.g., Redis).
*
* **Data Structures (per node):**
* - `connectionRooms: Map<ConnectionId, Set<RoomId>>` - tracks which rooms each connection is in
* - `roomConnections: Map<RoomId, Set<ConnectionId>>` - tracks which connections are in each room
*
* @example Basic usage (single node)
* ```typescript
* const roomManager = new SSERoomManager()
*
* // Join rooms
* roomManager.join(connectionId, 'announcements')
* roomManager.join(connectionId, ['project:123', 'team:eng'])
*
* // Query rooms
* roomManager.getRooms(connectionId) // ['announcements', 'project:123', 'team:eng']
* roomManager.getConnectionsInRoom('team:eng') // [connectionId, ...]
*
* // Leave rooms
* roomManager.leave(connectionId, 'project:123')
* roomManager.leaveAll(connectionId) // Called automatically on disconnect
* ```
*
* @example With Redis adapter (multi-node)
* ```typescript
* import { RedisAdapter } from '@opinionated-machine/sse-rooms-redis'
*
* const roomManager = new SSERoomManager({
* adapter: new RedisAdapter({ pubClient, subClient })
* })
* ```
*/
export declare class SSERoomManager {
/** Map of connection ID to set of room names */
private readonly connectionRooms;
/** Map of room name to set of connection IDs */
private readonly roomConnections;
/** Adapter for cross-node communication */
readonly adapter: SSERoomAdapter;
/** Unique identifier for this node */
readonly nodeId: string;
/** Handler for remote messages from adapter */
private messageHandler?;
constructor(config?: SSERoomManagerConfig);
/**
* Connect the adapter (if applicable).
* Call this during server startup.
*/
connect(): Promise<void>;
/**
* Disconnect the adapter (if applicable).
* Call this during graceful shutdown.
*/
disconnect(): Promise<void>;
/**
* Register a handler for messages from other nodes.
* The controller uses this to forward messages to local connections.
*
* @param handler - Callback invoked when a remote message is received
*/
onRemoteMessage(handler: SSERoomMessageHandler): void;
/**
* Join one or more rooms.
*
* @param connectionId - The connection to add to rooms
* @param room - Room name or array of room names
* @param logger - Used to report adapter subscription failures (optional)
*/
join(connectionId: string, room: string | string[], logger?: SSELogger): void;
/**
* Leave one or more rooms.
*
* @param connectionId - The connection to remove from rooms
* @param room - Room name or array of room names
* @param logger - Used to report adapter unsubscription failures (optional)
*/
leave(connectionId: string, room: string | string[], logger?: SSELogger): void;
/**
* Leave all rooms for a connection.
* Called automatically when a connection disconnects.
*
* @param connectionId - The connection to remove from all rooms
* @returns Array of room names the connection was in
*/
leaveAll(connectionId: string): string[];
/**
* Get all rooms a connection is in.
*
* @param connectionId - The connection to query
* @returns Array of room names
*/
getRooms(connectionId: string): string[];
/**
* Get all connection IDs in a room.
*
* @param room - The room to query
* @returns Array of connection IDs
*/
getConnectionsInRoom(room: string): string[];
/**
* Get the number of connections in a room.
*
* @param room - The room to query
* @returns Number of connections
*/
getConnectionCountInRoom(room: string): number;
/**
* Check if a connection is in a specific room.
*
* @param connectionId - The connection to check
* @param room - The room to check
* @returns true if the connection is in the room
*/
isInRoom(connectionId: string, room: string): boolean;
/**
* Get all room names that have at least one connection.
*
* @returns Array of room names
*/
getAllRooms(): string[];
/**
* Publish a message to a room via the adapter.
* This propagates the message to other nodes.
*
* @param room - The room to publish to
* @param message - The SSE message to broadcast
* @param options - Broadcast options (e.g. `local: true` to skip adapter)
* @param metadata - Optional opaque metadata propagated to other nodes
* alongside the message. Used by `SSESubscriptionManager` for cross-node
* resolver evaluation; not delivered to clients.
*/
publish(room: string, message: SSEMessage, options?: RoomBroadcastOptions, metadata?: Record<string, unknown>): Promise<void>;
}