type ActiveGenerationConsumer = { controller: AbortController; settled: Promise; }; export type GenerationConsumerHandle = { signal: AbortSignal; release(): void; }; const activeGenerationConsumers = new Set(); let pausedTransitions = 0; let transitionTail = Promise.resolve(); function abortError(): DOMException { return new DOMException("The operation was aborted", "AbortError"); } export function activeGenerationConsumerController(controller: AbortController): AbortController { return controller.signal.aborted ? new AbortController() : controller; } export function runGenerationConsumer(signal: AbortSignal | undefined, operation: (signal: AbortSignal) => Promise): Promise { if (pausedTransitions > 0) return Promise.reject(abortError()); const controller = new AbortController(); const abort = () => controller.abort(); if (signal?.aborted) abort(); else signal?.addEventListener("abort", abort, { once: true }); const active = {} as ActiveGenerationConsumer; const result = Promise.resolve().then(async () => { if (controller.signal.aborted) throw abortError(); return operation(controller.signal); }); active.controller = controller; active.settled = result.finally(() => { signal?.removeEventListener("abort", abort); activeGenerationConsumers.delete(active); }); activeGenerationConsumers.add(active); return active.settled as Promise; } export function beginGenerationConsumer(signal?: AbortSignal): GenerationConsumerHandle { const controller = new AbortController(); if (pausedTransitions > 0) { controller.abort(); return { signal: controller.signal, release() {} }; } const abort = () => controller.abort(); if (signal?.aborted) abort(); else signal?.addEventListener("abort", abort, { once: true }); let release!: () => void; const settled = new Promise((resolve) => { release = resolve; }); const active: ActiveGenerationConsumer = { controller, settled }; activeGenerationConsumers.add(active); let released = false; return { signal: controller.signal, release() { if (released) return; released = true; signal?.removeEventListener("abort", abort); activeGenerationConsumers.delete(active); release(); }, }; } async function cancelAndDrainActiveGenerationConsumers() { while (activeGenerationConsumers.size) { for (const active of activeGenerationConsumers) active.controller.abort(); await Promise.allSettled([...activeGenerationConsumers].map((active) => active.settled)); } } export function withGenerationConsumersPaused(operation: () => Promise): Promise { pausedTransitions += 1; const result = transitionTail.then(async () => { await cancelAndDrainActiveGenerationConsumers(); return operation(); }); transitionTail = result.then( () => undefined, () => undefined, ); return result.finally(() => { pausedTransitions -= 1; }); } export function cancelAndDrainGenerationConsumers(): Promise { return withGenerationConsumersPaused(async () => undefined); }