mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 09:02:11 +03:00
fix(bun): use native bun:sqlite during startup to avoid N-API crash (#11468)
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip (Bun-native SQLite infrastructure cluster from the same contributor). - Focused test: bunSqliteAdapter.test.ts — part of batch's 5/5 node:test run - typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK - Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff Thanks for tracing this to the pre-boot better-sqlite3 require — a native NAPI abort that JS try/catch cannot recover from is exactly the kind of failure mode that needs the guard moved earlier, and aligning bootstrap/sync-env with the already-preferred bun:sqlite driver is the right fix.
This commit is contained in:
@@ -26,6 +26,17 @@ let resolvedCached = null;
|
||||
export async function loadSqliteRuntime() {
|
||||
if (resolvedCached) return resolvedCached;
|
||||
|
||||
if (process.versions.bun) {
|
||||
try {
|
||||
const bunSqlite = await import("bun:sqlite");
|
||||
resolvedCached = {
|
||||
driver: { kind: "bun-sqlite", Database: bunSqlite.Database },
|
||||
source: "bun-sqlite",
|
||||
};
|
||||
return resolvedCached;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const bundled = await tryLoadBundled();
|
||||
if (bundled) {
|
||||
resolvedCached = { driver: bundled, source: "bundled" };
|
||||
|
||||
1
changelog.d/fixes/11468-bun-sqlite-startup.md
Normal file
1
changelog.d/fixes/11468-bun-sqlite-startup.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(bun):** use native `bun:sqlite` in `bootstrap-env` and `sync-env` to avoid loading `better-sqlite3` N-API addon during Bun startup ([#11468](https://github.com/diegosouzapw/OmniRoute/pull/11468)) — thanks @TheDemonTuan
|
||||
@@ -82,6 +82,32 @@ function hasEncryptedCredentials(dataDir) {
|
||||
const dbPath = join(dataDir, "storage.sqlite");
|
||||
if (!existsSync(dbPath)) return false;
|
||||
|
||||
if (process.versions.bun) {
|
||||
try {
|
||||
const { Database } = require("bun:sqlite");
|
||||
const db = new Database(dbPath, { readonly: true, create: false });
|
||||
try {
|
||||
const row = db
|
||||
.query(
|
||||
`SELECT 1
|
||||
FROM provider_connections
|
||||
WHERE access_token LIKE 'enc:v1:%'
|
||||
OR refresh_token LIKE 'enc:v1:%'
|
||||
OR api_key LIKE 'enc:v1:%'
|
||||
OR id_token LIKE 'enc:v1:%'
|
||||
LIMIT 1`
|
||||
)
|
||||
.get();
|
||||
return !!row;
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Unable to inspect existing database at ${dbPath}: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const Database = require("better-sqlite3");
|
||||
const db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
||||
|
||||
@@ -93,12 +93,38 @@ function hasEncryptedCredentials(dataDir) {
|
||||
const dbPath = join(dataDir, "storage.sqlite");
|
||||
if (!existsSync(dbPath)) return false;
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
if (process.versions.bun) {
|
||||
try {
|
||||
const { Database } = require("bun:sqlite");
|
||||
const db = new Database(dbPath, { readonly: true, create: false });
|
||||
try {
|
||||
const row = db
|
||||
.query(
|
||||
`SELECT 1
|
||||
FROM provider_connections
|
||||
WHERE access_token LIKE 'enc:v1:%'
|
||||
OR refresh_token LIKE 'enc:v1:%'
|
||||
OR api_key LIKE 'enc:v1:%'
|
||||
OR id_token LIKE 'enc:v1:%'
|
||||
LIMIT 1`
|
||||
)
|
||||
.get();
|
||||
return !!row;
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Resolve `require` lazily here (not at module top-level): when this file is
|
||||
// bundled into a standalone route, a top-level `createRequire(import.meta.url)`
|
||||
// throws during module evaluation and 500s the whole route (#5006). Inside this
|
||||
// guarded block, any failure simply returns false (the safe default below).
|
||||
const require = createRequire(import.meta.url);
|
||||
const Database = require("better-sqlite3");
|
||||
const db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
||||
try {
|
||||
|
||||
@@ -81,3 +81,15 @@ test("bun:sqlite adapter backs up on-disk databases without serializing them", a
|
||||
assert.deepEqual(execCalls, ["PRAGMA wal_checkpoint(TRUNCATE)"]);
|
||||
assert.equal(fs.readFileSync(destinationPath, "utf8"), sourceContents);
|
||||
});
|
||||
|
||||
test("loadSqliteRuntime prioritizes bun:sqlite under Bun without loading better-sqlite3", async (t) => {
|
||||
if (!process.versions.bun) {
|
||||
t.skip("bun:sqlite is only available under Bun");
|
||||
return;
|
||||
}
|
||||
|
||||
const { loadSqliteRuntime } = await import("../../../bin/cli/runtime/sqliteRuntime.mjs");
|
||||
const runtime = await loadSqliteRuntime();
|
||||
assert.equal(runtime.driver.kind, "bun-sqlite");
|
||||
assert.equal(runtime.source, "bun-sqlite");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user