| 202 | } |
| 203 | |
| 204 | export function decodeClientFrame(value: unknown): ClientFrame { |
| 205 | const frame = requireRecord(value, 'client frame'); |
| 206 | if (frame.kind === 'hello') { |
| 207 | const protocolMin = requireProtocolVersion(frame.protocolMin, 'protocolMin'); |
| 208 | const protocolMax = requireProtocolVersion(frame.protocolMax, 'protocolMax'); |
| 209 | validateProtocolRange({ min: protocolMin, max: protocolMax }); |
| 210 | const generation = |
| 211 | frame.generation === undefined ? undefined : requireHostGeneration(frame.generation); |
| 212 | const takeover = decodeTakeover(frame.takeover); |
| 213 | if (takeover !== undefined && generation === undefined) { |
| 214 | throw invalidProtocolFrame('Runtime Host takeover requires a generation'); |
| 215 | } |
| 216 | return { |
| 217 | kind: 'hello', |
| 218 | clientInstanceId: requireClientInstanceId(frame.clientInstanceId), |
| 219 | surface: requireSurface(frame.surface), |
| 220 | protocolMin, |
| 221 | protocolMax, |
| 222 | compatibilityEpoch: decodeCompatibilityEpoch(frame.compatibilityEpoch), |
| 223 | compositionId: decodeCompositionId(frame.compositionId), |
| 224 | ...(generation === undefined ? {} : { generation }), |
| 225 | ...(takeover === undefined ? {} : { takeover }), |
| 226 | } satisfies ClientHello; |
| 227 | } |
| 228 | if (isClientCapabilityClientFrameKind(frame.kind)) { |
| 229 | return decodeClientCapabilityClientFrame(frame); |
| 230 | } |
| 231 | return decodeRequestFrame(frame); |
| 232 | } |
| 233 | |
| 234 | export function decodeHostFrame(value: unknown): HostFrame { |
| 235 | const frame = requireRecord(value, 'host frame'); |