Apply PR #23516: electron: use custom oc:// protocol for renderer windows
Some checks are pending
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404, x86_64-linux) (push) Waiting to run
nix-hashes / compute-hash (blacksmith-4vcpu-ubuntu-2404-arm, aarch64-linux) (push) Waiting to run
nix-hashes / compute-hash (macos-15-intel, x86_64-darwin) (push) Waiting to run
nix-hashes / compute-hash (macos-latest, aarch64-darwin) (push) Waiting to run
nix-hashes / update-hashes (push) Blocked by required conditions
publish / version (push) Waiting to run
publish / build-cli (push) Blocked by required conditions
publish / sign-cli-windows (push) Blocked by required conditions
publish / build-tauri (map[host:blacksmith-4vcpu-ubuntu-2404 target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-tauri (map[host:blacksmith-4vcpu-windows-2025 target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / build-tauri (map[host:blacksmith-8vcpu-ubuntu-2404-arm target:aarch64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-tauri (map[host:macos-latest target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / build-tauri (map[host:macos-latest target:x86_64-apple-darwin]) (push) Blocked by required conditions
publish / build-tauri (map[host:windows-2025 target:aarch64-pc-windows-msvc]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:aarch64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / build-electron (map[host:macos-latest platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[host:macos-latest platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Blocked by required conditions
publish / publish (push) Blocked by required conditions

This commit is contained in:
opencode-agent[bot] 2026-04-21 01:06:13 +00:00
commit 2cf03a2175
4 changed files with 43 additions and 8 deletions

View file

@ -42,7 +42,7 @@ import { initLogging } from "./logging"
import { parseMarkdown } from "./markdown" import { parseMarkdown } from "./markdown"
import { createMenu } from "./menu" import { createMenu } from "./menu"
import { getDefaultServerUrl, getWslConfig, setDefaultServerUrl, setWslConfig, spawnLocalServer } from "./server" import { getDefaultServerUrl, getWslConfig, setDefaultServerUrl, setWslConfig, spawnLocalServer } from "./server"
import { createLoadingWindow, createMainWindow, setBackgroundColor, setDockIcon } from "./windows" import { createLoadingWindow, createMainWindow, registerRendererProtocol, setBackgroundColor, setDockIcon } from "./windows"
import { drizzle } from "drizzle-orm/node-sqlite/driver" import { drizzle } from "drizzle-orm/node-sqlite/driver"
import type { Server } from "virtual:opencode-server" import type { Server } from "virtual:opencode-server"
@ -106,6 +106,7 @@ function setupApp() {
void app.whenReady().then(async () => { void app.whenReady().then(async () => {
app.setAsDefaultProtocolClient("opencode") app.setAsDefaultProtocolClient("opencode")
registerRendererProtocol()
setDockIcon() setDockIcon()
setupAutoUpdater() setupAutoUpdater()
await initialize() await initialize()

View file

@ -51,6 +51,7 @@ export async function spawnLocalServer(hostname: string, port: number, password:
hostname, hostname,
username: "opencode", username: "opencode",
password, password,
cors: ["oc://renderer"],
}) })
const relayURL = (process.env.OPENCODE_EXPERIMENTAL_PUSH_RELAY_URL ?? DEFAULT_RELAY_URL).trim() const relayURL = (process.env.OPENCODE_EXPERIMENTAL_PUSH_RELAY_URL ?? DEFAULT_RELAY_URL).trim()

View file

@ -1,7 +1,7 @@
import windowState from "electron-window-state" import windowState from "electron-window-state"
import { app, BrowserWindow, nativeImage, nativeTheme } from "electron" import { app, BrowserWindow, net, nativeImage, nativeTheme, protocol } from "electron"
import { dirname, join } from "node:path" import { dirname, isAbsolute, join, relative, resolve } from "node:path"
import { fileURLToPath } from "node:url" import { fileURLToPath, pathToFileURL } from "node:url"
import type { TitlebarTheme } from "../preload/types" import type { TitlebarTheme } from "../preload/types"
type Globals = { type Globals = {
@ -10,6 +10,20 @@ type Globals = {
} }
const root = dirname(fileURLToPath(import.meta.url)) const root = dirname(fileURLToPath(import.meta.url))
const rendererRoot = join(root, "../renderer")
const rendererProtocol = "oc"
const rendererHost = "renderer"
protocol.registerSchemesAsPrivileged([
{
scheme: rendererProtocol,
privileges: {
secure: true,
standard: true,
supportFetchAPI: true,
},
},
])
let backgroundColor: string | undefined let backgroundColor: string | undefined
@ -131,6 +145,25 @@ export function createLoadingWindow(globals: Globals) {
return win return win
} }
export function registerRendererProtocol() {
if (protocol.isProtocolHandled(rendererProtocol)) return
protocol.handle(rendererProtocol, (request) => {
const url = new URL(request.url)
if (url.host !== rendererHost) {
return new Response("Not found", { status: 404 })
}
const file = resolve(rendererRoot, `.${decodeURIComponent(url.pathname)}`)
const rel = relative(rendererRoot, file)
if (rel.startsWith("..") || isAbsolute(rel)) {
return new Response("Not found", { status: 404 })
}
return net.fetch(pathToFileURL(file).toString())
})
}
function loadWindow(win: BrowserWindow, html: string) { function loadWindow(win: BrowserWindow, html: string) {
const devUrl = process.env.ELECTRON_RENDERER_URL const devUrl = process.env.ELECTRON_RENDERER_URL
if (devUrl) { if (devUrl) {
@ -139,7 +172,7 @@ function loadWindow(win: BrowserWindow, html: string) {
return return
} }
void win.loadFile(join(root, `../renderer/${html}`)) void win.loadURL(`${rendererProtocol}://${rendererHost}/${html}`)
} }
function injectGlobals(win: BrowserWindow, globals: Globals) { function injectGlobals(win: BrowserWindow, globals: Globals) {

View file

@ -9,9 +9,9 @@ const root = resolve(dir, "../..")
const html = async (name: string) => Bun.file(join(dir, name)).text() const html = async (name: string) => Bun.file(join(dir, name)).text()
/** /**
* Electron loads renderer HTML via `win.loadFile()` which uses the `file://` * Packaged Electron windows load renderer HTML via the privileged `oc://`
* protocol. Absolute paths like `src="/foo.js"` resolve to the filesystem root * protocol. Root-relative asset paths like `src="/foo.js"` would resolve from
* (e.g. `file:///C:/foo.js` on Windows) instead of relative to the app bundle. * the protocol origin root instead of relative to the current HTML entrypoint.
* *
* All local resource references must use relative paths (`./`). * All local resource references must use relative paths (`./`).
*/ */