From 43305336f93f2e4456c65a55eab8af15ddcec3db Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 22 Apr 2026 14:57:52 -0700 Subject: [PATCH] fix(desktop): unbreak safe-url test on bun by splitting pure helpers `safe-url.ts` imports `shell` from electron at the module top level, so bun's test runner can't load the file and the whole suite fails with `SyntaxError: Export named 'shell' not found`. Moves the pure URL helpers (`isSafeExternalUrl`, `externalUrlLogLabel`) to `scheme.ts` and has the test import from there. `safeOpenExternal` stays in `safe-url.ts` with the electron import; the barrel keeps the same public surface. --- apps/desktop/src/main/lib/safe-url/index.ts | 7 ++--- .../src/main/lib/safe-url/safe-url.test.ts | 2 +- .../desktop/src/main/lib/safe-url/safe-url.ts | 26 +------------------ apps/desktop/src/main/lib/safe-url/scheme.ts | 24 +++++++++++++++++ 4 files changed, 28 insertions(+), 31 deletions(-) create mode 100644 apps/desktop/src/main/lib/safe-url/scheme.ts diff --git a/apps/desktop/src/main/lib/safe-url/index.ts b/apps/desktop/src/main/lib/safe-url/index.ts index d27a156d6cd..cec73bbf341 100644 --- a/apps/desktop/src/main/lib/safe-url/index.ts +++ b/apps/desktop/src/main/lib/safe-url/index.ts @@ -1,5 +1,2 @@ -export { - externalUrlLogLabel, - isSafeExternalUrl, - safeOpenExternal, -} from "./safe-url"; +export { safeOpenExternal } from "./safe-url"; +export { externalUrlLogLabel, isSafeExternalUrl } from "./scheme"; diff --git a/apps/desktop/src/main/lib/safe-url/safe-url.test.ts b/apps/desktop/src/main/lib/safe-url/safe-url.test.ts index 56ee203f1c7..33340bd175f 100644 --- a/apps/desktop/src/main/lib/safe-url/safe-url.test.ts +++ b/apps/desktop/src/main/lib/safe-url/safe-url.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "bun:test"; -import { externalUrlLogLabel, isSafeExternalUrl } from "./safe-url"; +import { externalUrlLogLabel, isSafeExternalUrl } from "./scheme"; describe("isSafeExternalUrl", () => { it("allows http, https, and mailto URLs", () => { diff --git a/apps/desktop/src/main/lib/safe-url/safe-url.ts b/apps/desktop/src/main/lib/safe-url/safe-url.ts index 4911f4d51b2..3ac8fb349d5 100644 --- a/apps/desktop/src/main/lib/safe-url/safe-url.ts +++ b/apps/desktop/src/main/lib/safe-url/safe-url.ts @@ -1,29 +1,5 @@ import { shell } from "electron"; - -/** - * Schemes safe to hand to Electron's `shell.openExternal`. - * Anything else (file:, javascript:, custom handlers, etc.) can execute - * binaries or scripts via the OS URL handler registry. - */ -const ALLOWED_SCHEMES = new Set(["http:", "https:", "mailto:"]); - -export function isSafeExternalUrl(url: string): boolean { - if (typeof url !== "string" || url.length === 0) return false; - try { - return ALLOWED_SCHEMES.has(new URL(url).protocol); - } catch { - return false; - } -} - -export function externalUrlLogLabel(url: string): string { - if (typeof url !== "string" || url.length === 0) return "empty"; - try { - return new URL(url).protocol || "unknown:"; - } catch { - return "malformed"; - } -} +import { externalUrlLogLabel, isSafeExternalUrl } from "./scheme"; /** * Wraps `shell.openExternal` with a scheme allowlist. Returns false and diff --git a/apps/desktop/src/main/lib/safe-url/scheme.ts b/apps/desktop/src/main/lib/safe-url/scheme.ts new file mode 100644 index 00000000000..0ca05a82aac --- /dev/null +++ b/apps/desktop/src/main/lib/safe-url/scheme.ts @@ -0,0 +1,24 @@ +/** + * Schemes safe to hand to Electron's `shell.openExternal`. + * Anything else (file:, javascript:, custom handlers, etc.) can execute + * binaries or scripts via the OS URL handler registry. + */ +const ALLOWED_SCHEMES = new Set(["http:", "https:", "mailto:"]); + +export function isSafeExternalUrl(url: string): boolean { + if (typeof url !== "string" || url.length === 0) return false; + try { + return ALLOWED_SCHEMES.has(new URL(url).protocol); + } catch { + return false; + } +} + +export function externalUrlLogLabel(url: string): string { + if (typeof url !== "string" || url.length === 0) return "empty"; + try { + return new URL(url).protocol || "unknown:"; + } catch { + return "malformed"; + } +}