Files
orca/src/main/browser/browser-screencast-debugger-command.ts
T
Brennan Benson 4ebec19f46 fix(browser): a crashed page no longer crashes Orca when its viewport is resized (#23852)
* fix(browser): never resize a browser tab whose page crashed, which segfaulted Orca

Chromium's Emulation.setDeviceMetricsOverride and Emulation.setVisibleSize
resize the page's view without checking it still exists
(WebContentsImpl::SetDeviceEmulationSize). A crashed page renderer takes
its view with it until a reload builds a new one, so either command sent
in that gap killed Orca's whole main process with SIGSEGV.

One gate, sendGuestCdpCommand, now refuses those two commands while the
tab's renderer is gone. The viewport preset writer, the agent viewport
command, the agent bridge's command sender, the CDP proxy and the
screencast device metrics all send through it. The check runs in the same
task as the send, so the renderer cannot die in between. The page's own
reload reapplies the chosen preset on dom-ready, as it already did.

* test(browser): type the CDP gate's target so its test double needs no cast

CI's changed-lines gate rejects new type assertions. The gate only uses
isDestroyed, isCrashed and debugger.sendCommand, so it now takes exactly
that shape; the viewport test keeps the one fixture cast its siblings use,
with a line-specific SAFETY note.
2026-09-29 15:12:32 -07:00

33 lines
858 B
TypeScript

import type { WebContents } from 'electron'
const DEBUGGER_COMMAND_TIMEOUT_MS = 8_000
export function sendDebuggerCommand(
dbg: WebContents['debugger'],
method: string,
params: Record<string, unknown> = {}
): Promise<unknown> {
return runDebuggerCommandWithTimeout(method, () => dbg.sendCommand(method, params))
}
export async function runDebuggerCommandWithTimeout(
method: string,
send: () => Promise<unknown>
): Promise<unknown> {
let timeout: ReturnType<typeof setTimeout> | null = null
try {
return await Promise.race([
Promise.resolve().then(send),
new Promise<never>((_, reject) => {
timeout = setTimeout(() => {
reject(new Error(`Timed out while running ${method}.`))
}, DEBUGGER_COMMAND_TIMEOUT_MS)
})
])
} finally {
if (timeout) {
clearTimeout(timeout)
}
}
}