/** Shared, bounded queue; unused requests are removed or aborted. */ export function createResourceLoader(load: (key: string, signal: AbortSignal) => Promise, concurrency = 6, cacheSize = 16) { type Subscriber = { resolve: (value: T) => void; reject: (error: unknown) => void; cleanup: () => void }; type Job = { key: string; controller: AbortController; subscribers: Set }; const cache = new Map(); const jobs = new Map(); const queue: Job[] = []; let active = 0; function peek(key: string) { const value = cache.get(key); if (value !== undefined) { cache.delete(key); cache.set(key, value); } return value; } function pump() { while (active < concurrency && queue.length) { const job = queue.shift()!; if (!job.subscribers.size) continue; active++; Promise.resolve().then(() => { if (job.controller.signal.aborted) throw new DOMException("Aborted", "AbortError"); return load(job.key, job.controller.signal); }).then((value) => { if (!job.controller.signal.aborted) { cache.set(job.key, value); while (cache.size > cacheSize) cache.delete(cache.keys().next().value!); for (const subscriber of job.subscribers) { subscriber.cleanup(); subscriber.resolve(value); } } }, (error) => { for (const subscriber of job.subscribers) { subscriber.cleanup(); subscriber.reject(error); } }).finally(() => { if (jobs.get(job.key) === job) jobs.delete(job.key); active--; pump(); }); } } function request(key: string, signal?: AbortSignal): Promise { if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError")); const cached = peek(key); if (cached !== undefined) return Promise.resolve(cached); let job = jobs.get(key); if (!job) { job = { key, controller: new AbortController(), subscribers: new Set() }; jobs.set(key, job); queue.push(job); } const current = job; return new Promise((resolve, reject) => { const abort = () => { current.subscribers.delete(subscriber); subscriber.cleanup(); reject(new DOMException("Aborted", "AbortError")); if (!current.subscribers.size) { if (jobs.get(key) === current) jobs.delete(key); const index = queue.indexOf(current); if (index >= 0) queue.splice(index, 1); current.controller.abort(); } }; const subscriber: Subscriber = { resolve, reject, cleanup: () => signal?.removeEventListener("abort", abort) }; current.subscribers.add(subscriber); signal?.addEventListener("abort", abort, { once: true }); pump(); }); } return { request, peek }; }