import type { ToesEvent, ToesEventType } from '../shared/events' export type { ToesEvent, ToesEventType } type EventCallback = (event: ToesEvent) => void interface Listener { types: ToesEventType[] callback: EventCallback } const _listeners = new Set() let _source: EventSource | undefined function ensureConnection() { if (_source) return const url = `${process.env.TOES_URL}/api/events/stream` _source = new EventSource(url) _source.onerror = () => { if (_source?.readyState === EventSource.CLOSED) { console.warn('[toes] Event stream closed unexpectedly') _source = undefined } } _source.onmessage = (e) => { try { const event: ToesEvent = JSON.parse(e.data) _listeners.forEach(l => { if (l.types.includes(event.type)) l.callback(event) }) } catch { // Ignore malformed events } } } function closeConnection() { if (_source) { _source.close() _source = undefined } } export function on(type: ToesEventType | ToesEventType[], callback: EventCallback): () => void { const listener: Listener = { types: Array.isArray(type) ? type : [type], callback, } _listeners.add(listener) ensureConnection() return () => { _listeners.delete(listener) if (_listeners.size === 0) closeConnection() } }