type EventListener = (...args: T) => void | Promise; type OnOptions = { abortSignal?: AbortSignal; }; class EventEmitter void | Promise>> { #listeners = new Map>>(); on = (event: K, callback: EventListener>, options: OnOptions = {}) => { const { abortSignal } = options; if (!this.#listeners.has(event)) { this.#listeners.set(event, new Set()); } const callbackClone = (...args: Parameters) => callback(...args); const abortController = new AbortController(); const listeners = this.#listeners.get(event); if (!listeners) { throw new Error('Event registration failed'); } abortSignal?.addEventListener('abort', abortController.abort); listeners.add(callbackClone); abortController.signal.addEventListener('abort', () => { this.#listeners.set(event, listeners?.difference(new Set([callbackClone]))); }); return abortController.abort; }; once = (event: K, callback: EventListener>, options: OnOptions = {}) => { const abortController = new AbortController(); options.abortSignal?.addEventListener('abort', abortController.abort); return this.on( event, async (...args) => { abortController.abort(); await callback(...args); }, { ...options, abortSignal: abortController.signal, }, ); }; emit = (event: K, ...args: Parameters) => { const listeners = this.#listeners.get(event); if (!listeners) { return; } for (const listener of listeners) { listener(...args); } }; emitAsync = async (event: K, ...args: Parameters) => { const listeners = this.#listeners.get(event); if (!listeners) { return; } await Promise.all(listeners.values().map((listener) => listener(...args))); }; } export { EventEmitter };