a22f0a4e7b
- Read only first 4096 bytes of binary header instead of entire file - Add error logging to all catch blocks with specific failure messages - Separate copy vs dlopen catch blocks in postinstall Strategy 1 - Add archCount sanity cap (max 30) for fat Mach-O parsing - Distinguish timeout vs rebuild failure in Strategy 2
116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* OmniRoute — Postinstall Native Module Fix
|
|
*
|
|
* The npm package ships with a Next.js standalone build that includes
|
|
* better-sqlite3 compiled for the build platform (Linux x64) inside
|
|
* app/node_modules/. However, npm also installs better-sqlite3 as a
|
|
* top-level dependency (in the root node_modules/), correctly compiled
|
|
* for the user's platform.
|
|
*
|
|
* This script copies the correctly-built native binary from the root
|
|
* into the standalone app directory — no rebuild or build tools needed.
|
|
*
|
|
* Fixes: https://github.com/diegosouzapw/OmniRoute/issues/129
|
|
* Fixes: https://github.com/diegosouzapw/OmniRoute/issues/321
|
|
*/
|
|
|
|
import { existsSync, copyFileSync, mkdirSync } from "node:fs";
|
|
import { join, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import { PUBLISHED_BUILD_PLATFORM, PUBLISHED_BUILD_ARCH } from "./native-binary-compat.mjs";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const ROOT = join(__dirname, "..");
|
|
|
|
const appBinary = join(
|
|
ROOT,
|
|
"app",
|
|
"node_modules",
|
|
"better-sqlite3",
|
|
"build",
|
|
"Release",
|
|
"better_sqlite3.node"
|
|
);
|
|
const rootBinary = join(
|
|
ROOT,
|
|
"node_modules",
|
|
"better-sqlite3",
|
|
"build",
|
|
"Release",
|
|
"better_sqlite3.node"
|
|
);
|
|
|
|
if (!existsSync(join(ROOT, "app", "node_modules", "better-sqlite3"))) {
|
|
process.exit(0);
|
|
}
|
|
|
|
const platformMatch =
|
|
process.platform === PUBLISHED_BUILD_PLATFORM && process.arch === PUBLISHED_BUILD_ARCH;
|
|
|
|
if (platformMatch) {
|
|
try {
|
|
process.dlopen({ exports: {} }, appBinary);
|
|
process.exit(0);
|
|
} catch (err) {
|
|
console.warn(` ⚠️ Bundled binary incompatible despite platform match: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
console.log(`\n 🔧 Fixing better-sqlite3 binary for ${process.platform}-${process.arch}...`);
|
|
|
|
// Strategy 1: Copy the correctly-built binary from root node_modules
|
|
if (existsSync(rootBinary)) {
|
|
try {
|
|
mkdirSync(dirname(appBinary), { recursive: true });
|
|
copyFileSync(rootBinary, appBinary);
|
|
} catch (err) {
|
|
console.warn(` ⚠️ Failed to copy binary: ${err.message}`);
|
|
}
|
|
|
|
try {
|
|
process.dlopen({ exports: {} }, appBinary);
|
|
console.log(" ✅ Native module fixed successfully!\n");
|
|
process.exit(0);
|
|
} catch (err) {
|
|
console.warn(` ⚠️ Copied binary failed to load: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
// Strategy 2: Fall back to npm rebuild (may work if build tools are available)
|
|
console.log(" ⚠️ Root binary not available or incompatible, attempting npm rebuild...");
|
|
|
|
try {
|
|
const { execSync } = await import("node:child_process");
|
|
execSync("npm rebuild better-sqlite3", {
|
|
cwd: join(ROOT, "app"),
|
|
stdio: "inherit",
|
|
timeout: 120_000,
|
|
});
|
|
|
|
process.dlopen({ exports: {} }, appBinary);
|
|
console.log(" ✅ Native module rebuilt successfully!\n");
|
|
process.exit(0);
|
|
} catch (err) {
|
|
const isTimeout = err.killed || err.signal === "SIGTERM";
|
|
if (isTimeout) {
|
|
console.warn(" ⚠️ npm rebuild timed out after 120s.");
|
|
} else {
|
|
console.warn(` ⚠️ npm rebuild failed: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
// If nothing worked, warn but don't fail the install — let the package stay
|
|
// installed so users can fix manually or use the pre-flight check in the CLI
|
|
console.warn(" ⚠️ Could not fix better-sqlite3 native module automatically.");
|
|
console.warn(" The server may not start correctly.");
|
|
console.warn(" Try manually:");
|
|
console.warn(` cd ${join(ROOT, "app")} && npm rebuild better-sqlite3`);
|
|
if (process.platform === "darwin") {
|
|
console.warn(" If build tools are missing: xcode-select --install");
|
|
}
|
|
console.warn("");
|