mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +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.
151 lines
7.6 KiB
TypeScript
151 lines
7.6 KiB
TypeScript
/**
|
|
* Regression guard for the broken Turbopack production build on release/v3.8.50.
|
|
*
|
|
* Six independent module-level defects, each from a different PR, made `npm run build`
|
|
* fail. Most are *link-time* errors, so those cases are expressed as "this module must be
|
|
* importable / statically resolvable" rather than as behavioral assertions:
|
|
*
|
|
* 1. src/shared/components/modelSelectModalHelpers.ts — a lost `}` (#9011) left
|
|
* `export const PROVIDER_TEST_CHUNK_SIZE` inside a function body.
|
|
* 2. open-sse/handlers/videoGeneration.ts — `handleFalVideoGeneration` imported
|
|
* twice from two different modules (#9982 landed on top of #9969).
|
|
* 3. src/app/api/v1/models/catalog.ts — re-exported three SWR symbols that #9199
|
|
* deliberately removed from ./catalogCache when it replaced #8728's injectable
|
|
* policy with a fixed 30 s bound. The consumer was never updated.
|
|
* 4. src/app/api/v1/models/catalogCache.ts — the same PR left two dangling statements
|
|
* referencing undeclared `inFlight` / `promise`, so every stale-while-revalidate
|
|
* read threw a ReferenceError at RUNTIME (this one the build never caught).
|
|
* 5. open-sse/executors/tinycmsSigner.ts — generated wasm-bindgen glue kept a
|
|
* `new URL('wasm_signer_bg.wasm', import.meta.url)` default that no file backs.
|
|
* 6. src/app/api/providers/[id]/models/conolDiscovery.ts — imported
|
|
* `getProviderOutboundGuard` from ./outboundUrlGuard, which does not export it (#8974).
|
|
*/
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import path from "node:path";
|
|
|
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
|
|
test("modelSelectModalHelpers exports survive isProviderModelHidden (#9011 missing brace)", async () => {
|
|
const helpers = await import("@/shared/components/modelSelectModalHelpers");
|
|
|
|
// The missing `}` swallowed everything after isProviderModelHidden into its body,
|
|
// so this constant stopped being a module-level export.
|
|
assert.equal(helpers.PROVIDER_TEST_CHUNK_SIZE, 3);
|
|
|
|
const hidden = helpers.parseHiddenModelsByProvider({ openai: ["gpt-4o"] });
|
|
assert.equal(helpers.isProviderModelHidden(hidden, "openai", "gpt-4o"), true);
|
|
assert.equal(helpers.isProviderModelHidden(hidden, "openai", "gpt-4o-mini"), false);
|
|
assert.equal(helpers.isProviderModelHidden(hidden, "anthropic", "gpt-4o"), false);
|
|
});
|
|
|
|
test("videoGeneration handler links with a single handleFalVideoGeneration binding (#9982)", async () => {
|
|
// A duplicate import binding is an ESM early SyntaxError, so the import itself is
|
|
// the assertion. The Fal video path must resolve to the provider-neutral module
|
|
// that #9982 added (it also covers the #9969 Grok Imagine routing).
|
|
const mod = await import("@omniroute/open-sse/handlers/videoGeneration.ts");
|
|
assert.equal(typeof mod.handleVideoGeneration, "function");
|
|
|
|
const source = readFileSync(path.join(repoRoot, "open-sse/handlers/videoGeneration.ts"), "utf8");
|
|
const falImports = source.match(/import \{ handleFalVideoGeneration \}/g) ?? [];
|
|
assert.equal(falImports.length, 1, "handleFalVideoGeneration must be imported exactly once");
|
|
assert.match(source, /handleFalVideoGeneration \} from "\.\/mediaGeneration\/fal\.ts"/);
|
|
});
|
|
|
|
test("catalog.ts re-exports only what catalogCache actually exports (#9199)", async () => {
|
|
// #9199 deliberately replaced #8728's injectable SWR policy with a fixed bound, but
|
|
// left catalog.ts re-exporting the three removed symbols. Re-exporting a binding the
|
|
// source module does not export is a link-time error, so this import IS the assertion.
|
|
const catalog = await import("@/app/api/v1/models/catalog");
|
|
const catalogCache = await import("@/app/api/v1/models/catalogCache");
|
|
|
|
assert.equal(catalogCache.CATALOG_STALE_WHILE_REVALIDATE_MS, 30_000);
|
|
assert.equal(catalog.CATALOG_STALE_WHILE_REVALIDATE_MS, 30_000);
|
|
|
|
// The accessor/policy trio must stay gone — re-adding it would resurrect the
|
|
// unbounded window #9199 removed (a failing refresh could pin an old catalog forever).
|
|
for (const removed of [
|
|
"getCatalogStaleWhileRevalidateMs",
|
|
"__setCatalogStaleWhileRevalidateAccessorForTest",
|
|
"__setCatalogStaleWhileRevalidateMsForTest",
|
|
]) {
|
|
assert.equal(
|
|
(catalogCache as Record<string, unknown>)[removed],
|
|
undefined,
|
|
`${removed} was removed by #9199 and must not come back`
|
|
);
|
|
}
|
|
});
|
|
|
|
test("the stale-while-revalidate path does not throw a ReferenceError (#9199 merge residue)", async () => {
|
|
// The mangled merge left `inFlight = { … promise }` referencing two undeclared
|
|
// identifiers inside scheduleBackgroundRefresh, so EVERY stale read crashed at runtime.
|
|
const catalogCache = await import("@/app/api/v1/models/catalogCache");
|
|
catalogCache.__resetCatalogBuilderRunsForTest();
|
|
|
|
const payload = (body: string) => ({
|
|
body,
|
|
headers: { "content-type": "application/json" },
|
|
status: 200,
|
|
cacheTTL: 60_000,
|
|
});
|
|
const call = (body: string) =>
|
|
catalogCache.resolveCachedCatalogResponse(
|
|
new Request("http://localhost/v1/models"),
|
|
{ corsHeaders: {}, diagnosticHeaders: {} },
|
|
async () => payload(body)
|
|
);
|
|
|
|
await call("first");
|
|
catalogCache.__expireCatalogCacheForTest();
|
|
|
|
const stale = await call("second");
|
|
assert.equal(await stale.text(), "first", "the stale body must be served, not a crash");
|
|
await catalogCache.__flushCatalogBackgroundRefreshForTest();
|
|
});
|
|
|
|
test("conolDiscovery resolves getProviderOutboundGuard from the policy module (#8974)", async () => {
|
|
// outboundUrlGuard.ts does NOT export getProviderOutboundGuard — importing it from
|
|
// there is a link-time error, so the import below is the assertion.
|
|
const mod = await import("@/app/api/providers/[id]/models/conolDiscovery");
|
|
assert.equal(typeof mod.maybeHandleConolModelDiscovery, "function");
|
|
|
|
// The fix must stay on the consumer side. outboundUrlGuard.ts is loaded by the packaged
|
|
// CLI, where no tsconfig resolves `@/*`, so re-exporting the policy helpers from it
|
|
// (they pull in featureFlags → the DB layer) would break `omniroute setup-opencode`
|
|
// (#7682). Guard that nobody "fixes" this by adding the re-export instead.
|
|
const guardSource = readFileSync(
|
|
path.join(repoRoot, "src/shared/network/outboundUrlGuard.ts"),
|
|
"utf8"
|
|
);
|
|
// Positive anchor: prove we are still reading the real guard module — a stable
|
|
// top-level export — so the negative guard below cannot rot into a vacuous pass
|
|
// against an empty/moved file (source-scanner-guards rule).
|
|
assert.match(
|
|
guardSource,
|
|
/export class OutboundUrlGuardError extends Error/,
|
|
"outboundUrlGuard.ts moved or was emptied — re-anchor this guard before trusting it"
|
|
);
|
|
assert.doesNotMatch(
|
|
guardSource,
|
|
/^\s*(import|export)[^\n]*from\s+["']@\//m,
|
|
"outboundUrlGuard.ts must stay free of @/-aliased imports/re-exports (#7682)"
|
|
);
|
|
});
|
|
|
|
test("tinycmsSigner has no build-time-resolvable wasm sidecar URL (#8736/#10087)", () => {
|
|
const source = readFileSync(path.join(repoRoot, "open-sse/executors/tinycmsSigner.ts"), "utf8");
|
|
|
|
// The wasm binary ships inlined as WASM_BASE64; there is no wasm_signer_bg.wasm file.
|
|
// Turbopack statically resolves `new URL(<literal>, import.meta.url)`, so leaving the
|
|
// generated default in place fails `next build` with "Module not found".
|
|
assert.ok(source.includes("const WASM_BASE64 ="), "wasm binary must stay inlined");
|
|
assert.doesNotMatch(
|
|
source,
|
|
/new URL\(\s*['"]wasm_signer_bg\.wasm['"]/,
|
|
"generated wasm-bindgen sidecar URL must not survive — Turbopack resolves it at build time"
|
|
);
|
|
});
|