From 6c95e2b3545eab0cf4a93e4f6830bd0bacaae9d8 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Sat, 8 Aug 2026 13:51:57 -0300 Subject: [PATCH] fix(build): include better-sqlite3 prebuilds in standalone bun bundle (#8847) Refs: base-red #9737 --- changelog.d/fixes/8847-bun-prebuilds.md | 1 + scripts/build/assembleStandalone.mjs | 9 ++++ tests/unit/repro-8847.test.ts | 70 +++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 changelog.d/fixes/8847-bun-prebuilds.md create mode 100644 tests/unit/repro-8847.test.ts diff --git a/changelog.d/fixes/8847-bun-prebuilds.md b/changelog.d/fixes/8847-bun-prebuilds.md new file mode 100644 index 0000000000..2711dfa745 --- /dev/null +++ b/changelog.d/fixes/8847-bun-prebuilds.md @@ -0,0 +1 @@ +- fix(build): include better-sqlite3 prebuilds in standalone bun bundle diff --git a/scripts/build/assembleStandalone.mjs b/scripts/build/assembleStandalone.mjs index 3b9842e45a..412fe7b079 100644 --- a/scripts/build/assembleStandalone.mjs +++ b/scripts/build/assembleStandalone.mjs @@ -89,6 +89,15 @@ const NATIVE_ASSET_ENTRIES = [ src: ["node_modules", "better-sqlite3", "build"], dest: ["node_modules", "better-sqlite3", "build"], }, + { + // #8847: Bun (and npx -g global installs) resolve better-sqlite3's native + // binary from prebuilds/ instead of build/Release/, so the compiled build/ + // copy alone leaves a hollow package that falls back to sql.js (OOM under + // Bun). Ship the prebuilds alongside the compiled binary. + label: "better-sqlite3 prebuilds (Bun / global installs)", + src: ["node_modules", "better-sqlite3", "prebuilds"], + dest: ["node_modules", "better-sqlite3", "prebuilds"], + }, { // TPROXY IP_TRANSPARENT addon (Fase 3 / Epic A). Built by build-tproxy-native // before assembly; Linux-only + opt-in, so the source is absent on non-Linux diff --git a/tests/unit/repro-8847.test.ts b/tests/unit/repro-8847.test.ts new file mode 100644 index 0000000000..301263d35e --- /dev/null +++ b/tests/unit/repro-8847.test.ts @@ -0,0 +1,70 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { syncStandaloneNativeAssets } from "../../scripts/build/assembleStandalone.mjs"; + +/** + * Repro #8847: better-sqlite3 prebuilds are not included in the standalone + * bundle, so the bundled app fails when the platform's prebuild is needed + * (e.g. under Bun, which resolves the native binary via prebuilds/ rather + * than build/Release/). + * + * The test creates a synthetic node_modules/better-sqlite3/ tree with both + * the compiled build/Release/ binary AND the prebuilds/ directory, then + * confirms that syncStandaloneNativeAssets copies both into the standalone + * output. On the unfixed code this fails because NATIVE_ASSET_ENTRIES only + * lists better-sqlite3/build/. + */ +test("repro-8847: better-sqlite3 prebuilds are bundled alongside the compiled binary", async () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "repro-8847-")); + const projectRoot = path.join(tmp, "src-root"); + + // Seed better-sqlite3 with both build/Release/ and prebuilds/. + const bsqlDir = path.join(projectRoot, "node_modules", "better-sqlite3"); + fs.mkdirSync(path.join(bsqlDir, "build", "Release"), { recursive: true }); + fs.writeFileSync( + path.join(bsqlDir, "build", "Release", "better_sqlite3.node"), + "// native binary placeholder" + ); + fs.mkdirSync(path.join(bsqlDir, "prebuilds"), { recursive: true }); + for (const target of [ + "darwin-arm64.node", + "darwin-x64.node", + "linux-arm64.node", + "linux-x64.node", + "linuxmusl-arm64.node", + "linuxmusl-x64.node", + "win32-arm64.node", + "win32-x64.node", + ]) { + fs.writeFileSync(path.join(bsqlDir, "prebuilds", target), `// ${target}`); + } + + const outDir = path.join(tmp, "standalone"); + fs.mkdirSync(outDir, { recursive: true }); + + // Act: copy native assets into the standalone output. + await syncStandaloneNativeAssets(projectRoot, fs.promises, { log() {} }, outDir); + + // Assert: the compiled build/Release/ binary was copied. + assert.ok( + fs.existsSync( + path.join(outDir, "node_modules", "better-sqlite3", "build", "Release", "better_sqlite3.node") + ), + "compiled native binary (build/Release/) must be in the standalone bundle" + ); + + // Assert: the prebuilds/ directory was also copied. + const prebuildsDir = path.join(outDir, "node_modules", "better-sqlite3", "prebuilds"); + assert.ok(fs.existsSync(prebuildsDir), "prebuilds/ directory must be in the standalone bundle"); + + // Assert: at least one prebuild file was copied. + assert.ok( + fs.existsSync(path.join(prebuildsDir, "linux-x64.node")), + "linux-x64 prebuild must be in the standalone bundle" + ); + + fs.rmSync(tmp, { recursive: true, force: true }); +}); \ No newline at end of file