From 3a93a40e683bf772556c9fcf4edcd454d18ab115 Mon Sep 17 00:00:00 2001 From: herjarsa <204746071+herjarsa@users.noreply.github.com> Date: Thu, 7 May 2026 10:38:31 +0200 Subject: [PATCH] fix(desktop): hide bun:sqlite import from Node.js/Electron ESM loader Uses new Function() to prevent the static ESM loader from seeing the bun: protocol import at parse time. In Electron/Node.js, the import() call is evaluated at runtime and gracefully returns null when bun:sqlite is unavailable. Fixes #3829, likely fixes #3762 --- ...el-override.bun-sqlite-unavailable.test.ts | 4 +++- src/plugin/ultrawork-db-model-override.ts | 22 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/plugin/ultrawork-db-model-override.bun-sqlite-unavailable.test.ts b/src/plugin/ultrawork-db-model-override.bun-sqlite-unavailable.test.ts index ce305ffc8..bcaff8e27 100644 --- a/src/plugin/ultrawork-db-model-override.bun-sqlite-unavailable.test.ts +++ b/src/plugin/ultrawork-db-model-override.bun-sqlite-unavailable.test.ts @@ -13,7 +13,9 @@ describe("scheduleDeferredModelOverride bun:sqlite unavailable", () => { //#then expect(hasStaticBunSqliteImport).toBe(false) - expect(source).toContain('await import("bun:sqlite").catch(() => null)') + // new Function() hides the bun: import from Node.js/Electron static ESM loader + expect(source).toContain("new Function(\"return import('bun:sqlite')\")") + expect(source).toContain("typeof globalThis.Bun === \"undefined\"") expect(source).toContain("bun:sqlite unavailable") expect(source).toContain("return") }) diff --git a/src/plugin/ultrawork-db-model-override.ts b/src/plugin/ultrawork-db-model-override.ts index 3d83dc276..f88dba011 100644 --- a/src/plugin/ultrawork-db-model-override.ts +++ b/src/plugin/ultrawork-db-model-override.ts @@ -5,6 +5,24 @@ import { log } from "../shared" type BunDatabase = import("bun:sqlite").Database +/** + * Safely import bun:sqlite only when running in Bun runtime. + * Uses new Function() to hide the import from Node.js/Electron's static parser, + * which would fail on bun: protocol resolution before .catch() could run. + */ +async function importBunSqlite(): Promise { + if (typeof globalThis.Bun === "undefined") { + return null + } + try { + // new Function() prevents Node.js ESM loader from seeing the bun: import at parse time + const dynamicImport = new Function("return import('bun:sqlite')") as () => Promise + return await dynamicImport() + } catch { + return null + } +} + function getDbPath(): string { return join(getDataDir(), "opencode", "opencode.db") } @@ -114,7 +132,7 @@ export function scheduleDeferredModelOverride( variant?: string, ): void { queueMicrotask(async () => { - const sqliteModule = await import("bun:sqlite").catch(() => null) + const sqliteModule = await importBunSqlite() const Database = sqliteModule?.Database if (typeof Database !== "function") { log("[ultrawork-db-override] bun:sqlite unavailable, skipping deferred override", { messageId }) @@ -147,4 +165,4 @@ export function scheduleDeferredModelOverride( db.close() } }) -} +} \ No newline at end of file