30 lines
1.1 KiB
TypeScript
30 lines
1.1 KiB
TypeScript
// ISS-129 (v0.57.0): in-process fan-out registry for the SSE state stream (/api/events). The app
|
|
// runs as one long-lived server process (`next start`; instrumentation.ts already keeps background
|
|
// sim state alive) — no new dependencies, no WS upgrade needed. The Set lives on globalThis because
|
|
// Next.js gives instrumentation.ts (where broadcast() fires from the background tick) and route
|
|
// handlers (where subscribe() happens in /api/events) separate module instances; a plain `let` would
|
|
// give each its own empty set and no push would ever be delivered.
|
|
|
|
type Push = (text: string) => void;
|
|
|
|
const g = globalThis as unknown as { __flightSseSubscribers?: Set<Push> };
|
|
const subscribers: Set<Push> = (g.__flightSseSubscribers ??= new Set());
|
|
|
|
export function subscribe(fn: Push): () => void {
|
|
subscribers.add(fn);
|
|
return () => {
|
|
subscribers.delete(fn);
|
|
};
|
|
}
|
|
|
|
// Call each subscriber safely — one dead stream must not take the others down.
|
|
export function broadcast(text: string): void {
|
|
for (const fn of [...subscribers]) {
|
|
try {
|
|
fn(text);
|
|
} catch {
|
|
// subscriber's stream is gone; its own cleanup unsubscribes it
|
|
}
|
|
}
|
|
}
|