Files
SnowLuma/.pnpm-store/v11/files/4d/75885600bfa3941a54b3a4cd2783da1f75e9d58ad69059ee09448c1848fcf4328036bf0589418ad5122d371855e36a70902d6a3ccab7b7db2445e17d2bdf13
TanTan 2a69b23b47
Dev Build / cleanup (push) Canceled after 0s
Dev Build / typecheck (push) Canceled after 0s
Dev Build / build (linux-arm64, ubuntu-24.04-arm, linux-arm64) (push) Canceled after 0s
Dev Build / build (linux-x64, ubuntu-latest, linux-x64) (push) Canceled after 0s
Dev Build / build (win-x64, windows-latest, win32-x64) (push) Canceled after 0s
Dev Build / dispatch-dev-docker (push) Skipped
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

141 lines
7.0 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Loads the native addon through node-gyp-build, which prefers a
// prebuilds/ binary over a local build/ when both exist.
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import nodeGypBuild from 'node-gyp-build';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = join(__dirname, '..');
// The Node-API level this addon is built against (package.json
// binary.napi_versions; binding.gyp compiles with the same number). A
// runtime that does not expose at least this level cannot load the
// addon — and the failure is not graceful: loading a Node-API 10
// prebuild into a Node-API 9 runtime (Node 20, Electron 32–34)
// segfaults inside module registration rather than throwing, so the
// check below must run before the dlopen, not after it. The floors in
// the message are the first releases that expose Node-API 10; verified
// by loading the prebuild, not by reading a compatibility table.
const NAPI_VERSION_REQUIRED = 10;
// The supported floors from package.json `engines`, not merely the first
// releases that expose Node-API 10 (Node 22 does, but this package is not
// supported there) — pointing a user at a runtime `engines` rejects would
// only move them to the next failure.
const MIN_NODE = '24';
const MIN_ELECTRON = '35';
const rawNapi = process.versions.napi;
const napiVersion = Number.parseInt(
/** @type {string} */ (/** @type {unknown} */ (rawNapi)),
10,
);
if (!(napiVersion >= NAPI_VERSION_REQUIRED)) {
const runtime = process.versions.electron
? `Electron ${process.versions.electron} (Node ${process.versions.node})`
: `Node ${process.versions.node}`;
const floor = process.versions.electron
? `Electron >= ${MIN_ELECTRON} (Node >= ${MIN_NODE})`
: `Node >= ${MIN_NODE}`;
// A runtime with no `process.versions.napi` at all reports NaN above;
// say "no Node-API" rather than printing NaN back at the user.
const reported = Number.isNaN(napiVersion)
? 'no Node-API version'
: `Node-API ${napiVersion}`;
// Deliberately no "rebuild from source" remedy: this check runs on the
// runtime's reported Node-API level, before any dlopen, and
// package.json `binary.napi_versions` builds at Node-API 10 regardless
// — so a source rebuild produces this identical error. Upgrading the
// runtime is the only thing that works.
throw new Error(
`@appthreat/sqlite3 requires a runtime with Node-API ${NAPI_VERSION_REQUIRED} or newer ` +
`(${floor}); this runtime is ${runtime}, reporting ${reported}. ` +
'Upgrade the runtime; see docs/electron.md and docs/install.md.',
);
}
let binding;
let bindingPath;
try {
// node-gyp-build exposes .path only through its own JS
// implementation; on a runtime where it delegates to require.addon
// the resolver is not reachable, so the path is best-effort context
// for the error message below.
bindingPath =
typeof (/** @type {any} */ (nodeGypBuild).path) === 'function'
? /** @type {any} */ (nodeGypBuild).path(rootDir)
: undefined;
} catch {
bindingPath = undefined;
}
try {
binding = nodeGypBuild(rootDir);
} catch (err) {
// Make the two support-heavy failure modes name their cause: where
// the package root was resolved from, and — when that root sits
// inside an app.asar archive — the archive context. (Current
// Electron extracts a .node from inside an archive to a temp file
// transparently, so an in-archive binary often still loads; the
// failure this hint addresses is the packaging configurations that
// leave the binary missing or unreadable.)
const insideAsar = rootDir.includes('app.asar');
let hint = `@appthreat/sqlite3 could not load its native binding; resolved package root: ${rootDir}`;
if (insideAsar) {
hint +=
'. The package is inside an app.asar archive: when the archive does not ' +
'expose a loadable binary, it must be unpacked at package time — ' +
"electron-builder: add '**/node_modules/@appthreat/sqlite3/prebuilds/**' to build.asarUnpack; " +
'@electron/packager: asar: { unpack: "**/node_modules/@appthreat/sqlite3/prebuilds/**" } ' +
'(its default asar: true already unpacks *.node). See docs/electron.md#asar';
} else if (process.versions.electron) {
hint +=
'. Running under Electron: the prebuild loads without a rebuild on Node-API 10 ' +
`(Electron >= ${MIN_ELECTRON}); see docs/electron.md`;
}
throw new Error(hint, { cause: err });
}
// Staleness canary. node-gyp-build picks one binary out of prebuilds/ and
// build/ by a specificity sort, so the file that loads is not always the
// file that was just built: a leftover binary from an older revision
// loads clean and merely lacks whatever lib/ gained since. The sharpest
// case is a libc-tagged binary in a darwin-* or win32-* prebuilds
// directory — node-gyp-build resolves libc to 'glibc' on every non-Alpine
// platform, so `*.glibc.node` matches there and outranks the untagged
// current build. Symptom before this check: methods missing from the
// namespace, no error anywhere, and a 9.0-era binary passing itself off
// as 9.1. Now the mismatch is a load-time error that names the file.
//
// src/node_sqlite3.cc defines NODE_SQLITE3_NATIVE_INTERFACE; the two
// numbers are bumped in the same commit, whenever lib/ starts depending
// on something the addon did not export before.
const NATIVE_INTERFACE_EXPECTED = 1;
const reportedInterface = /** @type {any} */ (binding).NATIVE_INTERFACE_VERSION;
if (reportedInterface !== NATIVE_INTERFACE_EXPECTED) {
const where = bindingPath ? ` Loaded binary: ${bindingPath}.` : '';
const reported =
reportedInterface === undefined
? 'no NATIVE_INTERFACE_VERSION at all (a binary predating the check)'
: `native interface ${reportedInterface}`;
throw new Error(
'@appthreat/sqlite3 loaded a native binding that does not match this ' +
`JavaScript: lib/ expects native interface ${NATIVE_INTERFACE_EXPECTED}, ` +
`the binding reports ${reported}. A binary from another revision is being ` +
'resolved ahead of the current one: delete the stale artifacts and rebuild ' +
'(`rm -rf prebuilds build && pnpm run rebuild`). A libc-tagged binary ' +
'(*.glibc.node, *.musl.node) inside a darwin-* or win32-* prebuilds ' +
`directory is the usual cause — it must not be there at all.${where}`,
);
}
// The addon object carries everything; the classes are additionally
// exported by name so `export { Database } from './sqlite3-binding.js'`
// in lib/sqlite3.js is a real ESM re-export (whose declaration emit keeps
// the class's dual value+type meaning for the generated types).
const { Database, Statement, Backup, Session, Blob } = binding;
export { Backup, Blob, Database, Session, Statement };
export default binding;