mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-16 03:42:21 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
/**
|
|
* Generic keyed serialization lock. `run(key, fn)` queues onto whatever call
|
|
* is currently pending for `key` (or runs immediately if none), always
|
|
* invoking a NEW call to `fn()` for every caller — this is a SERIALIZATION
|
|
* queue, not a dedup cache. Contrast with
|
|
* `open-sse/services/tokenRefresh.ts`'s `connectionRefreshMutex`, which
|
|
* intentionally shares one execution's result across concurrent callers
|
|
* because they all want the identical "current access token" outcome; here,
|
|
* concurrent callers for the same key each get their own `fn`'s own result,
|
|
* just run one at a time.
|
|
*/
|
|
export function createKeyedMutex<T = unknown>(): {
|
|
run(key: string, fn: () => Promise<T>): Promise<T>;
|
|
} {
|
|
const queue = new Map<string, Promise<void>>();
|
|
|
|
function run(key: string, fn: () => Promise<T>): Promise<T> {
|
|
const prior = queue.get(key) ?? Promise.resolve();
|
|
const result = prior.then(fn, fn);
|
|
// Neutral marker (never rejects) used only to chain subsequent callers
|
|
// and to identify — by reference — whether this call is still the last
|
|
// one queued for `key` once it settles.
|
|
const marker: Promise<void> = result.then(
|
|
() => undefined,
|
|
() => undefined
|
|
);
|
|
queue.set(key, marker);
|
|
marker.finally(() => {
|
|
if (queue.get(key) === marker) {
|
|
queue.delete(key);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
return { run };
|
|
}
|