@swifttui/web 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.js +2 -2
  3. package/dist/src/CanvasSurfacePainter.d.ts +16 -0
  4. package/dist/src/CanvasSurfacePainter.js +160 -21
  5. package/dist/src/CanvasSurfacePainter.js.map +1 -1
  6. package/dist/src/DomSurfacePainter.d.ts +17 -3
  7. package/dist/src/DomSurfacePainter.js +50 -5
  8. package/dist/src/DomSurfacePainter.js.map +1 -1
  9. package/dist/src/SurfacePainterConformanceControl.js +13 -0
  10. package/dist/src/SurfacePainterConformanceControl.js.map +1 -0
  11. package/dist/src/SurfaceRenderer.d.ts +3 -2
  12. package/dist/src/SurfaceRenderer.js.map +1 -1
  13. package/dist/src/WebHostSceneRuntime.d.ts +3 -1
  14. package/dist/src/WebHostSceneRuntime.js +9 -6
  15. package/dist/src/WebHostSceneRuntime.js.map +1 -1
  16. package/dist/src/WebHostSurfaceTransport.d.ts +39 -4
  17. package/dist/src/WebHostSurfaceTransport.js +131 -9
  18. package/dist/src/WebHostSurfaceTransport.js.map +1 -1
  19. package/dist/src/WebSocketSceneBridge.d.ts +2 -1
  20. package/dist/src/WebSocketSceneBridge.js +26 -11
  21. package/dist/src/WebSocketSceneBridge.js.map +1 -1
  22. package/dist/src/normalizeWireTokens.d.ts +5 -0
  23. package/dist/src/wasi/BrowserWASIBridge.d.ts +8 -0
  24. package/dist/src/wasi/BrowserWASIBridge.js +29 -7
  25. package/dist/src/wasi/BrowserWASIBridge.js.map +1 -1
  26. package/dist/src/wasi/SharedInputQueue.d.ts +2 -0
  27. package/dist/src/wasi/SharedInputQueue.js +22 -0
  28. package/dist/src/wasi/SharedInputQueue.js.map +1 -1
  29. package/dist/src/wasi/WasmSceneRuntime.js +15 -1
  30. package/dist/src/wasi/WasmSceneRuntime.js.map +1 -1
  31. package/dist/src/wasi/WasmSceneWorker.js +1 -1
  32. package/dist/testing.d.ts +2 -1
  33. package/dist/wasi.js +1 -1
  34. package/package.json +2 -1
@@ -7,6 +7,12 @@ import { encodeWebHostTerminalRenderStyleBase64 } from "./WebHostTerminalStyle.j
7
7
  */
8
8
  const recordPrefix = "";
9
9
  const textEncoder = new TextEncoder();
10
+ /** Limits wire-derived recovery state and keeps every single-ID WASI request bounded. */
11
+ const MAX_IMAGE_RECOVERY_ID_BYTES = 1024;
12
+ const MAX_OUTSTANDING_IMAGE_RECOVERY_IDS = 1024;
13
+ function isWebHostImageRecoveryId(id) {
14
+ return id.length > 0 && id.length <= 1024 && textEncoder.encode(id).byteLength <= 1024;
15
+ }
10
16
  /**
11
17
  * The newest `surface` record version this runtime understands. Unknown
12
18
  * additive object keys are ignored by design (older runtimes render newer
@@ -22,8 +28,11 @@ var WebHostOutputDecoder = class {
22
28
  lastSurfaceFrame;
23
29
  lastEpoch;
24
30
  lastGen;
25
- pendingResyncRequest;
31
+ lastPresentedEpoch;
26
32
  keyframeResyncOutstanding = false;
33
+ keyframeResyncPending = false;
34
+ imageResyncOutstandingIds = /* @__PURE__ */ new Set();
35
+ imageResyncPendingIds = /* @__PURE__ */ new Set();
27
36
  feed(chunk) {
28
37
  this.bufferedText += this.textDecoder.decode(chunk, { stream: true });
29
38
  const records = [];
@@ -49,13 +58,68 @@ var WebHostOutputDecoder = class {
49
58
  this.bufferedText = "";
50
59
  return [this.decodeLine(text)];
51
60
  }
52
- takeResyncRequest() {
53
- const request = this.pendingResyncRequest;
54
- this.pendingResyncRequest = void 0;
55
- return request;
61
+ takeResyncRequest(maximumEncodedBytes) {
62
+ if (this.keyframeResyncPending) {
63
+ this.keyframeResyncPending = false;
64
+ return { scope: "keyframe" };
65
+ }
66
+ if (this.imageResyncPendingIds.size === 0) return;
67
+ const { ids, rejectedIds } = boundedImageResyncIds([...this.imageResyncPendingIds].sort(), maximumEncodedBytes);
68
+ for (const id of rejectedIds) {
69
+ this.imageResyncPendingIds.delete(id);
70
+ this.imageResyncOutstandingIds.delete(id);
71
+ }
72
+ for (const id of ids) this.imageResyncPendingIds.delete(id);
73
+ if (ids.length === 0) return;
74
+ return {
75
+ scope: "images",
76
+ ids
77
+ };
78
+ }
79
+ /**
80
+ * Adds locally unresolved image IDs to this epoch's recovery set. IDs remain
81
+ * outstanding after delivery, so repeat painter misses cannot create storms;
82
+ * a payload-bearing record or epoch re-anchor releases them. Returns the IDs
83
+ * now tracked (new or already outstanding); callers should suppress repeats
84
+ * only for this admitted subset.
85
+ */
86
+ requestImagePayloads(ids) {
87
+ const acceptedIds = /* @__PURE__ */ new Set();
88
+ for (const id of ids) {
89
+ if (!isWebHostImageRecoveryId(id)) continue;
90
+ if (this.imageResyncOutstandingIds.has(id)) {
91
+ acceptedIds.add(id);
92
+ continue;
93
+ }
94
+ if (this.imageResyncOutstandingIds.size >= 1024) continue;
95
+ this.imageResyncOutstandingIds.add(id);
96
+ this.imageResyncPendingIds.add(id);
97
+ acceptedIds.add(id);
98
+ }
99
+ return [...acceptedIds];
100
+ }
101
+ /**
102
+ * Advances image recovery immediately before one decoded surface reaches its
103
+ * presenter. Payload arrival and epoch reset therefore follow delivery order
104
+ * rather than `feed`'s parse-ahead order across a multi-record chunk. The
105
+ * return value identifies payloads that answer an outstanding image request,
106
+ * so presenters can open exactly one fresh local decode generation even when
107
+ * content-addressed retransmission uses identical bytes.
108
+ */
109
+ prepareToPresentSurface(frame) {
110
+ const recoveredImagePayloadIds = this.recoveredImagePayloadIds(frame.images);
111
+ this.resetImageResyncForEpoch(frame.epoch);
112
+ this.sweepImageResyncForPresentedImages(frame.images);
113
+ this.clearArrivedImagePayloads(frame.images);
114
+ if (frame.epoch !== void 0) this.lastPresentedEpoch = frame.epoch;
115
+ return recoveredImagePayloadIds;
56
116
  }
57
117
  resyncRequestDeliveryFailed(request) {
58
- if (request.scope === "keyframe" && this.keyframeResyncOutstanding && this.pendingResyncRequest === void 0) this.pendingResyncRequest = request;
118
+ if (request.scope === "keyframe") {
119
+ if (this.keyframeResyncOutstanding) this.keyframeResyncPending = true;
120
+ return;
121
+ }
122
+ for (const id of request.ids ?? []) if (this.imageResyncOutstandingIds.has(id)) this.imageResyncPendingIds.add(id);
59
123
  }
60
124
  decodeLine(line) {
61
125
  if (line.startsWith(`${recordPrefix}clipboard:`)) {
@@ -116,8 +180,8 @@ var WebHostOutputDecoder = class {
116
180
  this.lastSurfaceFrame = frame;
117
181
  this.lastEpoch = frame.epoch;
118
182
  this.lastGen = frame.gen;
119
- this.pendingResyncRequest = void 0;
120
183
  this.keyframeResyncOutstanding = false;
184
+ this.keyframeResyncPending = false;
121
185
  return {
122
186
  type: "surface",
123
187
  frame
@@ -159,7 +223,33 @@ var WebHostOutputDecoder = class {
159
223
  requestKeyframeResync() {
160
224
  if (this.keyframeResyncOutstanding) return;
161
225
  this.keyframeResyncOutstanding = true;
162
- this.pendingResyncRequest = { scope: "keyframe" };
226
+ this.keyframeResyncPending = true;
227
+ }
228
+ resetImageResyncForEpoch(epoch) {
229
+ if (epoch === void 0 || epoch === this.lastPresentedEpoch) return;
230
+ this.imageResyncOutstandingIds.clear();
231
+ this.imageResyncPendingIds.clear();
232
+ }
233
+ clearArrivedImagePayloads(images) {
234
+ for (const image of images ?? []) {
235
+ if (image.dataBase64 === void 0) continue;
236
+ this.imageResyncOutstandingIds.delete(image.id);
237
+ this.imageResyncPendingIds.delete(image.id);
238
+ }
239
+ }
240
+ recoveredImagePayloadIds(images) {
241
+ const recoveredIds = /* @__PURE__ */ new Set();
242
+ for (const image of images ?? []) if (image.dataBase64 !== void 0 && this.imageResyncOutstandingIds.has(image.id)) recoveredIds.add(image.id);
243
+ return [...recoveredIds].sort();
244
+ }
245
+ sweepImageResyncForPresentedImages(images) {
246
+ const presentedIds = /* @__PURE__ */ new Set();
247
+ for (const image of images ?? []) if (this.imageResyncOutstandingIds.has(image.id)) presentedIds.add(image.id);
248
+ for (const id of this.imageResyncOutstandingIds) {
249
+ if (presentedIds.has(id)) continue;
250
+ this.imageResyncOutstandingIds.delete(id);
251
+ this.imageResyncPendingIds.delete(id);
252
+ }
163
253
  }
164
254
  materializeDeltaFrame(frame) {
165
255
  const baseline = this.lastSurfaceFrame;
@@ -191,6 +281,38 @@ var WebHostOutputDecoder = class {
191
281
  };
192
282
  }
193
283
  };
284
+ function boundedImageResyncIds(sortedIds, maximumEncodedBytes) {
285
+ if (maximumEncodedBytes === void 0 || !Number.isFinite(maximumEncodedBytes)) return {
286
+ ids: sortedIds,
287
+ rejectedIds: []
288
+ };
289
+ const emptyRequestBytes = encodeResyncControlMessage({
290
+ scope: "images",
291
+ ids: []
292
+ }).byteLength;
293
+ const normalizedMaximum = Math.max(0, Math.floor(maximumEncodedBytes));
294
+ const ids = [];
295
+ const rejectedIds = [];
296
+ let encodedBytes = emptyRequestBytes;
297
+ for (const id of sortedIds) {
298
+ const separatorBytes = ids.length === 0 ? 0 : 1;
299
+ const idBytes = textEncoder.encode(JSON.stringify(id)).byteLength;
300
+ if (encodedBytes + separatorBytes + idBytes > normalizedMaximum) {
301
+ if (ids.length === 0) {
302
+ rejectedIds.push(id);
303
+ continue;
304
+ }
305
+ break;
306
+ }
307
+ ids.push(id);
308
+ encodedBytes += separatorBytes + idBytes;
309
+ if (encodedBytes >= normalizedMaximum) break;
310
+ }
311
+ return {
312
+ ids,
313
+ rejectedIds
314
+ };
315
+ }
194
316
  function declaresNewerSurfaceVersion(value) {
195
317
  if (!value || typeof value !== "object") return false;
196
318
  const version = value.version;
@@ -359,6 +481,6 @@ function isWebHostSurfaceScalingMode(value) {
359
481
  return typeof value === "string";
360
482
  }
361
483
  //#endregion
362
- export { SUPPORTED_SURFACE_VERSION, WebHostOutputDecoder, encodeCapabilitiesControlMessage, encodeKeyInputMessage, encodeMouseInputMessage, encodePasteInputMessage, encodeRenderStyleControlMessage, encodeResizeControlMessage, encodeResyncControlMessage };
484
+ export { MAX_IMAGE_RECOVERY_ID_BYTES, MAX_OUTSTANDING_IMAGE_RECOVERY_IDS, SUPPORTED_SURFACE_VERSION, WebHostOutputDecoder, encodeCapabilitiesControlMessage, encodeKeyInputMessage, encodeMouseInputMessage, encodePasteInputMessage, encodeRenderStyleControlMessage, encodeResizeControlMessage, encodeResyncControlMessage, isWebHostImageRecoveryId };
363
485
 
364
486
  //# sourceMappingURL=WebHostSurfaceTransport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebHostSurfaceTransport.js","names":[],"sources":["../../src/WebHostSurfaceTransport.ts"],"sourcesContent":["/**\n * Browser consumer for SwiftTUI's host wire. The normative cross-host\n * contract lives upstream:\n * https://github.com/SwiftTUI/swift-tui/blob/main/docs/HOST-WIRE-CONTRACT.md\n */\nimport {\n encodeWebHostTerminalRenderStyleBase64,\n type WebHostTerminalStyle,\n} from \"./WebHostTerminalStyle.ts\";\n\nexport interface WebHostSurfaceStyle {\n fg?: string;\n bg?: string;\n em?: number;\n underline?: WebHostSurfaceLineStyle;\n strikethrough?: WebHostSurfaceLineStyle;\n opacity?: number;\n}\n\nexport interface WebHostSurfaceLineStyle {\n pattern: \"solid\" | \"dot\" | \"dash\" | \"dashDot\" | \"dashDotDot\" | \"double\" | \"curly\";\n color?: string;\n}\n\nexport type WebHostSurfaceCell = [\n x: number,\n text: string,\n span: number,\n styleIndex: number,\n];\n\nexport type WebHostSurfaceRect = [\n x: number,\n y: number,\n width: number,\n height: number,\n];\n\nexport type WebHostSurfaceSize = [\n width: number,\n height: number,\n];\n\nexport type WebHostAccessibilityPoint = [\n x: number,\n y: number,\n];\n\nexport type WebHostAccessibilityLiveRegion = string;\n\nexport interface WebHostAccessibilityNode {\n id: string;\n parentId?: string;\n rect: WebHostSurfaceRect;\n role: string;\n label?: string;\n hint?: string;\n /** omitted when false */\n hidden?: boolean;\n liveRegion?: WebHostAccessibilityLiveRegion;\n cursorAnchor?: WebHostAccessibilityPoint;\n isFocused?: boolean;\n}\n\n/**\n * One hyperlink run within a row: [x, spanWidth, linkTargetIndex]. The index\n * points into the frame's deduplicated `linkTargets` table.\n */\nexport type WebHostSurfaceLinkRun = [\n x: number,\n span: number,\n targetIndex: number,\n];\n\n/** Hyperlink runs for one row: [rowIndex, runs]. */\nexport type WebHostSurfaceLinkRow = [\n row: number,\n runs: WebHostSurfaceLinkRun[],\n];\n\nexport type WebHostFocusSemantics = string;\n\n/**\n * The settled focus presentation for a committed frame — the same derivation\n * the Android host consumes (`prefersTextInput` gates its IME).\n */\nexport interface WebHostFocusPresentation {\n focusedIdentity?: string;\n semantics: WebHostFocusSemantics;\n prefersTextInput: boolean;\n hasFocusedRegion: boolean;\n}\n\nexport interface WebHostAccessibilityAnnouncement {\n message: string;\n politeness: WebHostAccessibilityLiveRegion;\n}\n\nexport type WebHostSurfaceImageFormat = string;\n\nexport interface WebHostSurfaceImage {\n id: string;\n format: WebHostSurfaceImageFormat;\n bounds: WebHostSurfaceRect;\n visibleBounds: WebHostSurfaceRect;\n scalingMode: string;\n pixelSize?: WebHostSurfaceSize;\n dataBase64?: string;\n}\n\nexport type WebHostSurfaceDamageRange = [\n start: number,\n end: number,\n];\n\nexport type WebHostSurfaceDamageTextRow = [\n row: number,\n ranges: WebHostSurfaceDamageRange[],\n];\n\nexport interface WebHostSurfaceDamage {\n textRows: WebHostSurfaceDamageTextRow[];\n requiresFullTextRepaint: boolean;\n requiresFullGraphicsReplay: boolean;\n}\n\n/**\n * Per-region scroll extent published with each frame so the host can implement\n * scroll-chaining: capture the wheel only while the region under the pointer can\n * still scroll in the wheel's direction, otherwise let it fall through to the\n * page. The host recomputes the per-direction headroom from `offset`/`content`/\n * the viewport `rect`, mirroring SwiftTUI's\n * `min(max(0, offset), max(0, content - viewport))` clamp.\n */\nexport interface WebHostScrollRegion {\n /** identity path — same key space as accessibility node ids */\n id: string;\n /** viewport rect in cells: [x, y, width, height] */\n rect: WebHostSurfaceRect;\n /** current clamped scroll offset in cells: [x, y] */\n offset: WebHostAccessibilityPoint;\n /** total content size in cells: [width, height] */\n content: WebHostSurfaceSize;\n}\n\nexport interface WebHostSurfaceFrame {\n version: 1 | 2;\n epoch?: number;\n gen?: number;\n sequence?: number;\n width: number;\n height: number;\n styles: Array<WebHostSurfaceStyle | null>;\n rows: WebHostSurfaceCell[][];\n images?: WebHostSurfaceImage[];\n damage?: WebHostSurfaceDamage;\n accessibilityTree?: WebHostAccessibilityNode[];\n accessibilityAnnouncements?: WebHostAccessibilityAnnouncement[];\n scrollRegions?: WebHostScrollRegion[];\n links?: WebHostSurfaceLinkRow[];\n linkTargets?: string[];\n focusPresentation?: WebHostFocusPresentation;\n preferredGridWidth?: number;\n preferredGridHeight?: number;\n}\n\nexport type WebHostSurfaceDeltaRow = [\n row: number,\n cells: WebHostSurfaceCell[],\n];\n\nexport interface WebHostSurfaceDeltaFrame {\n version: 3;\n encoding: \"delta\";\n epoch?: number;\n gen?: number;\n baselineGen?: number;\n sequence?: number;\n width: number;\n height: number;\n styles: Array<WebHostSurfaceStyle | null>;\n deltaRows: WebHostSurfaceDeltaRow[];\n images?: WebHostSurfaceImage[];\n damage?: WebHostSurfaceDamage;\n accessibilityTree?: WebHostAccessibilityNode[];\n accessibilityAnnouncements?: WebHostAccessibilityAnnouncement[];\n scrollRegions?: WebHostScrollRegion[];\n links?: WebHostSurfaceLinkRow[];\n linkTargets?: string[];\n focusPresentation?: WebHostFocusPresentation;\n preferredGridWidth?: number;\n preferredGridHeight?: number;\n}\n\nexport interface WebHostRuntimeIssue {\n severity: \"warning\" | \"error\";\n code: string;\n message: string;\n description: string;\n identity?: string;\n source?: string;\n}\n\nexport interface WebHostFrameDiagnosticRecord {\n format: \"swift-tui-frame-diagnostics-v1\";\n header: string[];\n fields: string[];\n}\n\nexport type WebHostOutputRecord =\n | { type: \"surface\"; frame: WebHostSurfaceFrame }\n | { type: \"clipboard\"; text: string }\n | { type: \"runtimeIssue\"; issue: WebHostRuntimeIssue }\n | { type: \"frameDiagnostic\"; diagnostic: WebHostFrameDiagnosticRecord }\n | { type: \"surfaceDropped\"; reason: \"noBaseline\" | \"staleBaseline\" }\n | { type: \"text\"; text: string };\n\nexport type WebHostResyncRequest =\n | { scope: \"keyframe\" }\n | { scope: \"images\"; ids?: string[] };\n\nexport interface WebHostOutputSink {\n presentSurface(frame: WebHostSurfaceFrame): void;\n writeClipboard?(text: string): void | Promise<void>;\n notifyRuntimeIssue?(issue: WebHostRuntimeIssue): void;\n recordFrameDiagnostic?(diagnostic: WebHostFrameDiagnosticRecord): void;\n writeOutput?(text: string): void;\n writeError?(text: string): void;\n}\n\nexport interface WebHostKeyInput {\n key:\n | \"return\"\n | \"space\"\n | \"tab\"\n | \"arrowLeft\"\n | \"arrowRight\"\n | \"arrowUp\"\n | \"arrowDown\"\n | \"backspace\"\n | \"escape\"\n | \"home\"\n | \"end\"\n | \"character\";\n character?: string;\n modifiers?: number;\n}\n\nexport interface WebHostMouseInput {\n kind: \"down\" | \"up\" | \"moved\" | \"dragged\" | \"scrolled\";\n x: number;\n y: number;\n button?: \"primary\" | \"middle\" | \"secondary\";\n deltaX?: number;\n deltaY?: number;\n modifiers?: number;\n}\n\nconst recordPrefix = \"\\u001E\";\nconst textEncoder = new TextEncoder();\n\n/**\n * The newest `surface` record version this runtime understands. Unknown\n * additive object keys are ignored by design (older runtimes render newer\n * frames), but a frame declaring a NEWER version than this is surfaced as an\n * error-severity runtime issue instead of silently degrading to a text\n * diagnostic — silent version skew is the failure mode this guards against\n * (F57).\n */\nexport const SUPPORTED_SURFACE_VERSION = 3;\n\nexport class WebHostOutputDecoder {\n private readonly textDecoder = new TextDecoder();\n private bufferedText = \"\";\n private lastSurfaceFrame?: WebHostSurfaceFrame;\n private lastEpoch?: number;\n private lastGen?: number;\n private pendingResyncRequest?: WebHostResyncRequest;\n private keyframeResyncOutstanding = false;\n\n feed(\n chunk: Uint8Array\n ): WebHostOutputRecord[] {\n this.bufferedText += this.textDecoder.decode(chunk, { stream: true });\n const records: WebHostOutputRecord[] = [];\n\n while (true) {\n const newlineIndex = this.bufferedText.indexOf(\"\\n\");\n if (newlineIndex < 0) {\n break;\n }\n\n const line = this.bufferedText.slice(0, newlineIndex);\n this.bufferedText = this.bufferedText.slice(newlineIndex + 1);\n records.push(this.decodeLine(line));\n }\n\n if (this.bufferedText.length > 4096 && !this.bufferedText.startsWith(recordPrefix)) {\n records.push({ type: \"text\", text: this.bufferedText });\n this.bufferedText = \"\";\n }\n\n return records;\n }\n\n flush(): WebHostOutputRecord[] {\n if (!this.bufferedText) {\n return [];\n }\n const text = this.bufferedText;\n this.bufferedText = \"\";\n return [this.decodeLine(text)];\n }\n\n takeResyncRequest(): WebHostResyncRequest | undefined {\n const request = this.pendingResyncRequest;\n this.pendingResyncRequest = undefined;\n return request;\n }\n\n resyncRequestDeliveryFailed(\n request: WebHostResyncRequest\n ): void {\n if (\n request.scope === \"keyframe\"\n && this.keyframeResyncOutstanding\n && this.pendingResyncRequest === undefined\n ) {\n this.pendingResyncRequest = request;\n }\n }\n\n private decodeLine(\n line: string\n ): WebHostOutputRecord {\n if (line.startsWith(`${recordPrefix}clipboard:`)) {\n try {\n const record = JSON.parse(line.slice(`${recordPrefix}clipboard:`.length));\n if (isWebHostClipboardRecord(record)) {\n return { type: \"clipboard\", text: record.text };\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n if (line.startsWith(`${recordPrefix}runtimeIssue:`)) {\n try {\n const record = JSON.parse(line.slice(`${recordPrefix}runtimeIssue:`.length));\n if (isWebHostRuntimeIssue(record)) {\n return { type: \"runtimeIssue\", issue: record };\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n if (line.startsWith(`${recordPrefix}frameDiagnostic:`)) {\n try {\n const record = JSON.parse(line.slice(`${recordPrefix}frameDiagnostic:`.length));\n if (isWebHostFrameDiagnosticRecord(record)) {\n return { type: \"frameDiagnostic\", diagnostic: record };\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n if (!line.startsWith(`${recordPrefix}surface:`)) {\n return { type: \"text\", text: `${line}\\n` };\n }\n\n try {\n const frame = JSON.parse(line.slice(`${recordPrefix}surface:`.length));\n if (declaresNewerSurfaceVersion(frame)) {\n return {\n type: \"runtimeIssue\",\n issue: {\n severity: \"error\",\n code: \"surface.unsupportedVersion\",\n message: `SwiftTUI surface version ${frame.version} is newer than the supported ${SUPPORTED_SURFACE_VERSION}`,\n description: \"The app emitted a surface record with version \"\n + `${frame.version}, but this @swifttui/web runtime understands `\n + `versions up to ${SUPPORTED_SURFACE_VERSION}. Update @swifttui/web `\n + \"to render it.\",\n },\n };\n }\n if (isWebHostSurfaceFrame(frame)) {\n this.lastSurfaceFrame = frame;\n this.lastEpoch = frame.epoch;\n this.lastGen = frame.gen;\n this.pendingResyncRequest = undefined;\n this.keyframeResyncOutstanding = false;\n return { type: \"surface\", frame };\n }\n if (isWebHostSurfaceDeltaFrame(frame)) {\n const carriesDeliveryStamps = frame.epoch !== undefined\n || frame.gen !== undefined\n || frame.baselineGen !== undefined;\n if (\n !this.lastSurfaceFrame\n || this.lastSurfaceFrame.width !== frame.width\n || this.lastSurfaceFrame.height !== frame.height\n ) {\n if (carriesDeliveryStamps) {\n this.requestKeyframeResync();\n }\n return { type: \"surfaceDropped\", reason: \"noBaseline\" };\n }\n if (\n carriesDeliveryStamps\n && (\n frame.epoch === undefined\n || frame.gen === undefined\n || frame.baselineGen === undefined\n || frame.epoch !== this.lastEpoch\n || frame.baselineGen !== this.lastGen\n )\n ) {\n this.requestKeyframeResync();\n return { type: \"surfaceDropped\", reason: \"staleBaseline\" };\n }\n const materialized = this.materializeDeltaFrame(frame);\n if (materialized) {\n this.lastSurfaceFrame = materialized;\n this.lastEpoch = frame.epoch;\n this.lastGen = frame.gen;\n return { type: \"surface\", frame: materialized };\n }\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n private requestKeyframeResync(): void {\n if (this.keyframeResyncOutstanding) {\n return;\n }\n this.keyframeResyncOutstanding = true;\n this.pendingResyncRequest = { scope: \"keyframe\" };\n }\n\n private materializeDeltaFrame(\n frame: WebHostSurfaceDeltaFrame\n ): WebHostSurfaceFrame | undefined {\n const baseline = this.lastSurfaceFrame;\n if (!baseline) {\n return undefined;\n }\n\n const rows = baseline.rows.slice();\n for (const [row, cells] of frame.deltaRows) {\n if (!Number.isSafeInteger(row) || row < 0 || row >= frame.height) {\n return undefined;\n }\n rows[row] = cells;\n }\n\n return {\n version: baseline.version,\n epoch: frame.epoch,\n gen: frame.gen,\n sequence: frame.sequence,\n width: frame.width,\n height: frame.height,\n styles: frame.styles,\n rows,\n images: frame.images,\n damage: frame.damage,\n accessibilityTree: frame.accessibilityTree,\n accessibilityAnnouncements: frame.accessibilityAnnouncements,\n scrollRegions: frame.scrollRegions,\n links: frame.links,\n linkTargets: frame.linkTargets,\n focusPresentation: frame.focusPresentation,\n preferredGridWidth: frame.preferredGridWidth,\n preferredGridHeight: frame.preferredGridHeight,\n };\n }\n}\n\nfunction declaresNewerSurfaceVersion(\n value: unknown\n): value is { version: number } {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const version = (value as { version?: unknown }).version;\n return typeof version === \"number\"\n && Number.isSafeInteger(version)\n && version > SUPPORTED_SURFACE_VERSION;\n}\n\nfunction isWebHostClipboardRecord(\n value: unknown\n): value is { text: string } {\n return !!value && typeof value === \"object\" && typeof (value as { text?: unknown }).text === \"string\";\n}\n\nfunction isWebHostRuntimeIssue(\n value: unknown\n): value is WebHostRuntimeIssue {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const record = value as Partial<WebHostRuntimeIssue>;\n return (record.severity === \"warning\" || record.severity === \"error\")\n && typeof record.code === \"string\"\n && typeof record.message === \"string\"\n && typeof record.description === \"string\"\n && (record.identity === undefined || typeof record.identity === \"string\")\n && (record.source === undefined || typeof record.source === \"string\");\n}\n\nfunction isWebHostFrameDiagnosticRecord(\n value: unknown\n): value is WebHostFrameDiagnosticRecord {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const record = value as Partial<WebHostFrameDiagnosticRecord>;\n return record.format === \"swift-tui-frame-diagnostics-v1\"\n && Array.isArray(record.header)\n && record.header.every((field) => typeof field === \"string\")\n && Array.isArray(record.fields)\n && record.fields.every((field) => typeof field === \"string\");\n}\n\nexport function encodeResizeControlMessage(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n): Uint8Array {\n const normalizedColumns = Math.max(1, Math.round(columns));\n const normalizedRows = Math.max(1, Math.round(rows));\n if (cellWidth && cellHeight) {\n return textEncoder.encode(\n `${recordPrefix}resize:${normalizedColumns}:${normalizedRows}:${Math.max(1, Math.round(cellWidth))}:${Math.max(1, Math.round(cellHeight))}\\n`\n );\n }\n\n return textEncoder.encode(`${recordPrefix}resize:${normalizedColumns}:${normalizedRows}\\n`);\n}\n\nexport function encodeRenderStyleControlMessage(\n style: WebHostTerminalStyle\n): Uint8Array {\n const encoded = encodeWebHostTerminalRenderStyleBase64(style);\n return textEncoder.encode(`${recordPrefix}style:${encoded}\\n`);\n}\n\nexport function encodeCapabilitiesControlMessage(): Uint8Array {\n // The client's wire-capability declaration, sent once after the socket\n // opens. The declaration is truthful today: this decoder materializes v3\n // delta frames (`materializeDeltaFrame`). Byte shape and key order are\n // pinned by the cross-repo fixture Fixtures/Transport/web-caps-record.txt\n // — swift-tui's input parser consumes the identical bytes, and the\n // coordination root's transport_fixture_sync gate keeps the copies in\n // lockstep. Servers that predate the record drop it silently, so the\n // session degrades to today's full-frame defaults.\n //\n // Capabilities are named feature bits. The retired `maxWebSurfaceVersion`\n // key declared a decoder version ceiling, which was only ever read as\n // \"accepts delta or not\" and duplicated — more weakly — the version check\n // this decoder already performs on every record (SUPPORTED_SURFACE_VERSION).\n // Servers still expecting it skip unknown keys, so dropping it is safe in\n // both directions.\n return textEncoder.encode(\n `${recordPrefix}caps:{\"acceptsDeltaFrames\":true}\\n`\n );\n}\n\nexport function encodeResyncControlMessage(\n request: WebHostResyncRequest\n): Uint8Array {\n const payload = request.scope === \"keyframe\"\n ? { scope: \"keyframe\" }\n : {\n scope: \"images\",\n ...(request.ids === undefined ? {} : { ids: request.ids }),\n };\n return textEncoder.encode(\n `${recordPrefix}resync:${JSON.stringify(payload)}\\n`\n );\n}\n\nexport function encodeKeyInputMessage(\n input: WebHostKeyInput\n): Uint8Array {\n const modifiers = Math.max(0, Math.round(input.modifiers ?? 0));\n if (input.key === \"character\") {\n return textEncoder.encode(\n `${recordPrefix}key:character:${encodeURIComponent(input.character ?? \"\")}:${modifiers}\\n`\n );\n }\n return textEncoder.encode(`${recordPrefix}key:${input.key}:${modifiers}\\n`);\n}\n\nexport function encodePasteInputMessage(\n text: string\n): Uint8Array {\n return textEncoder.encode(`${recordPrefix}paste:${encodeURIComponent(text)}\\n`);\n}\n\nexport function encodeMouseInputMessage(\n input: WebHostMouseInput\n): Uint8Array {\n return textEncoder.encode(\n recordPrefix + [\n \"mouse\",\n input.kind,\n formatCellCoordinate(input.x),\n formatCellCoordinate(input.y),\n input.button ?? \"none\",\n Math.round(input.deltaX ?? 0),\n Math.round(input.deltaY ?? 0),\n Math.max(0, Math.round(input.modifiers ?? 0)),\n ].join(\":\") + \"\\n\"\n );\n}\n\nfunction formatCellCoordinate(\n value: number\n): string {\n return Number.isFinite(value) ? String(value) : \"0\";\n}\n\nfunction isWebHostSurfaceFrame(\n value: unknown\n): value is WebHostSurfaceFrame {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const frame = value as Partial<WebHostSurfaceFrame>;\n return (frame.version === 1 || frame.version === 2)\n && (\n frame.sequence === undefined\n || (Number.isSafeInteger(frame.sequence) && frame.sequence >= 0)\n )\n && typeof frame.width === \"number\"\n && typeof frame.height === \"number\"\n && Array.isArray(frame.styles)\n && Array.isArray(frame.rows)\n && frame.rows.every(isWebHostSurfaceRow)\n && (frame.images === undefined || isWebHostSurfaceImages(frame.images))\n && (frame.damage === undefined || isWebHostSurfaceDamage(frame.damage))\n && (\n frame.accessibilityTree === undefined\n || isWebHostAccessibilityNodes(frame.accessibilityTree)\n )\n && (\n frame.accessibilityAnnouncements === undefined\n || isWebHostAccessibilityAnnouncements(frame.accessibilityAnnouncements)\n )\n && (frame.scrollRegions === undefined || isWebHostScrollRegions(frame.scrollRegions))\n && hasValidAdditiveFrameFields(frame);\n}\n\nfunction isWebHostSurfaceDeltaFrame(\n value: unknown\n): value is WebHostSurfaceDeltaFrame {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const frame = value as Partial<WebHostSurfaceDeltaFrame>;\n return frame.version === 3\n && frame.encoding === \"delta\"\n && (\n frame.sequence === undefined\n || (Number.isSafeInteger(frame.sequence) && frame.sequence >= 0)\n )\n && typeof frame.width === \"number\"\n && typeof frame.height === \"number\"\n && Array.isArray(frame.styles)\n && Array.isArray(frame.deltaRows)\n && frame.deltaRows.every(isWebHostSurfaceDeltaRow)\n && isOptionalSafeInteger(frame.baselineGen)\n && (frame.images === undefined || isWebHostSurfaceImages(frame.images))\n && (frame.damage === undefined || isWebHostSurfaceDamage(frame.damage))\n && (\n frame.accessibilityTree === undefined\n || isWebHostAccessibilityNodes(frame.accessibilityTree)\n )\n && (\n frame.accessibilityAnnouncements === undefined\n || isWebHostAccessibilityAnnouncements(frame.accessibilityAnnouncements)\n )\n && (frame.scrollRegions === undefined || isWebHostScrollRegions(frame.scrollRegions))\n && hasValidAdditiveFrameFields(frame);\n}\n\n/**\n * The F19 additive fields shared by the full and delta record shapes. Absent\n * means \"feature not present\" — servers older than the field omit it.\n */\nfunction hasValidAdditiveFrameFields(\n frame: Partial<WebHostSurfaceFrame> | Partial<WebHostSurfaceDeltaFrame>\n): boolean {\n return isOptionalSafeInteger(frame.epoch)\n && isOptionalSafeInteger(frame.gen)\n && (frame.links === undefined || isWebHostSurfaceLinks(frame.links))\n && (frame.linkTargets === undefined || isWebHostSurfaceLinkTargets(frame.linkTargets))\n && (\n frame.focusPresentation === undefined\n || isWebHostFocusPresentation(frame.focusPresentation)\n )\n && (\n frame.preferredGridWidth === undefined\n || (Number.isSafeInteger(frame.preferredGridWidth) && frame.preferredGridWidth >= 0)\n )\n && (\n frame.preferredGridHeight === undefined\n || (Number.isSafeInteger(frame.preferredGridHeight) && frame.preferredGridHeight >= 0)\n );\n}\n\nfunction isOptionalSafeInteger(\n value: unknown\n): boolean {\n return value === undefined || Number.isSafeInteger(value);\n}\n\nfunction isWebHostSurfaceLinks(\n value: unknown\n): value is WebHostSurfaceLinkRow[] {\n return Array.isArray(value) && value.every(isWebHostSurfaceLinkRow);\n}\n\nfunction isWebHostSurfaceLinkRow(\n value: unknown\n): value is WebHostSurfaceLinkRow {\n return Array.isArray(value)\n && value.length === 2\n && Number.isSafeInteger(value[0])\n && value[0] >= 0\n && Array.isArray(value[1])\n && value[1].every(isWebHostSurfaceLinkRun);\n}\n\nfunction isWebHostSurfaceLinkRun(\n value: unknown\n): value is WebHostSurfaceLinkRun {\n if (!Array.isArray(value) || value.length !== 3) {\n return false;\n }\n const [x, span, targetIndex] = value as number[];\n return Number.isSafeInteger(x)\n && x >= 0\n && Number.isSafeInteger(span)\n && span >= 1\n && Number.isSafeInteger(targetIndex)\n && targetIndex >= 0;\n}\n\nfunction isWebHostSurfaceLinkTargets(\n value: unknown\n): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction isWebHostFocusPresentation(\n value: unknown\n): value is WebHostFocusPresentation {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const presentation = value as Partial<WebHostFocusPresentation>;\n return (\n presentation.focusedIdentity === undefined\n || typeof presentation.focusedIdentity === \"string\"\n )\n && typeof presentation.semantics === \"string\"\n && typeof presentation.prefersTextInput === \"boolean\"\n && typeof presentation.hasFocusedRegion === \"boolean\";\n}\n\nfunction isWebHostSurfaceDeltaRow(\n value: unknown\n): value is WebHostSurfaceDeltaRow {\n return Array.isArray(value)\n && value.length === 2\n && Number.isSafeInteger(value[0])\n && value[0] >= 0\n && isWebHostSurfaceRow(value[1]);\n}\n\nfunction isWebHostSurfaceRow(\n value: unknown\n): value is WebHostSurfaceCell[] {\n return Array.isArray(value) && value.every(isWebHostSurfaceCell);\n}\n\nfunction isWebHostSurfaceCell(\n value: unknown\n): value is WebHostSurfaceCell {\n return Array.isArray(value)\n && value.length === 4\n && Number.isSafeInteger(value[0])\n && value[0] >= 0\n && typeof value[1] === \"string\"\n && Number.isSafeInteger(value[2])\n && value[2] >= 1\n && Number.isSafeInteger(value[3])\n && value[3] >= 0;\n}\n\nfunction isWebHostAccessibilityNodes(\n value: unknown\n): value is WebHostAccessibilityNode[] {\n return Array.isArray(value) && value.every(isWebHostAccessibilityNode);\n}\n\nfunction isWebHostAccessibilityNode(\n value: unknown\n): value is WebHostAccessibilityNode {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const node = value as Partial<WebHostAccessibilityNode>;\n return typeof node.id === \"string\"\n && (node.parentId === undefined || typeof node.parentId === \"string\")\n && isWebHostSurfaceRect(node.rect)\n && typeof node.role === \"string\"\n && (node.label === undefined || typeof node.label === \"string\")\n && (node.hint === undefined || typeof node.hint === \"string\")\n && (node.hidden === undefined || typeof node.hidden === \"boolean\")\n && (node.liveRegion === undefined || typeof node.liveRegion === \"string\")\n && (node.cursorAnchor === undefined || isWebHostAccessibilityPoint(node.cursorAnchor))\n && (node.isFocused === undefined || typeof node.isFocused === \"boolean\");\n}\n\nfunction isWebHostAccessibilityPoint(\n value: unknown\n): value is WebHostAccessibilityPoint {\n return Array.isArray(value)\n && value.length === 2\n && value.every((entry) => typeof entry === \"number\");\n}\n\nfunction isWebHostAccessibilityAnnouncements(\n value: unknown\n): value is WebHostAccessibilityAnnouncement[] {\n return Array.isArray(value) && value.every(isWebHostAccessibilityAnnouncement);\n}\n\nfunction isWebHostAccessibilityAnnouncement(\n value: unknown\n): value is WebHostAccessibilityAnnouncement {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const announcement = value as Partial<WebHostAccessibilityAnnouncement>;\n return typeof announcement.message === \"string\"\n && typeof announcement.politeness === \"string\";\n}\n\nfunction isWebHostSurfaceImages(\n value: unknown\n): value is WebHostSurfaceImage[] {\n return Array.isArray(value) && value.every(isWebHostSurfaceImage);\n}\n\nfunction isWebHostSurfaceImage(\n value: unknown\n): value is WebHostSurfaceImage {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const image = value as Partial<WebHostSurfaceImage>;\n return typeof image.id === \"string\"\n && isWebHostSurfaceImageFormat(image.format)\n && isWebHostSurfaceRect(image.bounds)\n && isWebHostSurfaceRect(image.visibleBounds)\n && isWebHostSurfaceScalingMode(image.scalingMode)\n && (image.pixelSize === undefined || isWebHostSurfaceSize(image.pixelSize))\n && (image.dataBase64 === undefined || typeof image.dataBase64 === \"string\");\n}\n\nfunction isWebHostSurfaceDamage(\n value: unknown\n): value is WebHostSurfaceDamage {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const damage = value as Partial<WebHostSurfaceDamage>;\n return Array.isArray(damage.textRows)\n && damage.textRows.every(isWebHostSurfaceDamageTextRow)\n && typeof damage.requiresFullTextRepaint === \"boolean\"\n && typeof damage.requiresFullGraphicsReplay === \"boolean\";\n}\n\nfunction isWebHostSurfaceDamageTextRow(\n value: unknown\n): value is WebHostSurfaceDamageTextRow {\n return Array.isArray(value)\n && value.length === 2\n && typeof value[0] === \"number\"\n && Array.isArray(value[1])\n && value[1].every(isWebHostSurfaceDamageRange);\n}\n\nfunction isWebHostSurfaceDamageRange(\n value: unknown\n): value is WebHostSurfaceDamageRange {\n return Array.isArray(value)\n && value.length === 2\n && typeof value[0] === \"number\"\n && typeof value[1] === \"number\";\n}\n\nfunction isWebHostSurfaceImageFormat(\n value: unknown\n): value is WebHostSurfaceImageFormat {\n return typeof value === \"string\";\n}\n\nfunction isWebHostScrollRegions(\n value: unknown\n): value is WebHostScrollRegion[] {\n return Array.isArray(value) && value.every(isWebHostScrollRegion);\n}\n\nfunction isWebHostScrollRegion(\n value: unknown\n): value is WebHostScrollRegion {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const region = value as Partial<WebHostScrollRegion>;\n return typeof region.id === \"string\"\n && isWebHostSurfaceRect(region.rect)\n && isWebHostSurfaceSize(region.offset)\n && isWebHostSurfaceSize(region.content);\n}\n\nfunction isWebHostSurfaceRect(\n value: unknown\n): value is WebHostSurfaceRect {\n return Array.isArray(value)\n && value.length === 4\n && value.every((entry) => typeof entry === \"number\");\n}\n\nfunction isWebHostSurfaceSize(\n value: unknown\n): value is WebHostSurfaceSize {\n return Array.isArray(value)\n && value.length === 2\n && value.every((entry) => typeof entry === \"number\");\n}\n\nfunction isWebHostSurfaceScalingMode(\n value: unknown\n): value is WebHostSurfaceImage[\"scalingMode\"] {\n return typeof value === \"string\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WebHostSurfaceTransport.js","names":[],"sources":["../../src/WebHostSurfaceTransport.ts"],"sourcesContent":["/**\n * Browser consumer for SwiftTUI's host wire. The normative cross-host\n * contract lives upstream:\n * https://github.com/SwiftTUI/swift-tui/blob/main/docs/HOST-WIRE-CONTRACT.md\n */\nimport {\n encodeWebHostTerminalRenderStyleBase64,\n type WebHostTerminalStyle,\n} from \"./WebHostTerminalStyle.ts\";\n\nexport interface WebHostSurfaceStyle {\n fg?: string;\n bg?: string;\n em?: number;\n underline?: WebHostSurfaceLineStyle;\n strikethrough?: WebHostSurfaceLineStyle;\n opacity?: number;\n}\n\nexport interface WebHostSurfaceLineStyle {\n pattern: \"solid\" | \"dot\" | \"dash\" | \"dashDot\" | \"dashDotDot\" | \"double\" | \"curly\";\n color?: string;\n}\n\nexport type WebHostSurfaceCell = [\n x: number,\n text: string,\n span: number,\n styleIndex: number,\n];\n\nexport type WebHostSurfaceRect = [\n x: number,\n y: number,\n width: number,\n height: number,\n];\n\nexport type WebHostSurfaceSize = [\n width: number,\n height: number,\n];\n\nexport type WebHostAccessibilityPoint = [\n x: number,\n y: number,\n];\n\nexport type WebHostAccessibilityLiveRegion = string;\n\nexport interface WebHostAccessibilityNode {\n id: string;\n parentId?: string;\n rect: WebHostSurfaceRect;\n role: string;\n label?: string;\n hint?: string;\n /** omitted when false */\n hidden?: boolean;\n liveRegion?: WebHostAccessibilityLiveRegion;\n cursorAnchor?: WebHostAccessibilityPoint;\n isFocused?: boolean;\n}\n\n/**\n * One hyperlink run within a row: [x, spanWidth, linkTargetIndex]. The index\n * points into the frame's deduplicated `linkTargets` table.\n */\nexport type WebHostSurfaceLinkRun = [\n x: number,\n span: number,\n targetIndex: number,\n];\n\n/** Hyperlink runs for one row: [rowIndex, runs]. */\nexport type WebHostSurfaceLinkRow = [\n row: number,\n runs: WebHostSurfaceLinkRun[],\n];\n\nexport type WebHostFocusSemantics = string;\n\n/**\n * The settled focus presentation for a committed frame — the same derivation\n * the Android host consumes (`prefersTextInput` gates its IME).\n */\nexport interface WebHostFocusPresentation {\n focusedIdentity?: string;\n semantics: WebHostFocusSemantics;\n prefersTextInput: boolean;\n hasFocusedRegion: boolean;\n}\n\nexport interface WebHostAccessibilityAnnouncement {\n message: string;\n politeness: WebHostAccessibilityLiveRegion;\n}\n\nexport type WebHostSurfaceImageFormat = string;\n\n/**\n * Reports locally unresolved image IDs to a recovery-capable host. The first\n * branch lets bounded hosts return the admitted subset; the explicit legacy\n * void branch preserves contextual typing for concise callbacks that return\n * incidental values such as `array.push(...)`.\n */\nexport type WebHostImagePayloadRequestHandler =\n | ((ids: readonly string[]) => readonly string[])\n | ((ids: readonly string[]) => void);\n\nexport interface WebHostSurfaceImage {\n id: string;\n format: WebHostSurfaceImageFormat;\n bounds: WebHostSurfaceRect;\n visibleBounds: WebHostSurfaceRect;\n scalingMode: string;\n pixelSize?: WebHostSurfaceSize;\n dataBase64?: string;\n}\n\nexport type WebHostSurfaceDamageRange = [\n start: number,\n end: number,\n];\n\nexport type WebHostSurfaceDamageTextRow = [\n row: number,\n ranges: WebHostSurfaceDamageRange[],\n];\n\nexport interface WebHostSurfaceDamage {\n textRows: WebHostSurfaceDamageTextRow[];\n requiresFullTextRepaint: boolean;\n requiresFullGraphicsReplay: boolean;\n}\n\n/**\n * Per-region scroll extent published with each frame so the host can implement\n * scroll-chaining: capture the wheel only while the region under the pointer can\n * still scroll in the wheel's direction, otherwise let it fall through to the\n * page. The host recomputes the per-direction headroom from `offset`/`content`/\n * the viewport `rect`, mirroring SwiftTUI's\n * `min(max(0, offset), max(0, content - viewport))` clamp.\n */\nexport interface WebHostScrollRegion {\n /** identity path — same key space as accessibility node ids */\n id: string;\n /** viewport rect in cells: [x, y, width, height] */\n rect: WebHostSurfaceRect;\n /** current clamped scroll offset in cells: [x, y] */\n offset: WebHostAccessibilityPoint;\n /** total content size in cells: [width, height] */\n content: WebHostSurfaceSize;\n}\n\nexport interface WebHostSurfaceFrame {\n version: 1 | 2;\n epoch?: number;\n gen?: number;\n sequence?: number;\n width: number;\n height: number;\n styles: Array<WebHostSurfaceStyle | null>;\n rows: WebHostSurfaceCell[][];\n images?: WebHostSurfaceImage[];\n damage?: WebHostSurfaceDamage;\n accessibilityTree?: WebHostAccessibilityNode[];\n accessibilityAnnouncements?: WebHostAccessibilityAnnouncement[];\n scrollRegions?: WebHostScrollRegion[];\n links?: WebHostSurfaceLinkRow[];\n linkTargets?: string[];\n focusPresentation?: WebHostFocusPresentation;\n preferredGridWidth?: number;\n preferredGridHeight?: number;\n}\n\nexport type WebHostSurfaceDeltaRow = [\n row: number,\n cells: WebHostSurfaceCell[],\n];\n\nexport interface WebHostSurfaceDeltaFrame {\n version: 3;\n encoding: \"delta\";\n epoch?: number;\n gen?: number;\n baselineGen?: number;\n sequence?: number;\n width: number;\n height: number;\n styles: Array<WebHostSurfaceStyle | null>;\n deltaRows: WebHostSurfaceDeltaRow[];\n images?: WebHostSurfaceImage[];\n damage?: WebHostSurfaceDamage;\n accessibilityTree?: WebHostAccessibilityNode[];\n accessibilityAnnouncements?: WebHostAccessibilityAnnouncement[];\n scrollRegions?: WebHostScrollRegion[];\n links?: WebHostSurfaceLinkRow[];\n linkTargets?: string[];\n focusPresentation?: WebHostFocusPresentation;\n preferredGridWidth?: number;\n preferredGridHeight?: number;\n}\n\nexport interface WebHostRuntimeIssue {\n severity: \"warning\" | \"error\";\n code: string;\n message: string;\n description: string;\n identity?: string;\n source?: string;\n}\n\nexport interface WebHostFrameDiagnosticRecord {\n format: \"swift-tui-frame-diagnostics-v1\";\n header: string[];\n fields: string[];\n}\n\nexport type WebHostOutputRecord =\n | { type: \"surface\"; frame: WebHostSurfaceFrame }\n | { type: \"clipboard\"; text: string }\n | { type: \"runtimeIssue\"; issue: WebHostRuntimeIssue }\n | { type: \"frameDiagnostic\"; diagnostic: WebHostFrameDiagnosticRecord }\n | { type: \"surfaceDropped\"; reason: \"noBaseline\" | \"staleBaseline\" }\n | { type: \"text\"; text: string };\n\nexport type WebHostResyncRequest =\n | { scope: \"keyframe\" }\n | { scope: \"images\"; ids?: string[] };\n\nexport interface WebHostOutputSink {\n presentSurface(\n frame: WebHostSurfaceFrame,\n recoveredImagePayloadIds?: readonly string[]\n ): void;\n writeClipboard?(text: string): void | Promise<void>;\n notifyRuntimeIssue?(issue: WebHostRuntimeIssue): void;\n recordFrameDiagnostic?(diagnostic: WebHostFrameDiagnosticRecord): void;\n writeOutput?(text: string): void;\n writeError?(text: string): void;\n}\n\nexport interface WebHostKeyInput {\n key:\n | \"return\"\n | \"space\"\n | \"tab\"\n | \"arrowLeft\"\n | \"arrowRight\"\n | \"arrowUp\"\n | \"arrowDown\"\n | \"backspace\"\n | \"escape\"\n | \"home\"\n | \"end\"\n | \"character\";\n character?: string;\n modifiers?: number;\n}\n\nexport interface WebHostMouseInput {\n kind: \"down\" | \"up\" | \"moved\" | \"dragged\" | \"scrolled\";\n x: number;\n y: number;\n button?: \"primary\" | \"middle\" | \"secondary\";\n deltaX?: number;\n deltaY?: number;\n modifiers?: number;\n}\n\nconst recordPrefix = \"\\u001E\";\nconst textEncoder = new TextEncoder();\n\n/** Limits wire-derived recovery state and keeps every single-ID WASI request bounded. */\nexport const MAX_IMAGE_RECOVERY_ID_BYTES = 1_024;\nexport const MAX_OUTSTANDING_IMAGE_RECOVERY_IDS = 1_024;\n\nexport function isWebHostImageRecoveryId(\n id: string\n): boolean {\n return id.length > 0\n && id.length <= MAX_IMAGE_RECOVERY_ID_BYTES\n && textEncoder.encode(id).byteLength <= MAX_IMAGE_RECOVERY_ID_BYTES;\n}\n\n/**\n * The newest `surface` record version this runtime understands. Unknown\n * additive object keys are ignored by design (older runtimes render newer\n * frames), but a frame declaring a NEWER version than this is surfaced as an\n * error-severity runtime issue instead of silently degrading to a text\n * diagnostic — silent version skew is the failure mode this guards against\n * (F57).\n */\nexport const SUPPORTED_SURFACE_VERSION = 3;\n\nexport class WebHostOutputDecoder {\n private readonly textDecoder = new TextDecoder();\n private bufferedText = \"\";\n private lastSurfaceFrame?: WebHostSurfaceFrame;\n private lastEpoch?: number;\n private lastGen?: number;\n private lastPresentedEpoch?: number;\n private keyframeResyncOutstanding = false;\n private keyframeResyncPending = false;\n private readonly imageResyncOutstandingIds = new Set<string>();\n private readonly imageResyncPendingIds = new Set<string>();\n\n feed(\n chunk: Uint8Array\n ): WebHostOutputRecord[] {\n this.bufferedText += this.textDecoder.decode(chunk, { stream: true });\n const records: WebHostOutputRecord[] = [];\n\n while (true) {\n const newlineIndex = this.bufferedText.indexOf(\"\\n\");\n if (newlineIndex < 0) {\n break;\n }\n\n const line = this.bufferedText.slice(0, newlineIndex);\n this.bufferedText = this.bufferedText.slice(newlineIndex + 1);\n records.push(this.decodeLine(line));\n }\n\n if (this.bufferedText.length > 4096 && !this.bufferedText.startsWith(recordPrefix)) {\n records.push({ type: \"text\", text: this.bufferedText });\n this.bufferedText = \"\";\n }\n\n return records;\n }\n\n flush(): WebHostOutputRecord[] {\n if (!this.bufferedText) {\n return [];\n }\n const text = this.bufferedText;\n this.bufferedText = \"\";\n return [this.decodeLine(text)];\n }\n\n takeResyncRequest(\n maximumEncodedBytes?: number\n ): WebHostResyncRequest | undefined {\n if (this.keyframeResyncPending) {\n this.keyframeResyncPending = false;\n return { scope: \"keyframe\" };\n }\n if (this.imageResyncPendingIds.size === 0) {\n return undefined;\n }\n\n const sortedIds = [...this.imageResyncPendingIds].sort();\n const { ids, rejectedIds } = boundedImageResyncIds(\n sortedIds,\n maximumEncodedBytes\n );\n for (const id of rejectedIds) {\n this.imageResyncPendingIds.delete(id);\n this.imageResyncOutstandingIds.delete(id);\n }\n for (const id of ids) {\n this.imageResyncPendingIds.delete(id);\n }\n if (ids.length === 0) {\n return undefined;\n }\n return { scope: \"images\", ids };\n }\n\n /**\n * Adds locally unresolved image IDs to this epoch's recovery set. IDs remain\n * outstanding after delivery, so repeat painter misses cannot create storms;\n * a payload-bearing record or epoch re-anchor releases them. Returns the IDs\n * now tracked (new or already outstanding); callers should suppress repeats\n * only for this admitted subset.\n */\n requestImagePayloads(\n ids: Iterable<string>\n ): readonly string[] {\n const acceptedIds = new Set<string>();\n for (const id of ids) {\n if (!isWebHostImageRecoveryId(id)) {\n continue;\n }\n if (this.imageResyncOutstandingIds.has(id)) {\n acceptedIds.add(id);\n continue;\n }\n if (\n this.imageResyncOutstandingIds.size\n >= MAX_OUTSTANDING_IMAGE_RECOVERY_IDS\n ) {\n continue;\n }\n this.imageResyncOutstandingIds.add(id);\n this.imageResyncPendingIds.add(id);\n acceptedIds.add(id);\n }\n return [...acceptedIds];\n }\n\n /**\n * Advances image recovery immediately before one decoded surface reaches its\n * presenter. Payload arrival and epoch reset therefore follow delivery order\n * rather than `feed`'s parse-ahead order across a multi-record chunk. The\n * return value identifies payloads that answer an outstanding image request,\n * so presenters can open exactly one fresh local decode generation even when\n * content-addressed retransmission uses identical bytes.\n */\n prepareToPresentSurface(\n frame: WebHostSurfaceFrame\n ): readonly string[] {\n const recoveredImagePayloadIds = this.recoveredImagePayloadIds(frame.images);\n this.resetImageResyncForEpoch(frame.epoch);\n this.sweepImageResyncForPresentedImages(frame.images);\n this.clearArrivedImagePayloads(frame.images);\n if (frame.epoch !== undefined) {\n this.lastPresentedEpoch = frame.epoch;\n }\n return recoveredImagePayloadIds;\n }\n\n resyncRequestDeliveryFailed(\n request: WebHostResyncRequest\n ): void {\n if (request.scope === \"keyframe\") {\n if (this.keyframeResyncOutstanding) {\n this.keyframeResyncPending = true;\n }\n return;\n }\n\n for (const id of request.ids ?? []) {\n if (this.imageResyncOutstandingIds.has(id)) {\n this.imageResyncPendingIds.add(id);\n }\n }\n }\n\n private decodeLine(\n line: string\n ): WebHostOutputRecord {\n if (line.startsWith(`${recordPrefix}clipboard:`)) {\n try {\n const record = JSON.parse(line.slice(`${recordPrefix}clipboard:`.length));\n if (isWebHostClipboardRecord(record)) {\n return { type: \"clipboard\", text: record.text };\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n if (line.startsWith(`${recordPrefix}runtimeIssue:`)) {\n try {\n const record = JSON.parse(line.slice(`${recordPrefix}runtimeIssue:`.length));\n if (isWebHostRuntimeIssue(record)) {\n return { type: \"runtimeIssue\", issue: record };\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n if (line.startsWith(`${recordPrefix}frameDiagnostic:`)) {\n try {\n const record = JSON.parse(line.slice(`${recordPrefix}frameDiagnostic:`.length));\n if (isWebHostFrameDiagnosticRecord(record)) {\n return { type: \"frameDiagnostic\", diagnostic: record };\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n if (!line.startsWith(`${recordPrefix}surface:`)) {\n return { type: \"text\", text: `${line}\\n` };\n }\n\n try {\n const frame = JSON.parse(line.slice(`${recordPrefix}surface:`.length));\n if (declaresNewerSurfaceVersion(frame)) {\n return {\n type: \"runtimeIssue\",\n issue: {\n severity: \"error\",\n code: \"surface.unsupportedVersion\",\n message: `SwiftTUI surface version ${frame.version} is newer than the supported ${SUPPORTED_SURFACE_VERSION}`,\n description: \"The app emitted a surface record with version \"\n + `${frame.version}, but this @swifttui/web runtime understands `\n + `versions up to ${SUPPORTED_SURFACE_VERSION}. Update @swifttui/web `\n + \"to render it.\",\n },\n };\n }\n if (isWebHostSurfaceFrame(frame)) {\n this.lastSurfaceFrame = frame;\n this.lastEpoch = frame.epoch;\n this.lastGen = frame.gen;\n this.keyframeResyncOutstanding = false;\n this.keyframeResyncPending = false;\n return { type: \"surface\", frame };\n }\n if (isWebHostSurfaceDeltaFrame(frame)) {\n const carriesDeliveryStamps = frame.epoch !== undefined\n || frame.gen !== undefined\n || frame.baselineGen !== undefined;\n if (\n !this.lastSurfaceFrame\n || this.lastSurfaceFrame.width !== frame.width\n || this.lastSurfaceFrame.height !== frame.height\n ) {\n if (carriesDeliveryStamps) {\n this.requestKeyframeResync();\n }\n return { type: \"surfaceDropped\", reason: \"noBaseline\" };\n }\n if (\n carriesDeliveryStamps\n && (\n frame.epoch === undefined\n || frame.gen === undefined\n || frame.baselineGen === undefined\n || frame.epoch !== this.lastEpoch\n || frame.baselineGen !== this.lastGen\n )\n ) {\n this.requestKeyframeResync();\n return { type: \"surfaceDropped\", reason: \"staleBaseline\" };\n }\n const materialized = this.materializeDeltaFrame(frame);\n if (materialized) {\n this.lastSurfaceFrame = materialized;\n this.lastEpoch = frame.epoch;\n this.lastGen = frame.gen;\n return { type: \"surface\", frame: materialized };\n }\n }\n } catch {\n // Fall through to the text path below so malformed output remains visible.\n }\n\n return { type: \"text\", text: `${line}\\n` };\n }\n\n private requestKeyframeResync(): void {\n if (this.keyframeResyncOutstanding) {\n return;\n }\n this.keyframeResyncOutstanding = true;\n this.keyframeResyncPending = true;\n }\n\n private resetImageResyncForEpoch(\n epoch: number | undefined\n ): void {\n if (epoch === undefined || epoch === this.lastPresentedEpoch) {\n return;\n }\n this.imageResyncOutstandingIds.clear();\n this.imageResyncPendingIds.clear();\n }\n\n private clearArrivedImagePayloads(\n images: WebHostSurfaceImage[] | undefined\n ): void {\n for (const image of images ?? []) {\n if (image.dataBase64 === undefined) {\n continue;\n }\n this.imageResyncOutstandingIds.delete(image.id);\n this.imageResyncPendingIds.delete(image.id);\n }\n }\n\n private recoveredImagePayloadIds(\n images: WebHostSurfaceImage[] | undefined\n ): string[] {\n const recoveredIds = new Set<string>();\n for (const image of images ?? []) {\n if (\n image.dataBase64 !== undefined\n && this.imageResyncOutstandingIds.has(image.id)\n ) {\n recoveredIds.add(image.id);\n }\n }\n return [...recoveredIds].sort();\n }\n\n private sweepImageResyncForPresentedImages(\n images: WebHostSurfaceImage[] | undefined\n ): void {\n const presentedIds = new Set<string>();\n for (const image of images ?? []) {\n if (this.imageResyncOutstandingIds.has(image.id)) {\n presentedIds.add(image.id);\n }\n }\n for (const id of this.imageResyncOutstandingIds) {\n if (presentedIds.has(id)) {\n continue;\n }\n this.imageResyncOutstandingIds.delete(id);\n this.imageResyncPendingIds.delete(id);\n }\n }\n\n private materializeDeltaFrame(\n frame: WebHostSurfaceDeltaFrame\n ): WebHostSurfaceFrame | undefined {\n const baseline = this.lastSurfaceFrame;\n if (!baseline) {\n return undefined;\n }\n\n const rows = baseline.rows.slice();\n for (const [row, cells] of frame.deltaRows) {\n if (!Number.isSafeInteger(row) || row < 0 || row >= frame.height) {\n return undefined;\n }\n rows[row] = cells;\n }\n\n return {\n version: baseline.version,\n epoch: frame.epoch,\n gen: frame.gen,\n sequence: frame.sequence,\n width: frame.width,\n height: frame.height,\n styles: frame.styles,\n rows,\n images: frame.images,\n damage: frame.damage,\n accessibilityTree: frame.accessibilityTree,\n accessibilityAnnouncements: frame.accessibilityAnnouncements,\n scrollRegions: frame.scrollRegions,\n links: frame.links,\n linkTargets: frame.linkTargets,\n focusPresentation: frame.focusPresentation,\n preferredGridWidth: frame.preferredGridWidth,\n preferredGridHeight: frame.preferredGridHeight,\n };\n }\n}\n\nfunction boundedImageResyncIds(\n sortedIds: string[],\n maximumEncodedBytes: number | undefined\n): {\n ids: string[];\n rejectedIds: string[];\n} {\n if (\n maximumEncodedBytes === undefined\n || !Number.isFinite(maximumEncodedBytes)\n ) {\n return { ids: sortedIds, rejectedIds: [] };\n }\n\n const emptyRequestBytes = encodeResyncControlMessage({\n scope: \"images\",\n ids: [],\n }).byteLength;\n const normalizedMaximum = Math.max(0, Math.floor(maximumEncodedBytes));\n const ids: string[] = [];\n const rejectedIds: string[] = [];\n let encodedBytes = emptyRequestBytes;\n for (const id of sortedIds) {\n const separatorBytes = ids.length === 0 ? 0 : 1;\n const idBytes = textEncoder.encode(JSON.stringify(id)).byteLength;\n if (encodedBytes + separatorBytes + idBytes > normalizedMaximum) {\n if (ids.length === 0) {\n rejectedIds.push(id);\n continue;\n }\n break;\n }\n ids.push(id);\n encodedBytes += separatorBytes + idBytes;\n if (encodedBytes >= normalizedMaximum) {\n break;\n }\n }\n return { ids, rejectedIds };\n}\n\nfunction declaresNewerSurfaceVersion(\n value: unknown\n): value is { version: number } {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const version = (value as { version?: unknown }).version;\n return typeof version === \"number\"\n && Number.isSafeInteger(version)\n && version > SUPPORTED_SURFACE_VERSION;\n}\n\nfunction isWebHostClipboardRecord(\n value: unknown\n): value is { text: string } {\n return !!value && typeof value === \"object\" && typeof (value as { text?: unknown }).text === \"string\";\n}\n\nfunction isWebHostRuntimeIssue(\n value: unknown\n): value is WebHostRuntimeIssue {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const record = value as Partial<WebHostRuntimeIssue>;\n return (record.severity === \"warning\" || record.severity === \"error\")\n && typeof record.code === \"string\"\n && typeof record.message === \"string\"\n && typeof record.description === \"string\"\n && (record.identity === undefined || typeof record.identity === \"string\")\n && (record.source === undefined || typeof record.source === \"string\");\n}\n\nfunction isWebHostFrameDiagnosticRecord(\n value: unknown\n): value is WebHostFrameDiagnosticRecord {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const record = value as Partial<WebHostFrameDiagnosticRecord>;\n return record.format === \"swift-tui-frame-diagnostics-v1\"\n && Array.isArray(record.header)\n && record.header.every((field) => typeof field === \"string\")\n && Array.isArray(record.fields)\n && record.fields.every((field) => typeof field === \"string\");\n}\n\nexport function encodeResizeControlMessage(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n): Uint8Array {\n const normalizedColumns = Math.max(1, Math.round(columns));\n const normalizedRows = Math.max(1, Math.round(rows));\n if (cellWidth && cellHeight) {\n return textEncoder.encode(\n `${recordPrefix}resize:${normalizedColumns}:${normalizedRows}:${Math.max(1, Math.round(cellWidth))}:${Math.max(1, Math.round(cellHeight))}\\n`\n );\n }\n\n return textEncoder.encode(`${recordPrefix}resize:${normalizedColumns}:${normalizedRows}\\n`);\n}\n\nexport function encodeRenderStyleControlMessage(\n style: WebHostTerminalStyle\n): Uint8Array {\n const encoded = encodeWebHostTerminalRenderStyleBase64(style);\n return textEncoder.encode(`${recordPrefix}style:${encoded}\\n`);\n}\n\nexport function encodeCapabilitiesControlMessage(): Uint8Array {\n // The client's wire-capability declaration, sent once after the socket\n // opens. The declaration is truthful today: this decoder materializes v3\n // delta frames (`materializeDeltaFrame`). Byte shape and key order are\n // pinned by the cross-repo fixture Fixtures/Transport/web-caps-record.txt\n // — swift-tui's input parser consumes the identical bytes, and the\n // coordination root's transport_fixture_sync gate keeps the copies in\n // lockstep. Servers that predate the record drop it silently, so the\n // session degrades to today's full-frame defaults.\n //\n // Capabilities are named feature bits. The retired `maxWebSurfaceVersion`\n // key declared a decoder version ceiling, which was only ever read as\n // \"accepts delta or not\" and duplicated — more weakly — the version check\n // this decoder already performs on every record (SUPPORTED_SURFACE_VERSION).\n // Servers still expecting it skip unknown keys, so dropping it is safe in\n // both directions.\n return textEncoder.encode(\n `${recordPrefix}caps:{\"acceptsDeltaFrames\":true}\\n`\n );\n}\n\nexport function encodeResyncControlMessage(\n request: WebHostResyncRequest\n): Uint8Array {\n const payload = request.scope === \"keyframe\"\n ? { scope: \"keyframe\" }\n : {\n scope: \"images\",\n ...(request.ids === undefined ? {} : { ids: request.ids }),\n };\n return textEncoder.encode(\n `${recordPrefix}resync:${JSON.stringify(payload)}\\n`\n );\n}\n\nexport function encodeKeyInputMessage(\n input: WebHostKeyInput\n): Uint8Array {\n const modifiers = Math.max(0, Math.round(input.modifiers ?? 0));\n if (input.key === \"character\") {\n return textEncoder.encode(\n `${recordPrefix}key:character:${encodeURIComponent(input.character ?? \"\")}:${modifiers}\\n`\n );\n }\n return textEncoder.encode(`${recordPrefix}key:${input.key}:${modifiers}\\n`);\n}\n\nexport function encodePasteInputMessage(\n text: string\n): Uint8Array {\n return textEncoder.encode(`${recordPrefix}paste:${encodeURIComponent(text)}\\n`);\n}\n\nexport function encodeMouseInputMessage(\n input: WebHostMouseInput\n): Uint8Array {\n return textEncoder.encode(\n recordPrefix + [\n \"mouse\",\n input.kind,\n formatCellCoordinate(input.x),\n formatCellCoordinate(input.y),\n input.button ?? \"none\",\n Math.round(input.deltaX ?? 0),\n Math.round(input.deltaY ?? 0),\n Math.max(0, Math.round(input.modifiers ?? 0)),\n ].join(\":\") + \"\\n\"\n );\n}\n\nfunction formatCellCoordinate(\n value: number\n): string {\n return Number.isFinite(value) ? String(value) : \"0\";\n}\n\nfunction isWebHostSurfaceFrame(\n value: unknown\n): value is WebHostSurfaceFrame {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const frame = value as Partial<WebHostSurfaceFrame>;\n return (frame.version === 1 || frame.version === 2)\n && (\n frame.sequence === undefined\n || (Number.isSafeInteger(frame.sequence) && frame.sequence >= 0)\n )\n && typeof frame.width === \"number\"\n && typeof frame.height === \"number\"\n && Array.isArray(frame.styles)\n && Array.isArray(frame.rows)\n && frame.rows.every(isWebHostSurfaceRow)\n && (frame.images === undefined || isWebHostSurfaceImages(frame.images))\n && (frame.damage === undefined || isWebHostSurfaceDamage(frame.damage))\n && (\n frame.accessibilityTree === undefined\n || isWebHostAccessibilityNodes(frame.accessibilityTree)\n )\n && (\n frame.accessibilityAnnouncements === undefined\n || isWebHostAccessibilityAnnouncements(frame.accessibilityAnnouncements)\n )\n && (frame.scrollRegions === undefined || isWebHostScrollRegions(frame.scrollRegions))\n && hasValidAdditiveFrameFields(frame);\n}\n\nfunction isWebHostSurfaceDeltaFrame(\n value: unknown\n): value is WebHostSurfaceDeltaFrame {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const frame = value as Partial<WebHostSurfaceDeltaFrame>;\n return frame.version === 3\n && frame.encoding === \"delta\"\n && (\n frame.sequence === undefined\n || (Number.isSafeInteger(frame.sequence) && frame.sequence >= 0)\n )\n && typeof frame.width === \"number\"\n && typeof frame.height === \"number\"\n && Array.isArray(frame.styles)\n && Array.isArray(frame.deltaRows)\n && frame.deltaRows.every(isWebHostSurfaceDeltaRow)\n && isOptionalSafeInteger(frame.baselineGen)\n && (frame.images === undefined || isWebHostSurfaceImages(frame.images))\n && (frame.damage === undefined || isWebHostSurfaceDamage(frame.damage))\n && (\n frame.accessibilityTree === undefined\n || isWebHostAccessibilityNodes(frame.accessibilityTree)\n )\n && (\n frame.accessibilityAnnouncements === undefined\n || isWebHostAccessibilityAnnouncements(frame.accessibilityAnnouncements)\n )\n && (frame.scrollRegions === undefined || isWebHostScrollRegions(frame.scrollRegions))\n && hasValidAdditiveFrameFields(frame);\n}\n\n/**\n * The F19 additive fields shared by the full and delta record shapes. Absent\n * means \"feature not present\" — servers older than the field omit it.\n */\nfunction hasValidAdditiveFrameFields(\n frame: Partial<WebHostSurfaceFrame> | Partial<WebHostSurfaceDeltaFrame>\n): boolean {\n return isOptionalSafeInteger(frame.epoch)\n && isOptionalSafeInteger(frame.gen)\n && (frame.links === undefined || isWebHostSurfaceLinks(frame.links))\n && (frame.linkTargets === undefined || isWebHostSurfaceLinkTargets(frame.linkTargets))\n && (\n frame.focusPresentation === undefined\n || isWebHostFocusPresentation(frame.focusPresentation)\n )\n && (\n frame.preferredGridWidth === undefined\n || (Number.isSafeInteger(frame.preferredGridWidth) && frame.preferredGridWidth >= 0)\n )\n && (\n frame.preferredGridHeight === undefined\n || (Number.isSafeInteger(frame.preferredGridHeight) && frame.preferredGridHeight >= 0)\n );\n}\n\nfunction isOptionalSafeInteger(\n value: unknown\n): boolean {\n return value === undefined || Number.isSafeInteger(value);\n}\n\nfunction isWebHostSurfaceLinks(\n value: unknown\n): value is WebHostSurfaceLinkRow[] {\n return Array.isArray(value) && value.every(isWebHostSurfaceLinkRow);\n}\n\nfunction isWebHostSurfaceLinkRow(\n value: unknown\n): value is WebHostSurfaceLinkRow {\n return Array.isArray(value)\n && value.length === 2\n && Number.isSafeInteger(value[0])\n && value[0] >= 0\n && Array.isArray(value[1])\n && value[1].every(isWebHostSurfaceLinkRun);\n}\n\nfunction isWebHostSurfaceLinkRun(\n value: unknown\n): value is WebHostSurfaceLinkRun {\n if (!Array.isArray(value) || value.length !== 3) {\n return false;\n }\n const [x, span, targetIndex] = value as number[];\n return Number.isSafeInteger(x)\n && x >= 0\n && Number.isSafeInteger(span)\n && span >= 1\n && Number.isSafeInteger(targetIndex)\n && targetIndex >= 0;\n}\n\nfunction isWebHostSurfaceLinkTargets(\n value: unknown\n): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction isWebHostFocusPresentation(\n value: unknown\n): value is WebHostFocusPresentation {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const presentation = value as Partial<WebHostFocusPresentation>;\n return (\n presentation.focusedIdentity === undefined\n || typeof presentation.focusedIdentity === \"string\"\n )\n && typeof presentation.semantics === \"string\"\n && typeof presentation.prefersTextInput === \"boolean\"\n && typeof presentation.hasFocusedRegion === \"boolean\";\n}\n\nfunction isWebHostSurfaceDeltaRow(\n value: unknown\n): value is WebHostSurfaceDeltaRow {\n return Array.isArray(value)\n && value.length === 2\n && Number.isSafeInteger(value[0])\n && value[0] >= 0\n && isWebHostSurfaceRow(value[1]);\n}\n\nfunction isWebHostSurfaceRow(\n value: unknown\n): value is WebHostSurfaceCell[] {\n return Array.isArray(value) && value.every(isWebHostSurfaceCell);\n}\n\nfunction isWebHostSurfaceCell(\n value: unknown\n): value is WebHostSurfaceCell {\n return Array.isArray(value)\n && value.length === 4\n && Number.isSafeInteger(value[0])\n && value[0] >= 0\n && typeof value[1] === \"string\"\n && Number.isSafeInteger(value[2])\n && value[2] >= 1\n && Number.isSafeInteger(value[3])\n && value[3] >= 0;\n}\n\nfunction isWebHostAccessibilityNodes(\n value: unknown\n): value is WebHostAccessibilityNode[] {\n return Array.isArray(value) && value.every(isWebHostAccessibilityNode);\n}\n\nfunction isWebHostAccessibilityNode(\n value: unknown\n): value is WebHostAccessibilityNode {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const node = value as Partial<WebHostAccessibilityNode>;\n return typeof node.id === \"string\"\n && (node.parentId === undefined || typeof node.parentId === \"string\")\n && isWebHostSurfaceRect(node.rect)\n && typeof node.role === \"string\"\n && (node.label === undefined || typeof node.label === \"string\")\n && (node.hint === undefined || typeof node.hint === \"string\")\n && (node.hidden === undefined || typeof node.hidden === \"boolean\")\n && (node.liveRegion === undefined || typeof node.liveRegion === \"string\")\n && (node.cursorAnchor === undefined || isWebHostAccessibilityPoint(node.cursorAnchor))\n && (node.isFocused === undefined || typeof node.isFocused === \"boolean\");\n}\n\nfunction isWebHostAccessibilityPoint(\n value: unknown\n): value is WebHostAccessibilityPoint {\n return Array.isArray(value)\n && value.length === 2\n && value.every((entry) => typeof entry === \"number\");\n}\n\nfunction isWebHostAccessibilityAnnouncements(\n value: unknown\n): value is WebHostAccessibilityAnnouncement[] {\n return Array.isArray(value) && value.every(isWebHostAccessibilityAnnouncement);\n}\n\nfunction isWebHostAccessibilityAnnouncement(\n value: unknown\n): value is WebHostAccessibilityAnnouncement {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const announcement = value as Partial<WebHostAccessibilityAnnouncement>;\n return typeof announcement.message === \"string\"\n && typeof announcement.politeness === \"string\";\n}\n\nfunction isWebHostSurfaceImages(\n value: unknown\n): value is WebHostSurfaceImage[] {\n return Array.isArray(value) && value.every(isWebHostSurfaceImage);\n}\n\nfunction isWebHostSurfaceImage(\n value: unknown\n): value is WebHostSurfaceImage {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const image = value as Partial<WebHostSurfaceImage>;\n return typeof image.id === \"string\"\n && isWebHostSurfaceImageFormat(image.format)\n && isWebHostSurfaceRect(image.bounds)\n && isWebHostSurfaceRect(image.visibleBounds)\n && isWebHostSurfaceScalingMode(image.scalingMode)\n && (image.pixelSize === undefined || isWebHostSurfaceSize(image.pixelSize))\n && (image.dataBase64 === undefined || typeof image.dataBase64 === \"string\");\n}\n\nfunction isWebHostSurfaceDamage(\n value: unknown\n): value is WebHostSurfaceDamage {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const damage = value as Partial<WebHostSurfaceDamage>;\n return Array.isArray(damage.textRows)\n && damage.textRows.every(isWebHostSurfaceDamageTextRow)\n && typeof damage.requiresFullTextRepaint === \"boolean\"\n && typeof damage.requiresFullGraphicsReplay === \"boolean\";\n}\n\nfunction isWebHostSurfaceDamageTextRow(\n value: unknown\n): value is WebHostSurfaceDamageTextRow {\n return Array.isArray(value)\n && value.length === 2\n && typeof value[0] === \"number\"\n && Array.isArray(value[1])\n && value[1].every(isWebHostSurfaceDamageRange);\n}\n\nfunction isWebHostSurfaceDamageRange(\n value: unknown\n): value is WebHostSurfaceDamageRange {\n return Array.isArray(value)\n && value.length === 2\n && typeof value[0] === \"number\"\n && typeof value[1] === \"number\";\n}\n\nfunction isWebHostSurfaceImageFormat(\n value: unknown\n): value is WebHostSurfaceImageFormat {\n return typeof value === \"string\";\n}\n\nfunction isWebHostScrollRegions(\n value: unknown\n): value is WebHostScrollRegion[] {\n return Array.isArray(value) && value.every(isWebHostScrollRegion);\n}\n\nfunction isWebHostScrollRegion(\n value: unknown\n): value is WebHostScrollRegion {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n const region = value as Partial<WebHostScrollRegion>;\n return typeof region.id === \"string\"\n && isWebHostSurfaceRect(region.rect)\n && isWebHostSurfaceSize(region.offset)\n && isWebHostSurfaceSize(region.content);\n}\n\nfunction isWebHostSurfaceRect(\n value: unknown\n): value is WebHostSurfaceRect {\n return Array.isArray(value)\n && value.length === 4\n && value.every((entry) => typeof entry === \"number\");\n}\n\nfunction isWebHostSurfaceSize(\n value: unknown\n): value is WebHostSurfaceSize {\n return Array.isArray(value)\n && value.length === 2\n && value.every((entry) => typeof entry === \"number\");\n}\n\nfunction isWebHostSurfaceScalingMode(\n value: unknown\n): value is WebHostSurfaceImage[\"scalingMode\"] {\n return typeof value === \"string\";\n}\n"],"mappings":"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"}
@@ -41,11 +41,12 @@ declare class WebSocketSceneBridge implements WebHostSceneBridge {
41
41
  resize(columns: number, rows: number, cellWidth?: number, cellHeight?: number): void;
42
42
  updateRenderStyle(style: WebHostTerminalStyle): void;
43
43
  sendInput(chunk: Uint8Array): void;
44
+ requestImagePayloads(ids: readonly string[]): readonly string[];
44
45
  dispose(): void;
45
46
  private receive;
46
47
  private deliver;
47
48
  private flushQueuedInput;
48
- private sendPendingResyncRequest;
49
+ private sendPendingResyncRequests;
49
50
  }
50
51
  declare function webSocketSceneURL(options: Pick<WebSocketSceneBridgeOptions, "baseURL" | "webSocketURL" | "sceneId" | "token">): URL;
51
52
  //#endregion
@@ -43,8 +43,14 @@ var WebSocketSceneBridge = class {
43
43
  sendInput(chunk) {
44
44
  if (this.disposed) return;
45
45
  const copy = new Uint8Array(chunk);
46
- if (this.socket.readyState === socketOpenState) this.socket.send(copy);
47
- else this.queuedInput.push(copy);
46
+ this.queuedInput.push(copy);
47
+ if (this.socket.readyState === socketOpenState) this.flushQueuedInput();
48
+ }
49
+ requestImagePayloads(ids) {
50
+ if (this.disposed) return [];
51
+ const acceptedIds = this.decoder.requestImagePayloads(ids);
52
+ this.sendPendingResyncRequests();
53
+ return acceptedIds;
48
54
  }
49
55
  dispose() {
50
56
  if (this.disposed) return;
@@ -62,7 +68,7 @@ var WebSocketSceneBridge = class {
62
68
  const bytes = await bytesFromWebSocketMessage(message);
63
69
  if (!bytes) return;
64
70
  for (const record of this.decoder.feed(bytes)) this.deliver(record);
65
- this.sendPendingResyncRequest();
71
+ this.sendPendingResyncRequests();
66
72
  }
67
73
  deliver(record) {
68
74
  const sink = this.sink;
@@ -72,7 +78,7 @@ var WebSocketSceneBridge = class {
72
78
  }
73
79
  switch (record.type) {
74
80
  case "surface":
75
- sink.presentSurface(record.frame);
81
+ sink.presentSurface(record.frame, this.decoder.prepareToPresentSurface(record.frame));
76
82
  break;
77
83
  case "clipboard":
78
84
  sink.writeClipboard?.(record.text);
@@ -91,14 +97,23 @@ var WebSocketSceneBridge = class {
91
97
  }
92
98
  flushQueuedInput() {
93
99
  if (this.disposed || this.socket.readyState !== socketOpenState) return;
94
- while (this.queuedInput.length > 0) this.socket.send(this.queuedInput.shift());
95
- }
96
- sendPendingResyncRequest() {
97
- const request = this.decoder.takeResyncRequest();
98
- if (request) try {
99
- this.sendInput(encodeResyncControlMessage(request));
100
+ while (this.queuedInput.length > 0) try {
101
+ this.socket.send(this.queuedInput[0]);
102
+ this.queuedInput.shift();
100
103
  } catch {
101
- this.decoder.resyncRequestDeliveryFailed(request);
104
+ return;
105
+ }
106
+ }
107
+ sendPendingResyncRequests() {
108
+ while (true) {
109
+ const request = this.decoder.takeResyncRequest();
110
+ if (!request) return;
111
+ try {
112
+ this.sendInput(encodeResyncControlMessage(request));
113
+ } catch {
114
+ this.decoder.resyncRequestDeliveryFailed(request);
115
+ return;
116
+ }
102
117
  }
103
118
  }
104
119
  };
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketSceneBridge.js","names":[],"sources":["../../src/WebSocketSceneBridge.ts"],"sourcesContent":["import {\n WebHostOutputDecoder,\n encodeCapabilitiesControlMessage,\n encodeResyncControlMessage,\n encodeRenderStyleControlMessage,\n encodeResizeControlMessage,\n type WebHostOutputRecord,\n type WebHostOutputSink,\n} from \"./WebHostSurfaceTransport.ts\";\nimport type { WebHostTerminalStyle } from \"./WebHostTerminalStyle.ts\";\nimport type { WebHostSceneBridge } from \"./WebHostSceneRuntime.ts\";\n\nexport interface WebSocketSceneBridgeOptions {\n sceneId: string;\n token: string;\n baseURL?: string | URL;\n webSocketURL?: string | URL;\n webSocketFactory?: WebSocketSceneBridgeFactory;\n}\n\nexport type WebSocketSceneBridgeFactory = (url: string | URL) => WebSocketSceneSocket;\n\nexport interface WebSocketSceneSocket {\n binaryType: BinaryType;\n readonly readyState: number;\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\n close(code?: number, reason?: string): void;\n addEventListener(type: \"open\", listener: (event: Event) => void): void;\n addEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n addEventListener(type: \"close\", listener: (event: CloseEvent) => void): void;\n addEventListener(type: \"error\", listener: (event: Event) => void): void;\n removeEventListener(type: \"open\", listener: (event: Event) => void): void;\n removeEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n removeEventListener(type: \"close\", listener: (event: CloseEvent) => void): void;\n removeEventListener(type: \"error\", listener: (event: Event) => void): void;\n}\n\nconst socketOpenState = 1;\nconst textEncoder = new TextEncoder();\n\nexport class WebSocketSceneBridge implements WebHostSceneBridge {\n readonly url: URL;\n\n private readonly socket: WebSocketSceneSocket;\n private readonly decoder = new WebHostOutputDecoder();\n private readonly queuedInput: Uint8Array[] = [];\n private readonly queuedOutput: WebHostOutputRecord[] = [];\n private sink?: WebHostOutputSink;\n private disposed = false;\n\n private readonly handleOpen = () => {\n this.flushQueuedInput();\n };\n\n private readonly handleMessage = (event: MessageEvent) => {\n void this.receive(event.data);\n };\n\n private readonly handleClose = () => {\n for (const record of this.decoder.flush()) {\n this.deliver(record);\n }\n };\n\n private readonly handleError = () => {};\n\n constructor(options: WebSocketSceneBridgeOptions) {\n this.url = webSocketSceneURL(options);\n this.socket = (options.webSocketFactory ?? defaultWebSocketFactory)(this.url);\n this.socket.binaryType = \"arraybuffer\";\n this.socket.addEventListener(\"open\", this.handleOpen);\n this.socket.addEventListener(\"message\", this.handleMessage);\n this.socket.addEventListener(\"close\", this.handleClose);\n this.socket.addEventListener(\"error\", this.handleError);\n // Declare wire capabilities first: queued input flushes in order on\n // open, so the declaration reaches the server ahead of any\n // resize/style/input record.\n this.sendInput(encodeCapabilitiesControlMessage());\n }\n\n bindOutput(\n sink: WebHostOutputSink\n ): void {\n this.sink = sink;\n while (this.queuedOutput.length > 0) {\n this.deliver(this.queuedOutput.shift()!);\n }\n }\n\n resize(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n ): void {\n this.sendInput(encodeResizeControlMessage(columns, rows, cellWidth, cellHeight));\n }\n\n updateRenderStyle(\n style: WebHostTerminalStyle\n ): void {\n this.sendInput(encodeRenderStyleControlMessage(style));\n }\n\n sendInput(\n chunk: Uint8Array\n ): void {\n if (this.disposed) {\n return;\n }\n\n const copy = new Uint8Array(chunk);\n if (this.socket.readyState === socketOpenState) {\n this.socket.send(copy);\n } else {\n this.queuedInput.push(copy);\n }\n }\n\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.socket.removeEventListener(\"open\", this.handleOpen);\n this.socket.removeEventListener(\"message\", this.handleMessage);\n this.socket.removeEventListener(\"close\", this.handleClose);\n this.socket.removeEventListener(\"error\", this.handleError);\n this.queuedInput.length = 0;\n this.queuedOutput.length = 0;\n this.socket.close(1000, \"WebHost scene disposed\");\n }\n\n private async receive(\n message: unknown\n ): Promise<void> {\n if (this.disposed) {\n return;\n }\n\n const bytes = await bytesFromWebSocketMessage(message);\n if (!bytes) {\n return;\n }\n\n for (const record of this.decoder.feed(bytes)) {\n this.deliver(record);\n }\n this.sendPendingResyncRequest();\n }\n\n private deliver(\n record: WebHostOutputRecord\n ): void {\n const sink = this.sink;\n if (!sink) {\n this.queuedOutput.push(record);\n return;\n }\n\n switch (record.type) {\n case \"surface\":\n sink.presentSurface(record.frame);\n break;\n case \"clipboard\":\n void sink.writeClipboard?.(record.text);\n break;\n case \"runtimeIssue\":\n sink.notifyRuntimeIssue?.(record.issue);\n break;\n case \"frameDiagnostic\":\n sink.recordFrameDiagnostic?.(record.diagnostic);\n break;\n case \"surfaceDropped\":\n break;\n case \"text\":\n sink.writeOutput?.(record.text);\n break;\n }\n }\n\n private flushQueuedInput(): void {\n if (this.disposed || this.socket.readyState !== socketOpenState) {\n return;\n }\n while (this.queuedInput.length > 0) {\n this.socket.send(this.queuedInput.shift()!);\n }\n }\n\n private sendPendingResyncRequest(): void {\n const request = this.decoder.takeResyncRequest();\n if (request) {\n try {\n this.sendInput(encodeResyncControlMessage(request));\n } catch {\n this.decoder.resyncRequestDeliveryFailed(request);\n }\n }\n }\n}\n\nexport function webSocketSceneURL(\n options: Pick<WebSocketSceneBridgeOptions, \"baseURL\" | \"webSocketURL\" | \"sceneId\" | \"token\">\n): URL {\n if (options.webSocketURL) {\n const explicit = new URL(String(options.webSocketURL), currentPageURL());\n explicit.searchParams.set(\"token\", options.token);\n return explicit;\n }\n\n const url = new URL(String(options.baseURL ?? currentPageURL()), currentPageURL());\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const basePath = url.pathname.endsWith(\"/\") ? url.pathname.slice(0, -1) : url.pathname;\n url.pathname = `${basePath}/ws/scene/${encodeURIComponent(options.sceneId)}`;\n url.search = \"\";\n url.searchParams.set(\"token\", options.token);\n return url;\n}\n\nasync function bytesFromWebSocketMessage(\n message: unknown\n): Promise<Uint8Array | undefined> {\n if (typeof message === \"string\") {\n return textEncoder.encode(message);\n }\n if (message instanceof Uint8Array) {\n return message;\n }\n if (message instanceof ArrayBuffer) {\n return new Uint8Array(message);\n }\n if (ArrayBuffer.isView(message)) {\n return new Uint8Array(message.buffer, message.byteOffset, message.byteLength);\n }\n if (typeof Blob !== \"undefined\" && message instanceof Blob) {\n return new Uint8Array(await message.arrayBuffer());\n }\n return undefined;\n}\n\nfunction defaultWebSocketFactory(\n url: string | URL\n): WebSocketSceneSocket {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\"WebSocket is not available\");\n }\n return new WebSocket(url) as WebSocketSceneSocket;\n}\n\nfunction currentPageURL(): string {\n return globalThis.location?.href ?? \"http://127.0.0.1/\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WebSocketSceneBridge.js","names":[],"sources":["../../src/WebSocketSceneBridge.ts"],"sourcesContent":["import {\n WebHostOutputDecoder,\n encodeCapabilitiesControlMessage,\n encodeResyncControlMessage,\n encodeRenderStyleControlMessage,\n encodeResizeControlMessage,\n type WebHostOutputRecord,\n type WebHostOutputSink,\n} from \"./WebHostSurfaceTransport.ts\";\nimport type { WebHostTerminalStyle } from \"./WebHostTerminalStyle.ts\";\nimport type { WebHostSceneBridge } from \"./WebHostSceneRuntime.ts\";\n\nexport interface WebSocketSceneBridgeOptions {\n sceneId: string;\n token: string;\n baseURL?: string | URL;\n webSocketURL?: string | URL;\n webSocketFactory?: WebSocketSceneBridgeFactory;\n}\n\nexport type WebSocketSceneBridgeFactory = (url: string | URL) => WebSocketSceneSocket;\n\nexport interface WebSocketSceneSocket {\n binaryType: BinaryType;\n readonly readyState: number;\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\n close(code?: number, reason?: string): void;\n addEventListener(type: \"open\", listener: (event: Event) => void): void;\n addEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n addEventListener(type: \"close\", listener: (event: CloseEvent) => void): void;\n addEventListener(type: \"error\", listener: (event: Event) => void): void;\n removeEventListener(type: \"open\", listener: (event: Event) => void): void;\n removeEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n removeEventListener(type: \"close\", listener: (event: CloseEvent) => void): void;\n removeEventListener(type: \"error\", listener: (event: Event) => void): void;\n}\n\nconst socketOpenState = 1;\nconst textEncoder = new TextEncoder();\n\nexport class WebSocketSceneBridge implements WebHostSceneBridge {\n readonly url: URL;\n\n private readonly socket: WebSocketSceneSocket;\n private readonly decoder = new WebHostOutputDecoder();\n private readonly queuedInput: Uint8Array[] = [];\n private readonly queuedOutput: WebHostOutputRecord[] = [];\n private sink?: WebHostOutputSink;\n private disposed = false;\n\n private readonly handleOpen = () => {\n this.flushQueuedInput();\n };\n\n private readonly handleMessage = (event: MessageEvent) => {\n void this.receive(event.data);\n };\n\n private readonly handleClose = () => {\n for (const record of this.decoder.flush()) {\n this.deliver(record);\n }\n };\n\n private readonly handleError = () => {};\n\n constructor(options: WebSocketSceneBridgeOptions) {\n this.url = webSocketSceneURL(options);\n this.socket = (options.webSocketFactory ?? defaultWebSocketFactory)(this.url);\n this.socket.binaryType = \"arraybuffer\";\n this.socket.addEventListener(\"open\", this.handleOpen);\n this.socket.addEventListener(\"message\", this.handleMessage);\n this.socket.addEventListener(\"close\", this.handleClose);\n this.socket.addEventListener(\"error\", this.handleError);\n // Declare wire capabilities first: queued input flushes in order on\n // open, so the declaration reaches the server ahead of any\n // resize/style/input record.\n this.sendInput(encodeCapabilitiesControlMessage());\n }\n\n bindOutput(\n sink: WebHostOutputSink\n ): void {\n this.sink = sink;\n while (this.queuedOutput.length > 0) {\n this.deliver(this.queuedOutput.shift()!);\n }\n }\n\n resize(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n ): void {\n this.sendInput(encodeResizeControlMessage(columns, rows, cellWidth, cellHeight));\n }\n\n updateRenderStyle(\n style: WebHostTerminalStyle\n ): void {\n this.sendInput(encodeRenderStyleControlMessage(style));\n }\n\n sendInput(\n chunk: Uint8Array\n ): void {\n if (this.disposed) {\n return;\n }\n\n const copy = new Uint8Array(chunk);\n this.queuedInput.push(copy);\n if (this.socket.readyState === socketOpenState) {\n this.flushQueuedInput();\n }\n }\n\n requestImagePayloads(\n ids: readonly string[]\n ): readonly string[] {\n if (this.disposed) {\n return [];\n }\n const acceptedIds = this.decoder.requestImagePayloads(ids);\n this.sendPendingResyncRequests();\n return acceptedIds;\n }\n\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.socket.removeEventListener(\"open\", this.handleOpen);\n this.socket.removeEventListener(\"message\", this.handleMessage);\n this.socket.removeEventListener(\"close\", this.handleClose);\n this.socket.removeEventListener(\"error\", this.handleError);\n this.queuedInput.length = 0;\n this.queuedOutput.length = 0;\n this.socket.close(1000, \"WebHost scene disposed\");\n }\n\n private async receive(\n message: unknown\n ): Promise<void> {\n if (this.disposed) {\n return;\n }\n\n const bytes = await bytesFromWebSocketMessage(message);\n if (!bytes) {\n return;\n }\n\n for (const record of this.decoder.feed(bytes)) {\n this.deliver(record);\n }\n this.sendPendingResyncRequests();\n }\n\n private deliver(\n record: WebHostOutputRecord\n ): void {\n const sink = this.sink;\n if (!sink) {\n this.queuedOutput.push(record);\n return;\n }\n\n switch (record.type) {\n case \"surface\":\n sink.presentSurface(\n record.frame,\n this.decoder.prepareToPresentSurface(record.frame)\n );\n break;\n case \"clipboard\":\n void sink.writeClipboard?.(record.text);\n break;\n case \"runtimeIssue\":\n sink.notifyRuntimeIssue?.(record.issue);\n break;\n case \"frameDiagnostic\":\n sink.recordFrameDiagnostic?.(record.diagnostic);\n break;\n case \"surfaceDropped\":\n break;\n case \"text\":\n sink.writeOutput?.(record.text);\n break;\n }\n }\n\n private flushQueuedInput(): void {\n if (this.disposed || this.socket.readyState !== socketOpenState) {\n return;\n }\n while (this.queuedInput.length > 0) {\n try {\n this.socket.send(this.queuedInput[0]!);\n this.queuedInput.shift();\n } catch {\n return;\n }\n }\n }\n\n private sendPendingResyncRequests(): void {\n while (true) {\n const request = this.decoder.takeResyncRequest();\n if (!request) {\n return;\n }\n try {\n this.sendInput(encodeResyncControlMessage(request));\n } catch {\n this.decoder.resyncRequestDeliveryFailed(request);\n return;\n }\n }\n }\n}\n\nexport function webSocketSceneURL(\n options: Pick<WebSocketSceneBridgeOptions, \"baseURL\" | \"webSocketURL\" | \"sceneId\" | \"token\">\n): URL {\n if (options.webSocketURL) {\n const explicit = new URL(String(options.webSocketURL), currentPageURL());\n explicit.searchParams.set(\"token\", options.token);\n return explicit;\n }\n\n const url = new URL(String(options.baseURL ?? currentPageURL()), currentPageURL());\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const basePath = url.pathname.endsWith(\"/\") ? url.pathname.slice(0, -1) : url.pathname;\n url.pathname = `${basePath}/ws/scene/${encodeURIComponent(options.sceneId)}`;\n url.search = \"\";\n url.searchParams.set(\"token\", options.token);\n return url;\n}\n\nasync function bytesFromWebSocketMessage(\n message: unknown\n): Promise<Uint8Array | undefined> {\n if (typeof message === \"string\") {\n return textEncoder.encode(message);\n }\n if (message instanceof Uint8Array) {\n return message;\n }\n if (message instanceof ArrayBuffer) {\n return new Uint8Array(message);\n }\n if (ArrayBuffer.isView(message)) {\n return new Uint8Array(message.buffer, message.byteOffset, message.byteLength);\n }\n if (typeof Blob !== \"undefined\" && message instanceof Blob) {\n return new Uint8Array(await message.arrayBuffer());\n }\n return undefined;\n}\n\nfunction defaultWebSocketFactory(\n url: string | URL\n): WebSocketSceneSocket {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\"WebSocket is not available\");\n }\n return new WebSocket(url) as WebSocketSceneSocket;\n}\n\nfunction currentPageURL(): string {\n return globalThis.location?.href ?? \"http://127.0.0.1/\";\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ //#region src/normalizeWireTokens.d.ts
2
+ type NormalizedSurfaceImageFormat = "png" | "jpeg" | "gif";
3
+ //#endregion
4
+ export { NormalizedSurfaceImageFormat };
5
+ //# sourceMappingURL=normalizeWireTokens.d.ts.map
@@ -25,6 +25,7 @@ declare class BrowserWASIBridge {
25
25
  readonly environment: Record<string, string>;
26
26
  private detachStdout?;
27
27
  private detachStderr?;
28
+ private decoder;
28
29
  private readonly resizeListeners;
29
30
  private latestResize;
30
31
  constructor(options: BrowserWASIBridgeOptions);
@@ -32,7 +33,14 @@ declare class BrowserWASIBridge {
32
33
  resize(columns: number, rows: number, cellWidth?: number, cellHeight?: number): void;
33
34
  updateRenderStyle(style: WebHostTerminalStyle): void;
34
35
  sendInput(chunk: Uint8Array): void;
36
+ requestImagePayloads(ids: readonly string[]): readonly string[];
37
+ /**
38
+ * Called by the WASI runtime when its shared stdin queue has enough capacity
39
+ * for the delivery that previously failed.
40
+ */
41
+ notifyInputCapacityAvailable(): void;
35
42
  subscribeResize(listener: (columns: number, rows: number, cellWidth?: number, cellHeight?: number) => void): () => void;
43
+ private sendPendingResyncRequests;
36
44
  dispose(): void;
37
45
  }
38
46
  //#endregion