Skip to content

feat: node26 image using built-in node:sqlite (drop native toolchain)#2

Merged
ahze merged 1 commit into
daemonless:mainfrom
jtrotsky:node26-node-sqlite
Jun 13, 2026
Merged

feat: node26 image using built-in node:sqlite (drop native toolchain)#2
ahze merged 1 commit into
daemonless:mainfrom
jtrotsky:node26-node-sqlite

Conversation

@jtrotsky

Copy link
Copy Markdown
Contributor

Moves the FreeBSD Papra image to node26 (matching upstream's .nvmrc) and replaces the better-sqlite3 driver swap with node26's built-in node:sqlite, driven through drizzle-orm/sqlite-proxy. This removes the entire C toolchain from the builder (no FreeBSD-clang/lld/toolchain/clibs-dev, no node-gyp, python, gmake) -- there is no native addon to compile -- and decouples the DB layer from node ABI churn (the better-sqlite3 11->12 break on node26 was exactly this class of problem).

node26 specifics:

  • node26 ships only in FreeBSD's latest pkg branch (the base image points at quarterly, which tops out at node25), so switch the branch before install in both stages.
  • papra uses the TC39 Temporal global. Official node26 ships it built-in, but FreeBSD's node26 package is compiled WITHOUT it (and --harmony-temporal is a no-op here), so preload a spec-compliant polyfill via node --import temporal-polyfill/global.

database.ts maps node:sqlite to the libsql semantics papra expects:

  • sqlite-proxy callback uses StatementSync.setReturnArrays(true) for the positional rows drizzle's query builder wants.
  • attachBatch: custom db.batch (sqlite-proxy's native batch can't handle papra's eagerly-executed db.run() results).
  • attachLibsqlRaw: raw db.run/all/get return libsql's row OBJECTS (migrations 0010-0019 read db.run(...).rows; the health check reads db.all(...)).

The other three FreeBSD patches (health-check, tasks-driver, migration 0006) are unchanged. Remote libSQL/Turso URLs remain unsupported (local file DB only) -- same as before.

Moves the FreeBSD Papra image to node26 (matching upstream's .nvmrc) and
replaces the better-sqlite3 driver swap with node26's built-in node:sqlite,
driven through drizzle-orm/sqlite-proxy. This removes the entire C toolchain
from the builder (no FreeBSD-clang/lld/toolchain/clibs-dev, no node-gyp,
python, gmake) -- there is no native addon to compile -- and decouples the DB
layer from node ABI churn (the better-sqlite3 11->12 break on node26 was
exactly this class of problem).

node26 specifics:
- node26 ships only in FreeBSD's `latest` pkg branch (the base image points
  at `quarterly`, which tops out at node25), so switch the branch before
  install in both stages.
- papra uses the TC39 Temporal global. Official node26 ships it built-in, but
  FreeBSD's node26 package is compiled WITHOUT it (and --harmony-temporal is a
  no-op here), so preload a spec-compliant polyfill via
  `node --import temporal-polyfill/global`.

database.ts maps node:sqlite to the libsql semantics papra expects:
- sqlite-proxy callback uses StatementSync.setReturnArrays(true) for the
  positional rows drizzle's query builder wants.
- attachBatch: custom db.batch (sqlite-proxy's native batch can't handle
  papra's eagerly-executed db.run() results).
- attachLibsqlRaw: raw db.run/all/get return libsql's row OBJECTS (migrations
  0010-0019 read db.run(...).rows; the health check reads db.all(...)).

The other three FreeBSD patches (health-check, tasks-driver, migration 0006)
are unchanged. Remote libSQL/Turso URLs remain unsupported (local file DB
only) -- same as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ahze ahze self-assigned this Jun 13, 2026
@ahze ahze merged commit b729b32 into daemonless:main Jun 13, 2026
6 checks passed
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.

2 participants