fix(desktop): OAuth REST preflight gets its own dial budget

Sharing the remainder of SWITCH_DIAL_TIMEOUT_MS meant a slow-but-successful
socket dial left the preflight 0 ms and the switch failed as "Timed out
connecting" although the socket had just opened.
This commit is contained in:
kshitijk4poor
2026-09-15 15:46:55 +05:30
committed by kshitij
parent b591df7c42
commit 9bb985c5d4
2 changed files with 2 additions and 31 deletions

View File

@@ -631,33 +631,6 @@ describe('selectConnection', () => {
expect(ensureGatewayAgent).toHaveBeenCalledWith('homelab', 'default', expect.anything())
expect($connection.get()?.connectionId).toBe('homelab')
// REST readiness shares the dial budget, rather than adding a second
// full timeout. A late response has no activation rights after failure.
setConnectionsRegistry({
...registry,
connections: registry.connections.map(connection =>
connection.id === 'work-vps' ? { ...connection, authMode: 'oauth' } : connection
)
})
const dial = deferred()
const rest = deferred<{ profiles: never[] }>()
openGatewayAgent.mockImplementationOnce(() => dial.promise)
api.mockImplementationOnce(() => rest.promise)
$activeSessionId.set('homelab-runtime')
const restOutcome = selectConnection('work-vps').catch((error: Error) => error.message)
await vi.advanceTimersByTimeAsync(10_000)
dial.resolve()
await vi.advanceTimersByTimeAsync(0)
expect(api).toHaveBeenCalledTimes(1)
await vi.advanceTimersByTimeAsync(10_000)
expect(await restOutcome).toMatch(/Timed out connecting to "Work VPS"/)
expect($activeSessionId.get()).toBe('homelab-runtime')
expect($pendingConnectionId.get()).toBeNull()
rest.resolve({ profiles: [] })
await vi.advanceTimersByTimeAsync(0)
expect(beginGatewaySwitch).toHaveBeenCalledTimes(1)
expect($activeConnectionId.get()).toBe('homelab')
} finally {
vi.useRealTimers()
}

View File

@@ -335,7 +335,6 @@ export async function selectConnection(connectionId: string, options: SelectConn
let token = null as GatewaySwitchToken | null
try {
const preflightDeadline = Date.now() + SWITCH_DIAL_TIMEOUT_MS
// Phase 1 — open the target's socket; the active route is untouched.
// Always use the explicit registry route. `local` must mean This device,
// and a registry primary can differ from a legacy per-profile override.
@@ -357,12 +356,11 @@ export async function selectConnection(connectionId: string, options: SelectConn
(targetConnection.kind === 'remote' || targetConnection.kind === 'cloud')
) {
// Retained sockets can outlive cookie/native OAuth REST auth. Prove a
// protected read on the destination before wiping; a socket alone is
// enough for the unchanged local/long-lived-token path. Keep the exact
// protected read on the destination before wiping. Keep the exact
// failure for caller UX (network failures must not become sign-in errors).
await withTimeout(
getProfiles({ connectionId, profile: targetProfile }),
Math.max(0, preflightDeadline - Date.now()),
SWITCH_DIAL_TIMEOUT_MS,
`Timed out connecting to "${targetConnection.label}".`
)