Repository navigation
fix(config): keep the SQLite driver out of the client bundle (#10692) - #10695
Merged
diegosouzapw merged 2 commits intoAug 18, 2026
Merged
Conversation
`open-sse/services/combo.ts` imported "../../src/lib/localDb.js" — a .js suffix on a module that only exists as .ts. Turbopack resolved it by accident until the dependency-tree change in #10647; after that the instrumentation hook died at boot with MODULE_NOT_FOUND, breaking `npm run dev` and the production build (60 consecutive red `Build App` runs on release/v3.8.50). Fixes the same latent pattern in src/lib/usage/usageLedger.ts, which survived only because it is an `import type` and is erased before resolution. Adds a guard rejecting relative .js specifiers across open-sse/ and src/. Package specifiers are untouched: publishing ESM as .js is legitimate there (e.g. @modelcontextprotocol/sdk), and only first-party relative imports are first-party TypeScript. Closes #10674
The `aihorde` entry in IMAGE_PROVIDERS imported its live-catalog service directly. IMAGE_PROVIDERS is reachable from "use client" dashboard pages — they read its KEYS to derive which providers support which media kind — so that import dragged aihordeImageCatalog → safeOutboundFetch → proxyFetch → featureFlags → db/core → sqljsAdapter into the browser graph. The build then tried to bundle fs/net/tls for the browser and failed with 28 Module not found errors, leaving `Build App` red for 60 consecutive runs and no artifact buildable from the branch. A dynamic import() does not fix this: the bundler still has to make the module browser-loadable. The dependency is inverted instead — the registry entry knows only a pure registration module, and the server-only service registers itself on import, which every server path needing live models already does. With nothing registered the getter yields [], exactly what the live catalog returned before its first poll. Validated by a full `npm run build:release`: 0 Module not found, artifact produced. Closes #10692
Collaborator
Author
|
Merging on top of #10691 (now merged). The remaining red checks are the same inherited set documented there (#9985) — stale doc counts, The check this PR is about is proven green locally in a way CI could not show before: a full |
diegosouzapw
added a commit
that referenced
this pull request
Aug 19, 2026
…y point (#10692) (#10700) The guard shipped with #10695 watched two hand-picked modules. It now walks the static import graph from all 753 "use client" files in src/ (plus the two originally pinned entries), so the invariant is verified across the repo instead of where someone remembered to look. Full sweep runs in ~750ms. Two exclusions make that practical: - `import type` is not an edge — TypeScript erases it before the bundler sees it. Counting type imports turns 3 real findings into 29; a guard that cries wolf gets switched off. - Dynamic `import()` is still not followed. It does not break a bundle edge (that was tried for #10692 and failed) but it does move the module into a chunk the browser fetches on demand, which is a legitimate boundary. The widened sweep immediately found what the narrow one could not: five value-form imports of `db/batches` / `db/files` across three files under dashboard/batch, each reaching db/core → the SQLite driver. All five bind only interfaces (BatchRecord, FileRecord) used in type position, so the compiler was eliding them and the build stayed green — the same latent shape as #10692 before #10647 removed the toolchain's tolerance. Marking them `import type` makes the elision explicit instead of incidental. Refs #10692 Co-authored-by: Xiangzhe <bakryun0718@proton.me>
This was referenced Aug 19, 2026
This was referenced Aug 19, 2026
5 tasks done
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…-inference#10692) (cheaper-inference#10695) * fix(sse): import localDb through its real .ts extension (cheaper-inference#10674) `open-sse/services/combo.ts` imported "../../src/lib/localDb.js" — a .js suffix on a module that only exists as .ts. Turbopack resolved it by accident until the dependency-tree change in cheaper-inference#10647; after that the instrumentation hook died at boot with MODULE_NOT_FOUND, breaking `npm run dev` and the production build (60 consecutive red `Build App` runs on release/v3.8.50). Fixes the same latent pattern in src/lib/usage/usageLedger.ts, which survived only because it is an `import type` and is erased before resolution. Adds a guard rejecting relative .js specifiers across open-sse/ and src/. Package specifiers are untouched: publishing ESM as .js is legitimate there (e.g. @modelcontextprotocol/sdk), and only first-party relative imports are first-party TypeScript. Closes cheaper-inference#10674 * fix(config): keep the SQLite driver out of the client bundle (cheaper-inference#10692) The `aihorde` entry in IMAGE_PROVIDERS imported its live-catalog service directly. IMAGE_PROVIDERS is reachable from "use client" dashboard pages — they read its KEYS to derive which providers support which media kind — so that import dragged aihordeImageCatalog → safeOutboundFetch → proxyFetch → featureFlags → db/core → sqljsAdapter into the browser graph. The build then tried to bundle fs/net/tls for the browser and failed with 28 Module not found errors, leaving `Build App` red for 60 consecutive runs and no artifact buildable from the branch. A dynamic import() does not fix this: the bundler still has to make the module browser-loadable. The dependency is inverted instead — the registry entry knows only a pure registration module, and the server-only service registers itself on import, which every server path needing live models already does. With nothing registered the getter yields [], exactly what the live catalog returned before its first poll. Validated by a full `npm run build:release`: 0 Module not found, artifact produced. Closes cheaper-inference#10692 --------- Co-authored-by: Xiangzhe <bakryun0718@proton.me>
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…y point (cheaper-inference#10692) (cheaper-inference#10700) The guard shipped with cheaper-inference#10695 watched two hand-picked modules. It now walks the static import graph from all 753 "use client" files in src/ (plus the two originally pinned entries), so the invariant is verified across the repo instead of where someone remembered to look. Full sweep runs in ~750ms. Two exclusions make that practical: - `import type` is not an edge — TypeScript erases it before the bundler sees it. Counting type imports turns 3 real findings into 29; a guard that cries wolf gets switched off. - Dynamic `import()` is still not followed. It does not break a bundle edge (that was tried for cheaper-inference#10692 and failed) but it does move the module into a chunk the browser fetches on demand, which is a legitimate boundary. The widened sweep immediately found what the narrow one could not: five value-form imports of `db/batches` / `db/files` across three files under dashboard/batch, each reaching db/core → the SQLite driver. All five bind only interfaces (BatchRecord, FileRecord) used in type position, so the compiler was eliding them and the build stayed green — the same latent shape as cheaper-inference#10692 before cheaper-inference#10647 removed the toolchain's tolerance. Marking them `import type` makes the elision explicit instead of incidental. Refs cheaper-inference#10692 Co-authored-by: Xiangzhe <bakryun0718@proton.me>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10692. Stacked on #10691 — that fix is required for the build to get far enough to hit
this one.
Root cause
IMAGE_PROVIDERSis reachable from"use client"dashboard pages: they read its keys toderive which providers support which media kind (
mediaServiceKinds.ts→serviceKindIndex.ts).The
aihordeentry imported its live-catalog service directly, so the browser graph inherited:serviceKindIndex.tsalready stated the invariant in a comment — "Client-safe: mediaServiceKindsonly pulls in the pure-data media registries (no server-only deps)" — but a comment cannot fail a
build, so #10542 broke it unnoticed.
Why a dynamic
import()is not the fixTried first, and it does not work: deferring the module still requires the bundler to make it
browser-loadable, so the same 28 errors came back. The dependency has to be inverted.
The fix
New pure module
open-sse/config/dynamicImageModelSources.ts(register / get / reset, no imports).aihordeImageCatalogregisters itself at import time. Every server path that needs live modelsalready imports it (
api/v1/models/catalog.ts, which is also the only caller ofgetAllImageModels(); the image-generation handler; provider validation), so server behaviouris unchanged.
[]— exactly what the live catalog returned beforeits first poll, so the pre-poll client view is unchanged too.
Validation
Full
npm run build:releaseon this branch: 0Module not found, artifact produced(
dist/BUILD_SHAwritten). That is the first successful build of this branch in 60+ recordedBuild Appruns.typecheck:coreclean,eslintclean.Guard
tests/unit/client-bundle-no-server-only-10692.test.tswalks the real static-import graph fromthe client-safe entry points and fails if any of them reaches
db/core,driverFactory,sqljsAdapterorproxyFetch— printing the offending chain. It deliberately does not followimport(), and it runs in ~30ms, so this class of regression is caught without waiting for anhour-long build. Proven to discriminate: it reproduced the exact 6-hop chain before the fix.