not-tonight/src/core/EventBus.ts
2026-07-19 16:20:53 +10:00

44 lines
1.2 KiB
TypeScript

import type { EventMap } from '../data/types';
type Handler<K extends keyof EventMap> = (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<keyof EventMap, Set<Handler<never>>>();
on<K extends keyof EventMap>(event: K, fn: Handler<K>): () => void {
let set = this.handlers.get(event);
if (!set) {
set = new Set();
this.handlers.set(event, set);
}
set.add(fn as Handler<never>);
return () => this.off(event, fn);
}
once<K extends keyof EventMap>(event: K, fn: Handler<K>): () => void {
const off = this.on(event, (payload) => {
off();
fn(payload);
});
return off;
}
off<K extends keyof EventMap>(event: K, fn: Handler<K>): void {
this.handlers.get(event)?.delete(fn as Handler<never>);
}
emit<K extends keyof EventMap>(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<K>)(payload);
}
}
removeAll(): void {
this.handlers.clear();
}
}