// In-flight request deduplication with redirect-on-forceFresh. // // Basic case: when N components mount and each calls the same fetcher, the // "check cache → fetch → store on completion" pattern fires N concurrent // requests because every caller sees an empty cache. Routing those callers // through this helper collapses the burst into a single network request. // // forceFresh case: a caller that has just committed a mutation passes // `forceFresh: true` so it doesn't join a pre-mutation in-flight request and // return stale data. The OLD callers that already joined the in-flight // request are ALSO redirected — they receive the fresh response from the new // fetch, not the stale one. This is implemented by decoupling the external // promise that callers await from the inner fetch promise: a forceFresh // invocation discards the old inner fetch's eventual resolution and assigns // the new inner fetch's resolution to the SAME external promise that old // callers are waiting on. No caller ever observes pre-mutation data once a // post-mutation forceFresh has been requested. // // Layered caching (e.g. usePluginUiSlots' 60s TTL) is unaffected — that runs // at the hook layer, above this helper. interface InFlightEntry { /** The promise callers await. Resolves to whichever inner fetch wins. */ external: Promise; /** Resolves the external promise. Guarded by `done`. */ resolve: (value: T) => void; /** Rejects the external promise. Guarded by `done`. */ reject: (err: unknown) => void; /** Once resolved or rejected, further fetches must not write to external. */ done: boolean; } const inFlight = new Map>(); export interface DedupeOptions { /** * Skip joining an existing in-flight request and start a new fetch. Any * callers already awaiting the prior in-flight request will be redirected * to receive the new fetch's response instead — they will NOT see the * pre-forceFresh response. Use after a mutation when callers must observe * the post-mutation server snapshot. */ forceFresh?: boolean; } function makeEntry(): InFlightEntry { // Manually-constructed Deferred so we can assign whichever inner fetch // wins to the same external promise. let resolve!: (v: T) => void; let reject!: (e: unknown) => void; const external = new Promise((res, rej) => { resolve = res; reject = rej; }); return { external, resolve, reject, done: false }; } function attachInnerToEntry(entry: InFlightEntry, inner: Promise): void { inner.then( (value) => { if (entry.done) return; entry.done = true; entry.resolve(value); }, (err) => { if (entry.done) return; entry.done = true; entry.reject(err); }, ); } export function dedupe( key: string, fn: () => Promise, options?: DedupeOptions, ): Promise { const existing = inFlight.get(key) as InFlightEntry | undefined; if (existing && !existing.done) { if (!options?.forceFresh) { // Standard dedupe — join the in-flight request. return existing.external; } // forceFresh with an existing in-flight: start a new inner fetch and // redirect existing.external to its result. The old inner fetch's // eventual resolution is discarded by the `done` guard in // attachInnerToEntry. attachInnerToEntry(existing, fn()); return existing.external; } // No live entry (or forceFresh with nothing in flight) — start fresh. const entry = makeEntry(); attachInnerToEntry(entry, fn()); // Schedule cleanup once the external promise settles. We compare by // identity so a later forceFresh that swaps in a new entry under the same // key doesn't get deleted by this old cleanup. void entry.external.then( () => { if (inFlight.get(key) === entry) inFlight.delete(key); }, () => { if (inFlight.get(key) === entry) inFlight.delete(key); }, ); inFlight.set(key, entry as InFlightEntry); return entry.external; }