export interface ApprovalResult { readonly action: string; readonly resolvedBy: string; } export interface PendingApproval { readonly messageId: string; readonly chatId: string; readonly resolve: (result: ApprovalResult) => void; } export interface ApprovalManagerOptions { readonly timeoutMs?: number; } export class ApprovalManager { private readonly timeoutMs: number; private pending = new Map(); constructor(options: ApprovalManagerOptions = {}) { this.timeoutMs = options.timeoutMs ?? 5 * 60 * 1000; } register(messageId: string, chatId: string): Promise { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.pending.delete(messageId); reject(new Error(`approval timed out after ${this.timeoutMs}ms`)); }, this.timeoutMs); const unref = (timeout as { unref?: () => void }).unref; if (unref !== undefined) unref.call(timeout); this.pending.set(messageId, { messageId, chatId, resolve: (result) => { clearTimeout(timeout); resolve(result); }, }); }); } resolve(messageId: string, action: string, resolvedBy: string): void { const pending = this.pending.get(messageId); if (pending === undefined) return; this.pending.delete(messageId); pending.resolve({ action, resolvedBy }); } hasPending(messageId: string): boolean { return this.pending.has(messageId); } }