import type { ServerResponse } from 'node:http'; type EventPayload = unknown; type EventListener = (payload: EventPayload) => void; export class HostEventBus { private readonly listeners = new Map>(); private readonly sseClients = new Set(); on(eventName: string, listener: EventListener): () => void { const bucket = this.listeners.get(eventName) ?? new Set(); bucket.add(listener); this.listeners.set(eventName, bucket); return () => { bucket.delete(listener); if (bucket.size === 0) { this.listeners.delete(eventName); } }; } addSseClient(res: ServerResponse): void { this.sseClients.add(res); res.on('close', () => { this.sseClients.delete(res); }); } emit(eventName: string, payload: EventPayload): void { const bucket = this.listeners.get(eventName); if (bucket) { for (const listener of bucket) { listener(payload); } } if (this.sseClients.size > 0) { const message = `event: ${eventName}\ndata: ${JSON.stringify(payload)}\n\n`; for (const client of this.sseClients) { try { client.write(message); } catch { this.sseClients.delete(client); } } } } closeAll(): void { this.listeners.clear(); for (const client of this.sseClients) { try { client.end(); } catch { // Ignore individual client close failures. } } this.sseClients.clear(); } } export const hostEventBus = new HostEventBus();