Files
orca/src/shared/pty-consumer-session-hello.ts
T
Jinjing 5c09f53997 fix(ssh): handle owner displacement and graceful shutdown
SSH connections can reconnect with valid session proof after network loss or
device sleep. When the incumbent owner is still half-open, allow the
reconnecting client to displace it outright rather than wait for socket closure
— a window that may never close. Retain displaced deliveries for the new owner
to rotate. During app shutdown, drain SSH sessions without terminating recovery
operations, and retry pending owner grants in case a replacement commits mid-drain.
2026-08-03 22:59:51 -07:00

53 lines
2.0 KiB
TypeScript

import type { PtyConsumerSessionHello } from './pty-consumer-session-contract'
export const MAX_CAPABILITY_VERSIONS = 8
export function assertNonEmptyString(value: unknown, name: string): asserts value is string {
if (typeof value !== 'string' || value.length === 0 || value.length > 512) {
throw new Error(`${name} must be a non-empty string of at most 512 characters`)
}
}
export function validateHello(hello: PtyConsumerSessionHello): void {
assertNonEmptyString(hello.clientInstanceId, 'clientInstanceId')
if (hello.requestedRole !== 'session-owner' && hello.requestedRole !== 'subscriber') {
throw new Error('requestedRole must be session-owner or subscriber')
}
if (hello.resume) {
if (!Number.isSafeInteger(hello.resume.ownerGeneration) || hello.resume.ownerGeneration <= 0) {
throw new Error('resume.ownerGeneration must be a positive safe integer')
}
assertNonEmptyString(hello.resume.ownerLease, 'resume.ownerLease')
}
const flow = hello.capabilities?.outputFlowControl
if (!flow) {
return
}
if (
!Array.isArray(flow.versions) ||
flow.versions.length > MAX_CAPABILITY_VERSIONS ||
flow.versions.some((version) => !Number.isSafeInteger(version) || version <= 0)
) {
throw new Error('outputFlowControl.versions must contain positive safe integers')
}
if (!Number.isSafeInteger(flow.requestedWindowSu) || flow.requestedWindowSu <= 0) {
throw new Error('outputFlowControl.requestedWindowSu must be a positive safe integer')
}
}
// Why: a duplicate open on one connection is only idempotent if it asks for exactly the same thing.
export function helloFingerprint(hello: PtyConsumerSessionHello): string {
const flow = hello.capabilities?.outputFlowControl
return JSON.stringify({
clientInstanceId: hello.clientInstanceId,
requestedRole: hello.requestedRole,
resume: hello.resume,
outputFlowControl: flow
? {
versions: [...flow.versions].sort((a, b) => a - b),
requestedWindowSu: flow.requestedWindowSu
}
: undefined
})
}