Skip to content

Commit e193c6a

Browse files
committed
fix(desktop): verify better-sqlite3's shipped prebuild
1 parent 2d66882 commit e193c6a

4 files changed

Lines changed: 27 additions & 16 deletions

File tree

apps/daemon/AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ Runs via `tsx` in dev (`pnpm -F @linkcode/daemon dev`) and a `tsup` bundle in pr
165165
materializes a self-contained dir at `apps/daemon/standalone` (gitignored; pass an explicit path as
166166
argv for CI) via `pnpm --prod deploy` — the tsup bundle plus its runtime externals flat in the dir's
167167
own `node_modules`, runnable anywhere as `node --import ./dist/instrument.js dist/index.js`. This is
168-
distinct from the desktop bundle: it targets **plain Node** (better-sqlite3 keeps its prebuild-install
169-
binary — a **same-platform** artifact, build per target), and it prunes the host-arch agent CLI
170-
platform packages (the daemon downloads them at runtime via `@linkcode/assets`, as the desktop
168+
distinct from the desktop bundle: it targets **plain Node** (still a **same-platform** artifact — the
169+
napi-rs optional deps and @sentry's profiler resolve host-only — build per target), and it prunes
170+
the host-arch agent CLI platform packages (the daemon downloads them at runtime via `@linkcode/assets`, as the desktop
171171
does). The pi npm closure needs no prune (CODE-219): its SDK is a devDependency of
172172
agent-adapter, so the `--prod` deploy never materializes it — the daemon downloads the managed
173173
closure on first use.

apps/daemon/scripts/package-daemon.mts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
* `node --import ./dist/instrument.js dist/index.js` with nothing else on disk.
1414
*
1515
* Unlike the desktop bundle (Electron `utilityProcess`, native modules rebuilt to Electron's ABI),
16-
* this targets plain Node: better-sqlite3 keeps the prebuild-install binary for the build host's
17-
* Node/OS/arch. It is therefore a same-platform artifact — build it on (or for) each target.
16+
* this targets plain Node. better-sqlite3 carries a NAPI prebuild per target, but the host-only
17+
* napi-rs optional deps and @sentry's ABI-pinned profiler do not: a same-platform artifact — build
18+
* it on (or for) each target.
1819
*
1920
* Agent CLI platform binaries are pruned: they are host-arch, ~230 MB each, and the daemon
2021
* provisions them at runtime through its managed-asset store (@linkcode/assets, CODE-111) exactly

apps/desktop/electron-builder.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ files:
5858
# verify-artifacts.mts guards against reintroduction.
5959
# Dead weight in the deploy closure (CODE-215). @linkcode/* are raw-TS workspace sources —
6060
# main/preload/daemon all bundle them, and migrations run from out/drizzle, so nothing resolves
61-
# them from node_modules at runtime. better-sqlite3/deps is the sqlite3 C amalgamation:
62-
# @electron/rebuild needs it at BUILD time (which is why the staging prune must not delete it),
63-
# but the compiled build/Release binding is all the app loads.
61+
# them from node_modules at runtime. better-sqlite3/deps is the sqlite3 C amalgamation, only ever
62+
# compiled if a from-source @electron/rebuild happens (which is why the staging prune must not
63+
# delete it); the app loads the shipped NAPI prebuild under better-sqlite3/prebuilds instead.
6464
- '!node_modules/@linkcode/**'
6565
- '!node_modules/better-sqlite3/deps/**'
6666

apps/desktop/scripts/verify-artifacts.mts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,23 @@ const EXPECTED: Partial<Record<string, PlatformExpectation>> = {
7575
};
7676

7777
const SIDECAR_BINARY = argv[2] === 'win' ? 'linkcode-pty.exe' : 'linkcode-pty';
78+
/** Node's platform name per builder platform — the token better-sqlite3 names its prebuilds by. */
79+
const NODE_PLATFORM: Partial<Record<string, string>> = {
80+
mac: 'darwin',
81+
win: 'win32',
82+
linux: 'linux',
83+
};
7884
/**
79-
* better-sqlite3's compiled binding, smartUnpacked beside the asar; the daemon requires it at boot.
80-
* A build where @electron/rebuild silently rebuilt nothing ships the wrong CPU/ABI and every client
81-
* shows "Unable to connect to the daemon" (broke every release through 0.2.1; see package-app.mts).
85+
* better-sqlite3's binding, smartUnpacked beside the asar; the daemon requires it at boot. Since
86+
* v13 it is one NAPI prebuild per platform-arch shipped in the tarball (`build/Release` is only
87+
* written when node-gyp actually compiles, which it now skips), so what breaks is the staging
88+
* prune keeping the wrong target — every client then shows "Unable to connect to the daemon".
8289
*/
83-
const NATIVE_BINDING = 'node_modules/better-sqlite3/build/Release/better_sqlite3.node'.replaceAll(
84-
'/',
85-
sep,
86-
);
90+
function sqliteBinding(platform: string, arch: string): string | null {
91+
const nodePlatform = NODE_PLATFORM[platform];
92+
if (nodePlatform === undefined) return null;
93+
return `node_modules/better-sqlite3/prebuilds/${nodePlatform}-${arch}.node`.replaceAll('/', sep);
94+
}
8795
/**
8896
* napi-rs platform-package triple for the target this artifact was packed for. napi-rs ships one
8997
* optional dependency per triple and installs only the host's, so a cross-packed build carries no
@@ -183,8 +191,10 @@ function readBinaryArch(file: string): 'x64' | 'arm64' | null {
183191
*/
184192
function verifyNativeBindings(platform: string, resourceDir: string, problems: string[]): void {
185193
const expectedArch = resourceDir.includes('arm64') ? 'arm64' : 'x64';
194+
const sqlite = sqliteBinding(platform, expectedArch);
186195
const keyring = keyringBinding(platform, expectedArch);
187-
const bindings: Array<[label: string, path: string]> = [['better-sqlite3', NATIVE_BINDING]];
196+
const bindings: Array<[label: string, path: string]> = [];
197+
if (sqlite !== null) bindings.push(['better-sqlite3', sqlite]);
188198
if (keyring !== null) bindings.push(['@napi-rs/keyring', keyring]);
189199

190200
for (const [label, relative] of bindings) {

0 commit comments

Comments
 (0)