export function timeoutSignal(ms: number): { signal: AbortSignal; cleanup: () => void; } { const controller = new AbortController(); const timeout = setTimeout(() => { controller.abort(new DOMException("Operation timed out", "TimeoutError")); }, ms); const cleanup = () => { clearTimeout(timeout); controller.signal.removeEventListener("abort", cleanup); }; controller.signal.addEventListener("abort", cleanup); return { signal: controller.signal, cleanup }; } export function combineSignals(...signals: AbortSignal[]): AbortSignal { const controller = new AbortController(); const cleanups = [] as (() => void)[]; for (const signal of signals) { if (signal.aborted) { controller.abort(signal.reason); return controller.signal; } const handler = () => { if (!controller.signal.aborted) { controller.abort(signal.reason); } }; signal.addEventListener("abort", handler); cleanups.push(() => signal.removeEventListener("abort", handler)); } controller.signal.addEventListener("abort", () => { cleanups.forEach((cb) => cb()); }); return controller.signal; }