Files
orca/src/main/runtime/runtime-browser-network-execution-host.ts
T
NeilandOliver Mee cf460aba5a fix(browser): switch client-hosted profiles by staging the replacement guest (#30452)
* fix(browser): switch client-hosted profiles with staged guest replacement

Squashed from #30351 by @oliver-mee onto the current main.

Fixes #30350

* fix(browser): fence staged profile guests, release switch grants, carry host profile metadata

- A fence during automation retirement now revokes and stops the staged guest.
- A failed or late-settling switch releases its execution-host grant so the page can be recreated.
- Staging cleanup failures before handover stay visible to executor close.
- createPage/restorePage carry host-owned profile metadata to profile-switch-v1 desktops,
  so recovery and restore can rebuild a switched page.

* fix(browser): roll back a switch whose replacement died, and report a lost old guest

* fix(browser): resolve client-hosted pages before the server-local target path when switching profiles

* fix(browser): a staged profile-switch guest owns downloads it starts while loading

* fix(browser): keep the original placement until a timed-out switch settles

* fix(browser): rebind the original guest before releasing a rolled-back staged guest

* test(browser): type the harness guest release mock

* fix(browser): release the replaced generation's download transfers when a switch commits

* fix(browser): admit file transfers from a staged profile-switch guest while its switch is pending

* fix(browser): release only the replaced generation's download transfers after a switch

* refactor(shared): import BrowserNetworkExecutionHost from its own module, no re-export

* fix(browser): adopt a profile switch the client finished after the caller timed out

---------

Co-authored-by: Oliver Mee <102673257+oliver-mee@users.noreply.github.com>
2026-10-18 17:48:57 -07:00

58 lines
1.9 KiB
TypeScript

import type { BrowserNetworkExecutionHost } from '../../shared/browser-network-execution-host'
import { parseExecutionHostId, type ExecutionHostId } from '../../shared/execution-host'
import type { ProjectExecutionRuntimeResolution } from '../../shared/project-execution-runtime'
import type { SshConnectionState } from '../../shared/ssh-types'
type RuntimeBrowserNetworkExecutionHostInput = {
runtimeId: string
runtimeRevision: number
executionHostId: ExecutionHostId
projectRuntime?: ProjectExecutionRuntimeResolution
sshState?: SshConnectionState
}
export function resolveRuntimeBrowserNetworkExecutionHost(
input: RuntimeBrowserNetworkExecutionHostInput
): BrowserNetworkExecutionHost {
const host = parseExecutionHostId(input.executionHostId)
if (host?.kind === 'local') {
if (input.projectRuntime?.status === 'repair-required') {
throw new Error('browser_tunnel_execution_host_unavailable')
}
if (input.projectRuntime?.runtime.kind === 'wsl') {
return {
kind: 'wsl',
runtimeId: input.runtimeId,
revision: input.runtimeRevision,
distro: input.projectRuntime.runtime.distro
}
}
return {
kind: 'native',
runtimeId: input.runtimeId,
revision: input.runtimeRevision
}
}
if (host?.kind === 'ssh') {
const state = input.sshState
const connectionGeneration = state?.connectionGeneration
if (
state?.targetId !== host.targetId ||
state.status !== 'connected' ||
!state.providerEpoch ||
typeof connectionGeneration !== 'number' ||
!Number.isSafeInteger(connectionGeneration) ||
connectionGeneration < 0
) {
throw new Error('browser_tunnel_execution_host_unavailable')
}
return {
kind: 'ssh',
targetId: host.targetId,
providerEpoch: state.providerEpoch,
connectionGeneration
}
}
throw new Error('browser_tunnel_execution_host_unavailable')
}