Skip to content

feat(cache)!: migrate from better-sqlite3 to node:sqlite; require Node 24 - #96

Merged
sjsyrek merged 1 commit into
mainfrom
feat/node-sqlite-cache
Jul 28, 2026
Merged

feat(cache)!: migrate from better-sqlite3 to node:sqlite; require Node 24#96
sjsyrek merged 1 commit into
mainfrom
feat/node-sqlite-cache

Conversation

@sjsyrek

@sjsyrek sjsyrek commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the better-sqlite3 native addon with Node's built-in node:sqlite module and raises engines.node to >=24.0.0. This removes the last native module from the production dependency tree, eliminating the ABI-mismatch failure class (ERR_DLOPEN_FAILED after a Node major upgrade, e.g. brew upgrade node) before the first npm publish — no published version will ever have carried the native dependency.

Closes the transitional inconsistency where engines.node (>=20.19.0) disagreed with commander 15's >=22.12.0: the engines bump lands together with the code that requires it.

Changes Made

  • src/storage/cache.ts — swapped better-sqlite3's Database for node:sqlite's DatabaseSync. prepare/exec/close map 1:1; the three .pragma() call sites (the only API gap) become exec('PRAGMA …') for writes and prepare('PRAGMA user_version').get() for the read. No behavior change otherwise.
  • package.json — removed better-sqlite3 and @types/better-sqlite3; engines.node is now >=24.0.0.
  • tests/fixtures/cache-better-sqlite3.db (new, force-added past the *.db ignore) — a cache database generated by better-sqlite3 12.11.1 / SQLite 3.53.2 mirroring the real on-disk layout: WAL journal mode, user_version = 1, three entries.
  • tests/unit/cache-backcompat.test.ts (new) — opens the fixture with the new backend: no corruption quarantine, all entries readable, stats accurate, mixed old/new writes, close/reopen cycle.
  • tests/unit/cache-native-failure.test.ts — backend mock retargeted from better-sqlite3 to node:sqlite's DatabaseSync; the load-failure-vs-corruption classification cases are unchanged.
  • tests/e2e/cli-cache-degraded.e2e.test.ts — the subprocess module-resolution hijack now intercepts node:sqlite and throws the realistic ERR_UNKNOWN_BUILTIN_MODULE (verified registerHooks intercepts builtin specifiers in both CJS and ESM).
  • tests/unit/cache-service.test.ts — three tests that reached into the private db handle via .pragma() now use the node:sqlite API.
  • src/cli/cache-loader.ts, CLAUDE.md — comment/architecture references updated. README/TROUBLESHOOTING native-module sections are deliberately NOT touched here — they are deleted by the docs issue, which is dependency-ordered after this change.

Test Coverage

  • New back-compat suite proves databases written by the old backend are read in place — the one spot real user data is at risk. The SQLite version gap is 3.53.2 → 3.53.1 (effectively none).
  • Existing degradation coverage (unit + E2E) proves a runtime without node:sqlite warns once and runs cacheless without touching the database.
  • Full suite: 236 suites / 5,532 tests pass on Node 24.18.0; lint and type-check clean; production npm audit at 0 vulnerabilities; npm pack --dry-run shows 0 internal-name hits, 0 .map files, README + LICENSE present; npm ls --omit=dev confirms no native module remains.

Backward Compatibility

Breaking: Node.js >= 24.0.0 is now required (hence v2.0.0). Node 18/20 lack node:sqlite entirely; Node 22 emits an ExperimentalWarning on every invocation and bundles an older SQLite (3.50.4 vs 3.53.1).
Cache data fully preserved: the on-disk format is unchanged; existing databases (including WAL sidecars and the user_version stamp) are read in place with no migration.
Degradation behavior preserved: backend-load failure still degrades to cacheless operation with a single warning and never touches the database.

Size: Medium ✓

Small mechanical diff in cache.ts (one import, three pragma call sites), but it carries the engines bump, a dependency removal, a committed binary fixture, and four test-file updates that must land atomically.

🤖 Generated with Claude Code

…e 24

Replace the better-sqlite3 native addon with Node's built-in node:sqlite
module and raise engines.node to >=24.0.0 (first release where
node:sqlite is non-experimental). The on-disk cache format is unchanged;
a fixture database written by better-sqlite3 12.11.1 (WAL mode,
user_version = 1) is committed and read back as a permanent
back-compat regression guard.

The production dependency tree no longer contains any native addon,
removing the ABI-mismatch failure class (ERR_DLOPEN_FAILED after a Node
major upgrade), a 1.9 MB platform-specific binary, and the compilation
toolchain requirement. The cacheless-degradation safety net now guards
node:sqlite absence (Node < 22.5.0) instead of native-binding failures.

BREAKING CHANGE: Node.js >= 24.0.0 is now required. Node 18/20 lack
node:sqlite entirely; Node 22 emits an ExperimentalWarning and bundles
an older SQLite (3.50.4).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@sjsyrek
sjsyrek merged commit f23df0b into main Jul 28, 2026
5 checks passed
@sjsyrek
sjsyrek deleted the feat/node-sqlite-cache branch July 28, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant