Measured while implementing #10062 (the gate for "published src/** imports minus declared dependencies"). Recorded, not acted on — the remediation there was decided per member, and this is the group where declaring was tried, measured, and deliberately reverted.
The population
Five occurrences across three published packages, all the same shape: a guarded await import(...) of a workspace driver package that the importing package declares nowhere — not in dependencies, not in peerDependencies, not in optionalDependencies.
@objectstack/service-datasource <- @objectstack/driver-turso
src/default-datasource-driver-factory.ts (try/catch -> MissingDriverPackageError)
@objectstack/service-datasource <- @objectstack/driver-sqlite-wasm
src/default-datasource-driver-factory.ts (try/catch -> missingSqliteWasmDriverMessage)
src/sqlite-driver-fallback.ts (try/catch -> next rung of the ladder)
@objectstack/service-datasource <- @objectstack/driver-mongodb
src/default-datasource-driver-factory.ts (try/catch -> named message, #7385)
@objectstack/runtime <- @objectstack/driver-turso
src/turso-driver-factory.ts (host-replaceable default thunk, #6268)
@objectstack/rest carries a sixth of the same kind against @objectstack/objectql (rest-server.ts, degrades to 501 NOT_IMPLEMENTED), listed here for completeness rather than as part of the same call — rest's non-coupling to the data engine is a stated architectural position, not a hygiene gap.
Each is now a optional-runtime-probe row in scripts/check-undeclared-dep-imports.mjs, so the class is no longer unguarded: a row goes red the moment its occurrence stops being a dynamic import, or the moment the package gets declared. What the rows do not do is tell an installing consumer anything.
The class this is, and the one that already got it right
An optional peerDependencies entry is exactly the declaration these want — it names the relationship without installing the package, so npm ls, a lockfile, an audit tool and a reader of the manifest can all see it. The tree already does this in one place: @objectstack/cli declares @objectstack/driver-turso as an optional peer while keeping it a devDependency. Today the consumer of service-datasource learns about these drivers only by hitting the arm and reading the runtime error — which is a good error (it carries the install command as data), but it arrives at the moment of failure rather than at install time.
Why #10062 did not do it, measured rather than assumed
It was tried on service-datasource and reverted. Adding
"peerDependencies": { "@objectstack/driver-turso": "workspace:^" }
"peerDependenciesMeta": { "@objectstack/driver-turso": { "optional": true } }
makes pnpm link the package inside the workspace (confirmed in pnpm-lock.yaml: the entry lands under dependencies as link:../../drivers/driver-turso). That takes out a live assertion:
FAIL src/__tests__/default-datasource-driver-factory.test.ts
> is what the turso arm actually raises when the optional package is absent
That test reaches the missing-package arm with no stub, on purpose, and its own comment says so:
@objectstack/driver-turso is deliberately not a dependency of this package — that is what "optional" means — so the missing-package path is reachable here for a real reason and needs no stub.
It also carries a notice for exactly this situation: "If the package was made a dependency, this assertion is the notice that the pin above needs a stubbed import instead." So the work is bounded and known: declare the optional peers, and convert that pin (and its #7385 siblings, if they turn out to rely on the same accident) onto a stubbed import.
Not asserted
No claim that anything is broken. Nothing user-visible changes today either way — the runtime error already carries the remedy. This records that the declaration is missing, that the fix is understood and bounded, and that it was measured to cost one test rewrite. Whether an install-time declaration is worth that is a dependency-hygiene judgement call this issue does not make.
Repo: objectstack. Files: packages/services/service-datasource/package.json, packages/services/service-datasource/src/default-datasource-driver-factory.ts, packages/services/service-datasource/src/sqlite-driver-fallback.ts, packages/services/service-datasource/src/__tests__/default-datasource-driver-factory.test.ts, packages/runtime/package.json, packages/runtime/src/turso-driver-factory.ts, scripts/check-undeclared-dep-imports.mjs.
Found while implementing #10062 (PR #12942).
Measured while implementing #10062 (the gate for "published
src/**imports minus declared dependencies"). Recorded, not acted on — the remediation there was decided per member, and this is the group where declaring was tried, measured, and deliberately reverted.The population
Five occurrences across three published packages, all the same shape: a guarded
await import(...)of a workspace driver package that the importing package declares nowhere — not independencies, not inpeerDependencies, not inoptionalDependencies.@objectstack/restcarries a sixth of the same kind against@objectstack/objectql(rest-server.ts, degrades to501 NOT_IMPLEMENTED), listed here for completeness rather than as part of the same call — rest's non-coupling to the data engine is a stated architectural position, not a hygiene gap.Each is now a
optional-runtime-proberow inscripts/check-undeclared-dep-imports.mjs, so the class is no longer unguarded: a row goes red the moment its occurrence stops being a dynamic import, or the moment the package gets declared. What the rows do not do is tell an installing consumer anything.The class this is, and the one that already got it right
An optional
peerDependenciesentry is exactly the declaration these want — it names the relationship without installing the package, sonpm ls, a lockfile, an audit tool and a reader of the manifest can all see it. The tree already does this in one place:@objectstack/clideclares@objectstack/driver-tursoas an optional peer while keeping it a devDependency. Today the consumer ofservice-datasourcelearns about these drivers only by hitting the arm and reading the runtime error — which is a good error (it carries the install command as data), but it arrives at the moment of failure rather than at install time.Why #10062 did not do it, measured rather than assumed
It was tried on
service-datasourceand reverted. Addingmakes pnpm link the package inside the workspace (confirmed in
pnpm-lock.yaml: the entry lands underdependenciesaslink:../../drivers/driver-turso). That takes out a live assertion:That test reaches the missing-package arm with no stub, on purpose, and its own comment says so:
It also carries a notice for exactly this situation: "If the package was made a dependency, this assertion is the notice that the pin above needs a stubbed import instead." So the work is bounded and known: declare the optional peers, and convert that pin (and its
#7385siblings, if they turn out to rely on the same accident) onto a stubbed import.Not asserted
No claim that anything is broken. Nothing user-visible changes today either way — the runtime error already carries the remedy. This records that the declaration is missing, that the fix is understood and bounded, and that it was measured to cost one test rewrite. Whether an install-time declaration is worth that is a dependency-hygiene judgement call this issue does not make.
Repo:
objectstack. Files:packages/services/service-datasource/package.json,packages/services/service-datasource/src/default-datasource-driver-factory.ts,packages/services/service-datasource/src/sqlite-driver-fallback.ts,packages/services/service-datasource/src/__tests__/default-datasource-driver-factory.test.ts,packages/runtime/package.json,packages/runtime/src/turso-driver-factory.ts,scripts/check-undeclared-dep-imports.mjs.Found while implementing #10062 (PR #12942).