/** * Native-addon (better-sqlite3) load diagnosis and recovery. * * Issue #231: `monograph build` died with a raw NODE_MODULE_VERSION dump and the * reporter then ran `npm rebuild better-sqlite3` five times — from their project * directory and against a *separate* global `@monoes/monograph` install — while the * binary that actually gets loaded lives several node_modules levels deeper, under * the globally installed `monomind` -> `@monoes/monomindcli` -> `@monoes/monograph`. * Every attempt left the file byte-identical because none of them ever touched it. * * So the useful thing to report is not "run npm rebuild" — it is *which physical * file* is being loaded and *which directory* owns the node_modules tree it lives * in, which is what these helpers derive. */ export type NativeBindingStatus = 'ok' | 'abi-mismatch' | 'missing-binary' | 'load-error'; export interface RebuildTarget { /** Which tool owns the tree the binary lives in — they need different commands. */ packageManager: 'npm' | 'pnpm'; /** Directory to run the rebuild from: the package owning that node_modules. */ rebuildCwd: string; /** The module's own directory under node_modules. */ packageDir: string; } export interface NativeBindingDiagnosis { status: NativeBindingStatus; module: string; /** Node currently running (`process.version`). */ nodeVersion: string; /** ABI this Node requires (`process.versions.modules`). */ runtimeAbi: string; /** ABI the binary on disk was compiled for, when the error reported it. */ builtForAbi?: string; /** The exact `.node` file that failed to load, when the error named it. */ binaryPath?: string; target?: RebuildTarget; /** One-line summary, safe to use as a doctor check message. */ summary: string; /** Exact command to run, including the directory it must run in. */ fix?: string; /** Raw error text, for logs. */ raw?: string; } export interface RuntimeInfo { nodeVersion: string; runtimeAbi: string; } /** * Works out where a `.node` binary's package lives and which directory a rebuild * has to run from. `rebuildCwd` is the part users can't guess: for a nested * global install it is not the project, and not the top-level global package, * but the intermediate package that owns the node_modules holding the binary. */ export declare function deriveRebuildTarget(binaryPath: string): RebuildTarget | null; /** * Turns a native-addon load failure into a diagnosis naming the running Node, the * ABI the binary was built for, the file itself, and the exact fix command. * Pure — takes the runtime facts rather than reading them, so it is testable. */ export declare function diagnoseNativeLoadError(err: unknown, module: string, runtime?: RuntimeInfo, /** * Absolute path of the module as resolved by the caller. The "bindings file not * found" error lists only *candidate* paths, most of them relative, so there is * nothing trustworthy in its text to locate the install from. */ resolvedModulePath?: string): NativeBindingDiagnosis; /** Multi-line, human-facing rendering of a failed diagnosis. */ export declare function formatNativeDiagnosis(diag: NativeBindingDiagnosis): string; /** * Diagnoses a failure thrown while monograph was using better-sqlite3, locating the * install through monograph's own resolution rather than guessing from error text. */ export declare function diagnoseMonographNativeError(err: unknown): NativeBindingDiagnosis; /** * Loads the very same `better-sqlite3` copy `@monoes/monograph` will load (resolved * from monograph's own location, not the CLI's — under nested installs they can * differ, which is the whole point) and opens an in-memory database to force the * addon binding. * * Runs in a child process on purpose. Once an addon has failed to dlopen in a * process, later attempts report a useless "Module did not self-register" instead * of the real ABI error — and doctor has other checks that touch sqlite before * this one. A fresh process also means a binary that segfaults on load can't take * doctor down with it. */ export declare function probeMonographSqliteBinding(runtime?: RuntimeInfo): NativeBindingDiagnosis; export interface AutoRebuildDecision { attempt: boolean; reason: string; } /** * Decides whether monomind may rebuild the module itself. Deliberately * conservative: a native rebuild mutates an install tree that may be a shared or * root-owned global one, so it only runs when the current user can actually * write there and the user hasn't opted out. */ export declare function planAutoRebuild(diag: NativeBindingDiagnosis, opts?: { disabled?: boolean; isWritable?: (dir: string) => boolean; }): AutoRebuildDecision; export interface RebuildResult { ok: boolean; command: string; output: string; } /** Runs the single rebuild `planAutoRebuild` approved. */ export declare function runNativeRebuild(diag: NativeBindingDiagnosis): RebuildResult; //# sourceMappingURL=native-binding.d.ts.map