@hex1b/web-terminal 0.171.0 → 0.172.0-alpha.1652.1.6a01c54

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.
package/README.md CHANGED
@@ -51,6 +51,111 @@ terminal.focus();
51
51
  or disposes a mounted view. Disposal removes only the appended element and its
52
52
  connection, not the container or server-side shared terminal.
53
53
 
54
+ ### Live transports
55
+
56
+ Supply **exactly one** of `url` or `transport`. TypeScript rejects both/neither,
57
+ and JavaScript callers receive a `TypeError` before a worker or connection is
58
+ created. `url` is only shorthand for the same first-party transport:
59
+
60
+ ```ts
61
+ import { WebTerminal, createWebSocketTransport } from "@hex1b/web-terminal";
62
+
63
+ const container = document.getElementById("terminal");
64
+ if (!container) throw new Error("Missing terminal container");
65
+ const terminal = await WebTerminal.mount(container, {
66
+ transport: createWebSocketTransport("/ws/terminal"),
67
+ });
68
+ ```
69
+
70
+ Both forms normalize URLs identically and run the WebSocket directly in the
71
+ rendering worker; frames and controls do not detour through the main thread.
72
+ Custom transports run in the host JavaScript context. Hex1b supplies the bridge
73
+ to its own worker, so adapters need neither a replacement worker nor knowledge
74
+ of private worker messages. All exports are also available from the standalone
75
+ `dist/index.js` ES module, with the same API and no framework dependencies.
76
+
77
+ A `TerminalTransport` implements `connect(context)`, returning a
78
+ `TerminalTransportConnection` synchronously or asynchronously. Return/resolve
79
+ when the channel is ready for controls. `context` is provided **before** attachment,
80
+ so even synchronous startup delivery has listeners. One early `onFrame` may
81
+ wait for connection readiness; **do not await it inside `connect`**.
82
+
83
+ The following adapter snippet assumes a host-provided `bridge.attach` operation.
84
+ It must install the supplied listeners before enabling delivery, honor `signal`
85
+ while attaching, and return a per-view channel (not the terminal workload):
86
+
87
+ ```ts
88
+ import { WebTerminal, type TerminalTransport } from "@hex1b/web-terminal";
89
+
90
+ // `bridge` is supplied by your host, not by Hex1b.
91
+ const transport: TerminalTransport = {
92
+ async connect({ signal, onFrame, onClose, onError }) {
93
+ const channel = await bridge.attach({
94
+ signal,
95
+ onFrame, // (ArrayBuffer | Uint8Array) => Promise<void>
96
+ onClose: (reason: string) => onClose({ reason }),
97
+ onError,
98
+ });
99
+ return {
100
+ // Forward opaque serialized controls unchanged. No keyboard/mouse/ACK parsing.
101
+ send: (control: string) => channel.send(control),
102
+ dispose: () => channel.detach(),
103
+ };
104
+ },
105
+ };
106
+
107
+ const container = document.getElementById("terminal");
108
+ if (!container) throw new Error("Missing terminal container");
109
+ const terminal = await WebTerminal.mount(container, {
110
+ transport,
111
+ onClose: details => console.log("View detached", details.reason),
112
+ onStatus: (message, level) => console.log(level, message),
113
+ });
114
+ ```
115
+
116
+ **Ordering and ownership:** deliver complete binary HWT1 frames in order, awaiting
117
+ each `onFrame` promise before delivering another. An `ArrayBuffer` is handed over
118
+ exclusively and may be detached; do not read, mutate, or reuse it after the call.
119
+ A `Uint8Array` backed by an `ArrayBuffer` is copied synchronously using only its
120
+ slice, leaving the host's buffer intact. Other views and shared buffers are not
121
+ supported. The existing 96 MiB HWT1 frame limit still applies.
122
+
123
+ `onFrame` completion means worker acceptance, **not GPU presentation or producer
124
+ ACK**. The worker forwards the actual HWT1 ACK only at its existing protocol
125
+ boundary: after renderer completion for presented frames, or when discarding a
126
+ mismatched revision / accepting an inventory fragment. Adapters must forward all
127
+ outgoing controls independently and unchanged; they must not manufacture ACKs,
128
+ wait for an ACK inside `send`, or use receipt completion to release the producer's
129
+ one-unacknowledged-state-frame gate. This preserves image resource lifetimes and
130
+ full-baseline/resync behavior. Concurrent deliveries or producer gate violations
131
+ fail the view rather than dropping deltas or accumulating frames.
132
+
133
+ `send(control)` may return `void` or `Promise<void>`. Hex1b waits for completion
134
+ before invoking the next send, preserving completion order as well as invocation
135
+ order. Resolve after the underlying channel accepts the control in order, not
136
+ after a response frame. Throw/reject to report failure. Queued controls are bounded
137
+ to 256 messages / 1 MiB (including the active send); overflow fails the view. The
138
+ WebSocket adapter additionally caps the browser's outgoing buffer at 1 MiB.
139
+ Adapters must keep their own native/channel buffering bounded too.
140
+
141
+ **Lifetime:** `signal` aborts on disposal, timeout, failed attachment, fatal error,
142
+ or close. Cancel pending attachment and detach listeners promptly. Hex1b disposes
143
+ any connection returned after cancellation. `dispose()` is synchronous, idempotent,
144
+ nonthrowing, and should initiate per-view channel teardown, never terminate the
145
+ server terminal. Late callbacks cannot revive a disposed view. Use `onError(Error)`
146
+ for a fatal transport failure (reported through `onStatus`, rejecting a pending
147
+ mount), and `onClose({ reason })` for actual custom-channel closure. Neither errors
148
+ nor local teardown invent WebSocket status codes. There is no automatic reconnect.
149
+ Recording APIs and formats are unchanged.
150
+
151
+ The public-bundle graphics regression needs only a static server, not a terminal
152
+ server. After building, serve this package directory as the HTTP root, open its
153
+ `/tests/` URL in an isolated Playwright CLI session, and run
154
+ `playwright-cli -s=transports run-code --filename src/web-terminal/tests/transport.browser.js`
155
+ from the repository root. It verifies real worker rendering, transferred buffers,
156
+ KGP/Sixel pixels, retained-image movement/release, ACK ordering, controls, and
157
+ closure without any WebSocket, using WebGL2 and WebGPU when available.
158
+
54
159
  ### Light and dark terminal palettes
55
160
 
56
161
  Supply JSON-compatible palettes independently for light and dark mode. Palette names
@@ -150,6 +255,9 @@ font license when vendoring.
150
255
 
151
256
  Use `onClose(details)` to observe the browser's actual WebSocket close event.
152
257
  `TerminalCloseDetails` contains readonly `code`, `reason`, and `wasClean` fields.
258
+ This payload is unchanged for both WebSocket configuration forms. Custom
259
+ transports use `TerminalTransportCloseDetails`; `code` and `wasClean` are absent
260
+ unless the underlying channel actually reports native WebSocket details.
153
261
  The callback runs once with the view already disconnected, **even if the socket
154
262
  closes before the first HWT frame or authoritative HMP peer state**. A pending
155
263
  mount rejects after the callback, so capture any host state before calling mount.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { WebTerminal } from "./web-terminal.js";
2
+ export { createWebSocketTransport } from "./websocket-transport.js";
2
3
  export { defaultLightPalette, defaultDarkPalette } from "./terminal-palette.js";
3
4
  export { InputRoute, TerminalAction, defaultInputBindings } from "./input-policy.js";
4
5
  export { MIN_FONT_SIZE, MAX_FONT_SIZE } from "./terminal-sizing.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,0BAA0B,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACvE,mBAAmB,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,0BAA0B,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACvE,mBAAmB,YAAY,CAAC"}