diff --git a/docs/i18n/ar/CHANGELOG.md b/docs/i18n/ar/CHANGELOG.md index 7c06b6ebe65..d2c25a654a8 100644 --- a/docs/i18n/ar/CHANGELOG.md +++ b/docs/i18n/ar/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/az/CHANGELOG.md b/docs/i18n/az/CHANGELOG.md index 6d42f659e91..ac25be0c6dc 100644 --- a/docs/i18n/az/CHANGELOG.md +++ b/docs/i18n/az/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/bg/CHANGELOG.md b/docs/i18n/bg/CHANGELOG.md index 6d42f659e91..ac25be0c6dc 100644 --- a/docs/i18n/bg/CHANGELOG.md +++ b/docs/i18n/bg/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/bn/CHANGELOG.md b/docs/i18n/bn/CHANGELOG.md index c0bd479da29..0834d753702 100644 --- a/docs/i18n/bn/CHANGELOG.md +++ b/docs/i18n/bn/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/cs/CHANGELOG.md b/docs/i18n/cs/CHANGELOG.md index a35490a8340..4e03f9602b0 100644 --- a/docs/i18n/cs/CHANGELOG.md +++ b/docs/i18n/cs/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/da/CHANGELOG.md b/docs/i18n/da/CHANGELOG.md index 4265c10895f..fc5df4cbbaa 100644 --- a/docs/i18n/da/CHANGELOG.md +++ b/docs/i18n/da/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/de/CHANGELOG.md b/docs/i18n/de/CHANGELOG.md index a7e302e9f19..1203fafe426 100644 --- a/docs/i18n/de/CHANGELOG.md +++ b/docs/i18n/de/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/es/CHANGELOG.md b/docs/i18n/es/CHANGELOG.md index dda2863fb75..1fe9641e4fd 100644 --- a/docs/i18n/es/CHANGELOG.md +++ b/docs/i18n/es/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/fa/CHANGELOG.md b/docs/i18n/fa/CHANGELOG.md index 8f20fde6f39..b79d3e6d715 100644 --- a/docs/i18n/fa/CHANGELOG.md +++ b/docs/i18n/fa/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/fi/CHANGELOG.md b/docs/i18n/fi/CHANGELOG.md index 105a264ca80..a012ba3fdbd 100644 --- a/docs/i18n/fi/CHANGELOG.md +++ b/docs/i18n/fi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/fr/CHANGELOG.md b/docs/i18n/fr/CHANGELOG.md index 77ce6ab7540..4ebd4e3b117 100644 --- a/docs/i18n/fr/CHANGELOG.md +++ b/docs/i18n/fr/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/gu/CHANGELOG.md b/docs/i18n/gu/CHANGELOG.md index 9a1f31b0c82..26119eb3b95 100644 --- a/docs/i18n/gu/CHANGELOG.md +++ b/docs/i18n/gu/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/he/CHANGELOG.md b/docs/i18n/he/CHANGELOG.md index 8cb4837f168..cec30fe21a4 100644 --- a/docs/i18n/he/CHANGELOG.md +++ b/docs/i18n/he/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/hi/CHANGELOG.md b/docs/i18n/hi/CHANGELOG.md index 6309d7218f0..63b343e7412 100644 --- a/docs/i18n/hi/CHANGELOG.md +++ b/docs/i18n/hi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/hu/CHANGELOG.md b/docs/i18n/hu/CHANGELOG.md index 6f1bc8d115b..703cc401fe1 100644 --- a/docs/i18n/hu/CHANGELOG.md +++ b/docs/i18n/hu/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/id/CHANGELOG.md b/docs/i18n/id/CHANGELOG.md index a2899b61e2a..ccd63ed6d0c 100644 --- a/docs/i18n/id/CHANGELOG.md +++ b/docs/i18n/id/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/in/CHANGELOG.md b/docs/i18n/in/CHANGELOG.md index 9b4f82708b8..fa54bd1fca5 100644 --- a/docs/i18n/in/CHANGELOG.md +++ b/docs/i18n/in/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/it/CHANGELOG.md b/docs/i18n/it/CHANGELOG.md index 0c9ad020018..51c2d0fc795 100644 --- a/docs/i18n/it/CHANGELOG.md +++ b/docs/i18n/it/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ja/CHANGELOG.md b/docs/i18n/ja/CHANGELOG.md index 984756b00c3..7c8b2f63175 100644 --- a/docs/i18n/ja/CHANGELOG.md +++ b/docs/i18n/ja/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ko/CHANGELOG.md b/docs/i18n/ko/CHANGELOG.md index e697cf76237..295d7b8e55e 100644 --- a/docs/i18n/ko/CHANGELOG.md +++ b/docs/i18n/ko/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/mr/CHANGELOG.md b/docs/i18n/mr/CHANGELOG.md index f2a5cdb9ed1..8f00e93e736 100644 --- a/docs/i18n/mr/CHANGELOG.md +++ b/docs/i18n/mr/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ms/CHANGELOG.md b/docs/i18n/ms/CHANGELOG.md index f9bef195142..8a1c635018c 100644 --- a/docs/i18n/ms/CHANGELOG.md +++ b/docs/i18n/ms/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/nl/CHANGELOG.md b/docs/i18n/nl/CHANGELOG.md index 52822a13392..7cfe6406d96 100644 --- a/docs/i18n/nl/CHANGELOG.md +++ b/docs/i18n/nl/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/no/CHANGELOG.md b/docs/i18n/no/CHANGELOG.md index 54899514532..4de0e1bf8da 100644 --- a/docs/i18n/no/CHANGELOG.md +++ b/docs/i18n/no/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/phi/CHANGELOG.md b/docs/i18n/phi/CHANGELOG.md index a12593964a4..2d0fd80b042 100644 --- a/docs/i18n/phi/CHANGELOG.md +++ b/docs/i18n/phi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/pl/CHANGELOG.md b/docs/i18n/pl/CHANGELOG.md index 9dbe2539c15..a6c0c4638c7 100644 --- a/docs/i18n/pl/CHANGELOG.md +++ b/docs/i18n/pl/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/pt-BR/CHANGELOG.md b/docs/i18n/pt-BR/CHANGELOG.md index b4554ef392b..2b69faea25f 100644 --- a/docs/i18n/pt-BR/CHANGELOG.md +++ b/docs/i18n/pt-BR/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/pt/CHANGELOG.md b/docs/i18n/pt/CHANGELOG.md index fb506f0763f..08bbf3db5ea 100644 --- a/docs/i18n/pt/CHANGELOG.md +++ b/docs/i18n/pt/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ro/CHANGELOG.md b/docs/i18n/ro/CHANGELOG.md index 41c566126e3..a331e42c85a 100644 --- a/docs/i18n/ro/CHANGELOG.md +++ b/docs/i18n/ro/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ru/CHANGELOG.md b/docs/i18n/ru/CHANGELOG.md index 3ad551e990c..c2fa33e8b7b 100644 --- a/docs/i18n/ru/CHANGELOG.md +++ b/docs/i18n/ru/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/sk/CHANGELOG.md b/docs/i18n/sk/CHANGELOG.md index cf760ab52d9..74f75ba62cf 100644 --- a/docs/i18n/sk/CHANGELOG.md +++ b/docs/i18n/sk/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/sv/CHANGELOG.md b/docs/i18n/sv/CHANGELOG.md index 3164c529f6c..c96db82ead4 100644 --- a/docs/i18n/sv/CHANGELOG.md +++ b/docs/i18n/sv/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/sw/CHANGELOG.md b/docs/i18n/sw/CHANGELOG.md index 9329b402dfe..d9258be4c99 100644 --- a/docs/i18n/sw/CHANGELOG.md +++ b/docs/i18n/sw/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ta/CHANGELOG.md b/docs/i18n/ta/CHANGELOG.md index bb7bdce7577..2a79a5512e4 100644 --- a/docs/i18n/ta/CHANGELOG.md +++ b/docs/i18n/ta/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/te/CHANGELOG.md b/docs/i18n/te/CHANGELOG.md index caf455a282b..62c87eba818 100644 --- a/docs/i18n/te/CHANGELOG.md +++ b/docs/i18n/te/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/th/CHANGELOG.md b/docs/i18n/th/CHANGELOG.md index 2bc5c1502a5..ab7c3e44d91 100644 --- a/docs/i18n/th/CHANGELOG.md +++ b/docs/i18n/th/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/tr/CHANGELOG.md b/docs/i18n/tr/CHANGELOG.md index c40d1a16b2a..67133c16578 100644 --- a/docs/i18n/tr/CHANGELOG.md +++ b/docs/i18n/tr/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/uk-UA/CHANGELOG.md b/docs/i18n/uk-UA/CHANGELOG.md index bbb7262c359..9afca5cbc63 100644 --- a/docs/i18n/uk-UA/CHANGELOG.md +++ b/docs/i18n/uk-UA/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/ur/CHANGELOG.md b/docs/i18n/ur/CHANGELOG.md index f63872fb11f..f740d738b2f 100644 --- a/docs/i18n/ur/CHANGELOG.md +++ b/docs/i18n/ur/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/vi/CHANGELOG.md b/docs/i18n/vi/CHANGELOG.md index 8863a0efd45..a0eb43f2a79 100644 --- a/docs/i18n/vi/CHANGELOG.md +++ b/docs/i18n/vi/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/docs/i18n/zh-CN/CHANGELOG.md b/docs/i18n/zh-CN/CHANGELOG.md index 900ccd76067..a2b4487077d 100644 --- a/docs/i18n/zh-CN/CHANGELOG.md +++ b/docs/i18n/zh-CN/CHANGELOG.md @@ -4,6 +4,8 @@ --- +## [3.8.25] — 2026-06-14 + ## [3.8.26] — TBD _See English CHANGELOG for v3.8.26 details._ diff --git a/open-sse/mcp-server/__tests__/audit.test.ts b/open-sse/mcp-server/__tests__/audit.test.ts index 90e5713a589..d51541f17f4 100644 --- a/open-sse/mcp-server/__tests__/audit.test.ts +++ b/open-sse/mcp-server/__tests__/audit.test.ts @@ -86,4 +86,57 @@ describe("MCP audit shutdown", () => { expect(audit.closeAuditDb()).toBe(true); expect(mockDb.close).toHaveBeenCalledTimes(1); }); + + it("falls back to node:sqlite when better-sqlite3 binding is missing", async () => { + const [maj, min] = process.versions.node.split(".").map(Number); + if (maj < 22 || (maj === 22 && min < 5)) { + return; // node:sqlite not available on this Node, skip + } + + // Simulate a global-install scenario where the bundled native binary + // never landed in dist/node_modules/better-sqlite3/build/Release/. + const bindingErr = new Error( + "Could not locate the bindings file. Tried: …/better_sqlite3.node" + ) as Error & { code?: string }; + bindingErr.code = "MODULE_NOT_FOUND"; + // Simulate the binding-missing failure as the better-sqlite3 default + // constructor throwing — this matches reality (`new Database()` throws + // "Could not locate the bindings file" when the prebuilt .node is absent) + // and reaches the adapter's `catch (nativeErr)`. A factory that itself + // throws is reported by vitest as a mock-setup error and never reaches + // the code under test. + const ThrowingDatabase = vi.fn(function ThrowingDatabase() { + throw bindingErr; + }); + vi.doMock("better-sqlite3", () => ({ + default: ThrowingDatabase, + })); + + // node:sqlite's DatabaseSync does not expose a boolean `open` property, + // so the mock intentionally omits it — the adapter tracks open state in + // a local closure and exposes it via a getter. + const mockNodeDb = { + prepare: vi.fn(() => createStatementMock()), + exec: vi.fn(), + close: vi.fn(), + }; + const DatabaseSync = vi.fn(function DatabaseSync() { + return mockNodeDb; + }); + vi.doMock("node:sqlite", () => ({ DatabaseSync })); + + const audit = await import("../audit.ts"); + + await audit.logToolCall("omniroute_get_health", { ok: true }, { ok: true }, 4, true); + expect(DatabaseSync).toHaveBeenCalledWith(dbFile); + expect(mockNodeDb.prepare).toHaveBeenCalled(); + + expect(audit.closeAuditDb()).toBe(true); + expect(mockNodeDb.exec).toHaveBeenCalledWith("PRAGMA wal_checkpoint(TRUNCATE)"); + expect(mockNodeDb.close).toHaveBeenCalledTimes(1); + + // Cache is cleared after close, so a second close is a no-op. + expect(audit.closeAuditDb()).toBe(false); + expect(mockNodeDb.close).toHaveBeenCalledTimes(1); + }); }); diff --git a/open-sse/mcp-server/audit.ts b/open-sse/mcp-server/audit.ts index 18897035e06..259ded1c49f 100644 --- a/open-sse/mcp-server/audit.ts +++ b/open-sse/mcp-server/audit.ts @@ -7,6 +7,7 @@ */ import { hashInput, summarizeOutput } from "./schemas/audit.ts"; +import { isNativeSqliteLoadError } from "../../src/lib/db/core.ts"; // ============ Database Connection ============ @@ -21,6 +22,61 @@ interface AuditDatabase { pragma: (sql: string) => unknown; close: () => void; open?: boolean; + driver?: "better-sqlite3" | "node:sqlite"; +} + +interface NodeSqliteDatabase { + prepare: (sql: string) => { + run: (...params: unknown[]) => { changes: number | bigint; lastInsertRowid: number | bigint }; + get: (...params: unknown[]) => unknown; + all: (...params: unknown[]) => unknown[]; + }; + exec: (sql: string) => void; + close: () => void; +} + +/** + * node:sqlite's `DatabaseSync` does NOT expose a boolean `open` property — + * `open` and `close` are methods on the prototype, and the only state + * surface is the `isOpen` getter. Track open state locally in a closure + * so the adapter's `AuditDatabase` contract (`open?: boolean`) is honored + * and `getCachedAuditDb()`'s truthy check doesn't return a closed handle + * after `closeAuditDb()`. + */ +function createNodeSqliteAuditAdapter(db: NodeSqliteDatabase): AuditDatabase { + let _isOpen = true; + return { + driver: "node:sqlite", + get open() { + return _isOpen; + }, + prepare(sql: string) { + const stmt = db.prepare(sql); + return { + get: (...params: unknown[]) => stmt.get(...params) as TRow | undefined, + all: (...params: unknown[]) => stmt.all(...params) as TRow[], + run: (...params: unknown[]) => stmt.run(...params), + }; + }, + pragma(pragmaSql: string) { + // node:sqlite has no .pragma() helper — route through .exec() for + // statement-shaped PRAGMAs (e.g. "wal_checkpoint(TRUNCATE)"). + try { + db.exec(`PRAGMA ${pragmaSql}`); + return null; + } catch (err) { + return err instanceof Error ? err.message : String(err); + } + }, + close: () => { + if (!_isOpen) return; + try { + db.close(); + } finally { + _isOpen = false; + } + }, + }; } declare global { @@ -153,6 +209,15 @@ function toString(value: unknown): string { /** * Lazy-load the database connection. * Uses the same SQLite database as the main OmniRoute app. + * + * Driver priority: + * 1. better-sqlite3 — fast native binding (when its compiled `.node` + * binary is present, see scripts/build/postinstall.mjs). + * 2. node:sqlite — built-in to Node 22.5+. Used as a transparent + * fallback so the MCP audit logger still works on installs where + * the better-sqlite3 binary failed to resolve (e.g. missing + * `dist/node_modules/better-sqlite3/build/Release/better_sqlite3.node` + * in some global-install / Docker scenarios). */ async function getDb(): Promise { const cachedDb = getCachedAuditDb(); @@ -173,12 +238,59 @@ async function getDb(): Promise { return null; } - const Database = (await import("better-sqlite3")).default as unknown as new ( - dbPath: string - ) => AuditDatabase; - const database = new Database(dbPath); - setCachedAuditDb(database); - return database; + // Try better-sqlite3 first (matches the main app's default driver). + try { + const Database = (await import("better-sqlite3")).default as unknown as new ( + dbPath: string + ) => AuditDatabase; + const database = new Database(dbPath); + setCachedAuditDb(database); + return database; + } catch (nativeErr) { + // Declared once at the top of the catch: nativeMessage is read both on + // the non-fallback bail-out and in the node:sqlite fallback warning + // further down. A block-scoped const inside the `if` below would be out + // of scope in the fallback path. + const nativeMessage = nativeErr instanceof Error ? nativeErr.message : String(nativeErr); + // Reuse the canonical detection helper from the main app's DB layer + // so we cover every ABI/binding failure mode the rest of the codebase + // already knows about: missing MODULE_NOT_FOUND, ERR_DLOPEN_FAILED, + // "Module did not self-register", "Cannot find module 'better-sqlite3'", + // the standard V8 "was compiled against a different Node.js version" + // message, and the bindings-loader "Could not locate the bindings file". + // Real errors (corrupt db, permission denied) still surface to the operator. + if (!isNativeSqliteLoadError(nativeErr)) { + console.error("[MCP Audit] Failed to connect to database:", nativeMessage); + return null; + } + // Fall back to Node's built-in sqlite (Node 22.5+). + const [maj, min] = (process.versions.node ?? "0.0").split(".").map(Number); + if (maj < 22 || (maj === 22 && (min ?? 0) < 5)) { + console.error( + `[MCP Audit] better-sqlite3 native binding unavailable and Node ${process.version} ` + + "has no built-in sqlite. Audit logging disabled. Fix: run " + + "`npm rebuild better-sqlite3` in the omniroute install root." + ); + return null; + } + try { + const { DatabaseSync } = (await import("node:sqlite")) as { + DatabaseSync: new (p: string) => NodeSqliteDatabase; + }; + const nodeDb = new DatabaseSync(dbPath); + const adapter = createNodeSqliteAuditAdapter(nodeDb); + setCachedAuditDb(adapter); + console.warn( + `[MCP Audit] better-sqlite3 binding unavailable — fell back to node:sqlite ` + + `(${nativeMessage.split("\n")[0]})` + ); + return adapter; + } catch (nodeErr) { + const nodeMessage = nodeErr instanceof Error ? nodeErr.message : String(nodeErr); + console.error("[MCP Audit] Failed to connect to database:", nodeMessage); + return null; + } + } } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); console.error("[MCP Audit] Failed to connect to database:", message);