mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
* fix(postinstall): auto-rebuild better-sqlite3 on Node.js ABI mismatch prebuild-install fetches a prebuilt binary for the Node.js version active at install time. On systems where the Node ABI differs from Node 24 (e.g. Arch Linux system Node, Node 22 LTS, Node 25), or after switching versions, the addon fails to dlopen at daemon startup. postinstall now tries to load the native addon after the workspace builds. On failure it locates node-gyp from the pnpm virtual store (bundled with better-sqlite3) and rebuilds from source — no external tooling beyond a C++ compiler required. pnpm install becomes self-healing across Node versions. Also adds a QUICKSTART troubleshooting entry for users with ignore-scripts=true who need to run `node scripts/postinstall.mjs` manually. * fix(postinstall): correct better-sqlite3 path and rebuild mechanism Two bugs in the initial implementation caught in review: - better-sqlite3 is declared by apps/daemon, not the workspace root. node_modules/better-sqlite3 at root does not exist in a normal pnpm install, so existsSync() was always false and the check never ran. Fix: resolve via createRequire from apps/daemon/package.json. - better-sqlite3@12.9.0 depends only on bindings and prebuild-install, not node-gyp. The assumed sibling path in the pnpm store does not exist, so the rebuild branch was hitting the "not found" exit instead of rebuilding. Fix: use pnpm --filter @open-design/daemon rebuild better-sqlite3 so pnpm manages node-gyp through its own lifecycle. Also expands the QUICKSTART troubleshooting entry with the manual rebuild command, a verification step, and build tool prerequisites. * fix(quickstart): scope better-sqlite3 verification to daemon package
88 lines
2.8 KiB
JavaScript
88 lines
2.8 KiB
JavaScript
import { spawnSync } from "node:child_process";
|
|
import { createRequire } from "node:module";
|
|
import { dirname, extname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = resolve(scriptDir, "..");
|
|
|
|
const buildTargets = [
|
|
"packages/contracts",
|
|
"packages/sidecar-proto",
|
|
"packages/sidecar",
|
|
"packages/platform",
|
|
"tools/dev",
|
|
"tools/pack",
|
|
];
|
|
|
|
const jsExtensions = new Set([".js", ".cjs", ".mjs"]);
|
|
|
|
function resolvePackageManagerInvocation() {
|
|
const pnpmExecPath = process.env.npm_execpath;
|
|
if (pnpmExecPath != null && pnpmExecPath.length > 0) {
|
|
if (jsExtensions.has(extname(pnpmExecPath).toLowerCase())) {
|
|
return { argsPrefix: [pnpmExecPath], command: process.execPath };
|
|
}
|
|
return { argsPrefix: [], command: pnpmExecPath };
|
|
}
|
|
|
|
return { argsPrefix: [], command: process.platform === "win32" ? "pnpm.cmd" : "pnpm" };
|
|
}
|
|
|
|
const packageManager = resolvePackageManagerInvocation();
|
|
|
|
for (const target of buildTargets) {
|
|
const result = spawnSync(
|
|
packageManager.command,
|
|
[...packageManager.argsPrefix, "-C", target, "run", "build"],
|
|
{
|
|
cwd: repoRoot,
|
|
stdio: "inherit",
|
|
},
|
|
);
|
|
|
|
if (result.error != null) {
|
|
throw result.error;
|
|
}
|
|
|
|
if (result.status !== 0) {
|
|
process.exit(result.status ?? 1);
|
|
}
|
|
}
|
|
|
|
// Verify the better-sqlite3 native addon loads under the current Node.js ABI.
|
|
// better-sqlite3 is a dep of apps/daemon (not the workspace root), so resolve
|
|
// it from the daemon package context. prebuild-install may have fetched a
|
|
// prebuilt binary for a different ABI (e.g. after switching between Node 22 /
|
|
// 24 / 25). When the addon fails to dlopen, pnpm rebuild handles the rebuild
|
|
// using its own node-gyp lifecycle — no assumptions about where node-gyp lives.
|
|
const req = createRequire(resolve(repoRoot, "apps/daemon/package.json"));
|
|
let needsRebuild = false;
|
|
try {
|
|
req("better-sqlite3");
|
|
} catch (e) {
|
|
// MODULE_NOT_FOUND means daemon deps aren't installed yet — not our problem.
|
|
// Any other error (ERR_DLOPEN_FAILED, ABI mismatch, etc.) warrants a rebuild.
|
|
if (e?.code !== "MODULE_NOT_FOUND") {
|
|
needsRebuild = true;
|
|
}
|
|
}
|
|
|
|
if (needsRebuild) {
|
|
process.stdout.write(
|
|
`postinstall: rebuilding better-sqlite3 for Node.js ${process.version}...\n`,
|
|
);
|
|
const rebuild = spawnSync(
|
|
packageManager.command,
|
|
[...packageManager.argsPrefix, "--filter", "@open-design/daemon", "rebuild", "better-sqlite3"],
|
|
{ cwd: repoRoot, stdio: "inherit" },
|
|
);
|
|
if (rebuild.error != null) throw rebuild.error;
|
|
if (rebuild.status !== 0) {
|
|
process.stderr.write(
|
|
"postinstall: better-sqlite3 rebuild failed.\n" +
|
|
"Install build tools (python3, make, g++ or clang++) then run: pnpm install\n",
|
|
);
|
|
process.exit(rebuild.status ?? 1);
|
|
}
|
|
}
|