import { ArgOf, EmitEvent } from 'src/repositories/event.repository'; export class PendingEvents extends { error?: string } ? T : never }[EmitEvent]> { private pending = new Map>[]; timeout: NodeJS.Timeout }>(); private timeoutMs: number; constructor({ timeoutMs }: { timeoutMs: number }) { this.timeoutMs = timeoutMs; } wait(key: string): Promise> { const completer = Promise.withResolvers>(); const existing = this.pending.get(key); if (existing) { existing.completers.push(completer); return completer.promise; } const timeout = setTimeout(() => this.complete(key, { error: 'Request timed out' }), this.timeoutMs); this.pending.set(key, { completers: [completer], timeout }); return completer.promise; } complete(key: string, value: ArgOf | { error: string }) { const pending = this.pending.get(key); if (!pending) { return; } clearTimeout(pending.timeout); this.pending.delete(key); if ('error' in value) { const error = new Error(value.error); for (const completer of pending.completers) { completer.reject(error); } } else { for (const completer of pending.completers) { completer.resolve(value); } } } rejectByPrefix(prefix: string, error: string) { for (const key of this.pending.keys()) { if (key.startsWith(prefix)) { this.complete(key, { error }); } } } }