Skip to content

fix(cli): extend better-sqlite3 → wasm SQLite auto-fallback to the persistent-file / --artifact dev path - #2234

Merged
xuyushun441-sys merged 1 commit into
mainfrom
fix/issue-2229-sqlite-wasm-fallback
Jun 23, 2026
Merged

fix(cli): extend better-sqlite3 → wasm SQLite auto-fallback to the persistent-file / --artifact dev path#2234
xuyushun441-sys merged 1 commit into
mainfrom
fix/issue-2229-sqlite-wasm-fallback

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Closes#2229.

Problem

The native-better-sqlite3 → wasm SQLite → in-memory auto-fallback only existed in the zero-config :memory: branch of serve (the else if (isDev) default-dev branch). A normal objectstack dev run never reaches it:

  • dev injects a persistent file: DB by design (so AI-authored metadata/records survive restarts) → routes into the explicit sqlite/file: branch in serve.ts, which did new SqlDriver({ client: 'better-sqlite3', … }) directly — no probe, no fallback.
  • --artifact boots resolve sqlite through default-datasource-driver-factory.ts (via standalone-stack) — also new SqlDriver({ client: 'better-sqlite3', … }) with no probe/fallback.

better-sqlite3 loads its native .node addon lazily (at the first pool-connection acquire / first query, not at require or knex construction). So an ABI mismatch (e.g. a cached prebuilt binary built for a different Node version — NODE_MODULE_VERSION mismatch) was invisible at boot and surfaced later as a runtime Find operation failed on the first query.

Fix

Hoist the probe-by-connect + step-down into a shared resolveSqliteDriver helper in @objectstack/service-datasource and apply it to both previously-unguarded sqlite construction sites:

  • the explicit sqlite/file: branch in serve.ts, and
  • the sqlite branch of the default datasource driver factory.

The existing default-dev :memory: branch is refactored onto the same helper, so there is now a single implementation.

The helper:

  • Forces the native addon to load with connect() + a cheap SELECT 1 (connect() alone is not a reliable probe — for SQLite it only does mkdir + a PRAGMA whose error it swallows; the raw SELECT 1 propagates the load error).
  • In dev, on a native load/ABI failure, steps down to wasm SQLite (real SQL semantics + on-disk persistence — the same file: keeps working) preserving the filename, then to InMemoryDriver as a dev-only last resort, emitting the existing warning verbatim:

    ⚠ native better-sqlite3 unavailable (ABI mismatch or not built) — dev using wasm SQLite (real SQL, slower).

  • In production, returns the native driver unprobed — a load failure surfaces loudly (fail-closed) instead of silently degrading to a different engine. Dev is plumbed explicitly through StandaloneStackConfig / serve.ts (with a NODE_ENV==='development' fallback for programmatic callers).

Tests / verification

  • New co-located unit test packages/services/service-datasource/src/sqlite-driver-fallback.test.ts (8 cases) simulates a NODE_MODULE_VERSION-style load failure and asserts: wasm fallback + the exact warning, on-write/on-disconnect persistence selection, in-memory last resort, autoMigrate/schemaMode pass-through, prod fail-closed (native returned, never degraded), and the NODE_ENV dev-gate default. pnpm test --filter @objectstack/service-datasource93 passed.
  • turbo run build for @objectstack/service-datasource, @objectstack/runtime, and @objectstack/cli all green (DTS typecheck included).
  • Real-driver sanity (no mocks): resolveSqliteDriver on :memory:, a persistent file: (with a real INSERT/SELECT round-trip), and dev: false all resolve to native better-sqlite3 with no warning — confirming no behavior change on the happy path.

Changeset

patch for @objectstack/service-datasource, @objectstack/cli, @objectstack/runtime.

🤖 Generated with Claude Code

…rsistent-file / --artifact dev path (#2229)
The native-better-sqlite3 → wasm SQLite → in-memory step-down previously only
guarded the zero-config `:memory:` dev branch of `serve`. A normal
`objectstack dev` run never reached it: `dev` injects a persistent `file:` DB so
AI-authored data survives restarts, and `--artifact` boots resolve sqlite
through the datasource factory — both constructed `better-sqlite3` directly with
no probe and no fallback. better-sqlite3 loads its native addon lazily (first
query), so an ABI mismatch was invisible at boot and surfaced later as a runtime
`Find operation failed`.
Hoist the probe-by-connect + step-down into a shared `resolveSqliteDriver`
helper (@objectstack/service-datasource) and apply it to both previously
unguarded sqlite construction sites: the explicit `sqlite`/`file:` branch in
serve.ts and the sqlite branch of the default datasource driver factory. The
helper forces the native load with `connect()` + `SELECT 1` and, in dev only,
steps down to wasm SQLite (real SQL + on-disk persistence — the same `file:`
keeps working) then to in-memory as a last resort, emitting the existing
`⚠ native better-sqlite3 unavailable …` warning. In production the native driver
is returned unprobed so a load failure surfaces loudly (fail-closed) instead of
silently degrading. Dev is plumbed through standalone-stack so the --artifact
boot enables the fallback explicitly (NODE_ENV fallback otherwise).
Adds a co-located unit test simulating a NODE_MODULE_VERSION load failure
(asserts wasm fallback + warning, in-memory last resort, and prod fail-closed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercelBot commented Jun 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 23, 2026 8:27am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file size/l tests tooling labels Jun 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cli, @objectstack/runtime, packages/services.

29 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/cloud-artifact-api.mdx(via packages/cli, packages/runtime)
  • content/docs/concepts/implementation-status.mdx(via @objectstack/cli, @objectstack/runtime)
  • content/docs/concepts/north-star.mdx(via packages/runtime)
  • content/docs/concepts/packages.mdx(via @objectstack/cli, @objectstack/runtime)
  • content/docs/getting-started/cli.mdx(via @objectstack/cli)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/cli)
  • content/docs/guides/api-reference.mdx(via @objectstack/runtime)
  • content/docs/guides/authentication.mdx(via @objectstack/cli, @objectstack/runtime)
  • content/docs/guides/client-sdk.mdx(via @objectstack/cli)
  • content/docs/guides/cloud-deployment.mdx(via @objectstack/runtime)
  • content/docs/guides/deployment-vercel.mdx(via @objectstack/runtime)
  • content/docs/guides/driver-configuration.mdx(via @objectstack/runtime)
  • content/docs/guides/hook-bodies.mdx(via packages/cli, @objectstack/runtime)
  • content/docs/guides/packages.mdx(via @objectstack/cli, @objectstack/runtime, packages/services)
  • content/docs/guides/plugin-chatbot-integration.mdx(via @objectstack/runtime)
  • content/docs/guides/production-readiness.mdx(via @objectstack/runtime)
  • content/docs/guides/project-scoping.mdx(via @objectstack/cli)
  • content/docs/guides/runtime-services/audit-service.mdx(via packages/services)
  • content/docs/guides/runtime-services/data-service.mdx(via packages/cli)
  • content/docs/guides/runtime-services/index.mdx(via packages/cli, packages/services)
  • content/docs/guides/runtime-services/settings-service.mdx(via packages/services)
  • content/docs/guides/single-project-mode.mdx(via @objectstack/runtime)
  • content/docs/guides/skills.mdx(via packages/cli)
  • content/docs/protocol/objectos/http-protocol.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/i18n-standard.mdx(via packages/services)
  • content/docs/protocol/objectos/index.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/lifecycle.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/cli)
  • content/docs/protocol/objectos/realtime-protocol.mdx(via @objectstack/cli)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@xuyushun441-sys
xuyushun441-sys merged commit f2063f3 into mainJun 23, 2026
17 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the fix/issue-2229-sqlite-wasm-fallback branch June 23, 2026 09:58
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

better-sqlite3 → wasm auto-fallback doesn't cover the persistent-file / --artifact dev path (only the zero-config :memory: branch)

2 participants

@xuyushun441-sys@os-zhuang