import type { EventMap } from '../data/types'; type Handler = (payload: EventMap[K]) => void; // Typed pub/sub. Handlers added/removed during an emit don't affect that emit // (we snapshot the handler list), matching what scenes need on shutdown. export class EventBus { private handlers = new Map>>(); on(event: K, fn: Handler): () => void { let set = this.handlers.get(event); if (!set) { set = new Set(); this.handlers.set(event, set); } set.add(fn as Handler); return () => this.off(event, fn); } once(event: K, fn: Handler): () => void { const off = this.on(event, (payload) => { off(); fn(payload); }); return off; } off(event: K, fn: Handler): void { this.handlers.get(event)?.delete(fn as Handler); } emit(event: K, payload: EventMap[K]): void { const set = this.handlers.get(event); if (!set) return; for (const fn of [...set]) { if (set.has(fn)) (fn as Handler)(payload); } } removeAll(): void { this.handlers.clear(); } }