From 4231bf619bac4ff5ac12c19a1286d62cec84da4b Mon Sep 17 00:00:00 2001 From: Ofek Gabay Date: Mon, 1 Jun 2026 16:42:07 +0300 Subject: [PATCH] fix: fall back to per-platform sub-package when native addon copy is missing The runtime loader only looked for lbugjs.node inside the main package directory, where install.js copies it during postinstall. Environments that skip lifecycle scripts (pnpm dlx, pnpx, --ignore-scripts, sandboxed installs) never run install.js, so the copy is absent and the loader fails with ERR_DLOPEN_FAILED even though the prebuilt binary is present in the @ladybugdb/core-- sub-package. Resolve the binary at runtime: prefer the in-package copy, and when it is missing, fall back to the per-platform sub-package using the same require.resolve logic install.js already uses. Fixes #20 Co-Authored-By: Claude Opus 4.8 (1M context) --- src_js/lbug_native.js | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src_js/lbug_native.js b/src_js/lbug_native.js index 818a363..f9de610 100644 --- a/src_js/lbug_native.js +++ b/src_js/lbug_native.js @@ -8,10 +8,48 @@ const process = require("process"); const constants = require("constants"); -const join = require("path").join; +const fs = require("fs"); +const path = require("path"); +const join = path.join; + +/** + * Resolve the path to the native addon (lbugjs.node). + * + * Normally the postinstall script (install.js) copies the prebuilt binary + * from the per-platform sub-package into this package directory. However, + * environments that skip lifecycle scripts (e.g. `pnpm dlx`, `pnpx`, + * `npm install --ignore-scripts`, sandboxed installs) never run install.js, + * so the in-package copy is missing even though the prebuilt binary is + * present in the per-platform sub-package. In that case, fall back to + * resolving the binary directly from the sub-package using the same logic + * install.js uses. + */ +function resolveNativeModulePath() { + const inPackagePath = join(__dirname, "lbugjs.node"); + if (fs.existsSync(inPackagePath)) { + return inPackagePath; + } + + try { + const MAIN_PKG_NAME = require(join(__dirname, "package.json")).name; + const subPkgName = `${MAIN_PKG_NAME}-${process.platform}-${process.arch}`; + const subPkgMain = require.resolve(`${subPkgName}/package.json`, { + paths: [__dirname], + }); + const subPkgBinaryPath = path.join(path.dirname(subPkgMain), "lbugjs.node"); + if (fs.existsSync(subPkgBinaryPath)) { + return subPkgBinaryPath; + } + } catch (e) { + // Sub-package not installed (unsupported platform or missing optionalDep); + // fall through and let dlopen surface the original error. + } + + return inPackagePath; +} const lbugNativeModule = { exports: {} }; -const modulePath = join(__dirname, "lbugjs.node"); +const modulePath = resolveNativeModulePath(); if (process.platform === "linux") { process.dlopen( lbugNativeModule,