export function delay(ms: number, signal?: AbortSignal): Promise { if (ms <= 0) return Promise.resolve(); if (signal?.aborted) return Promise.reject(new Error("aborted")); return new Promise((resolve, reject) => { const cleanup = () => { clearTimeout(timeout); signal?.removeEventListener("abort", abort); }; const timeout = setTimeout(() => { cleanup(); resolve(); }, ms); const abort = () => { cleanup(); reject(new Error("aborted")); }; signal?.addEventListener("abort", abort, { once: true }); }); } export async function withTimeout(promise: Promise, timeoutMs: number, label: string, signal?: AbortSignal): Promise { if (signal?.aborted) throw new Error("aborted"); let timeout: NodeJS.Timeout | undefined; let abort: (() => void) | undefined; const timeoutPromise = new Promise((_resolve, reject) => { timeout = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs); abort = () => reject(new Error("aborted")); signal?.addEventListener("abort", abort, { once: true }); }); return Promise.race([promise, timeoutPromise]).finally(() => { if (timeout) clearTimeout(timeout); if (abort) signal?.removeEventListener("abort", abort); }); }