@cplieger/web-terminal-engine 1.2.0

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 ADDED
@@ -0,0 +1,97 @@
1
+ # @cplieger/web-terminal-engine
2
+
3
+ [![npm](https://img.shields.io/npm/v/@cplieger/web-terminal-engine)](https://www.npmjs.com/package/@cplieger/web-terminal-engine)
4
+ [![JSR](https://jsr.io/badges/@cplieger/web-terminal-engine)](https://jsr.io/@cplieger/web-terminal-engine)
5
+
6
+ > Browser virtual terminal renderer for the [`cplieger/web-terminal-engine`](https://github.com/cplieger/web-terminal-engine) Go module: DOM-based VT500 screen with OSC 8 hyperlink support, scrollback, keyboard mapper, mouse encoder, and binary wire decoder. Zero runtime dependencies.
7
+
8
+ The browser half of the web-terminal-engine cross-language terminal library. Pairs with the Go server-side packages (`vt`, `terminal`) over a binary WebSocket protocol; see the [project README](https://github.com/cplieger/web-terminal-engine#readme) for the full story.
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ npx jsr add @cplieger/web-terminal-engine # JSR (preferred)
14
+ npm i @cplieger/web-terminal-engine # NPM
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```typescript
20
+ import {
21
+ render,
22
+ keyboard,
23
+ mouse,
24
+ scroll,
25
+ modes,
26
+ decodeWireBinary,
27
+ } from "@cplieger/web-terminal-engine";
28
+
29
+ const wrap = document.getElementById("term") as HTMLElement;
30
+ const out = document.getElementById("term-output") as HTMLElement;
31
+
32
+ render.init({ output: out, termWrap: wrap });
33
+ scroll.init({ scrollEl: wrap });
34
+ mouse.init({
35
+ send: (data) => ws.send(data),
36
+ cellSize: () => ({ width: cellW, height: cellH }),
37
+ termElement: () => wrap,
38
+ });
39
+
40
+ ws.binaryType = "arraybuffer";
41
+ ws.addEventListener("message", (ev) => {
42
+ const msg = decodeWireBinary(ev.data);
43
+ if (!msg) return;
44
+ switch (msg.type) {
45
+ case "screen":
46
+ render.handleScreen(msg);
47
+ break;
48
+ case "scroll":
49
+ render.handleScroll(msg);
50
+ break;
51
+ case "modes":
52
+ modes.setModes(
53
+ msg.bracketedPaste,
54
+ msg.applicationCursor,
55
+ msg.mouseSGR,
56
+ msg.focusReporting,
57
+ msg.mouseMode,
58
+ msg.applicationKeypad,
59
+ msg.reverseVideo,
60
+ );
61
+ break;
62
+ case "title":
63
+ document.title = msg.title;
64
+ break;
65
+ }
66
+ });
67
+
68
+ document.addEventListener("keydown", (ev) => {
69
+ const r = keyboard.mapKeyboardEvent(ev);
70
+ if (r.kind === "send") {
71
+ ws.send(r.bytes);
72
+ ev.preventDefault();
73
+ }
74
+ if (r.kind === "scroll-up" || r.kind === "scroll-down") ev.preventDefault();
75
+ });
76
+ ```
77
+
78
+ ## API
79
+
80
+ - **`render`** — DOM renderer driven by `ScreenMessage` / `ScrollMessage` frames. `init`, `handleScreen`, `handleScroll`, `updateFontMetrics`, `computeSize`, `getCursorPx`, `setPredictedCursor`, `resetScreen`, `resetScrollback`, `getScrollbackRowCount`, `updateReverseVideo`.
81
+ - **`keyboard`** — Translates `KeyboardEvent` to terminal byte sequences. `mapKeyboardEvent`, `bracketTextForPaste`, `prepareTextForTerminal`, `ctrlByteFor`. Honors `applicationCursor`, `applicationKeypad`, `bracketedPaste`. For touch / mobile UIs, `bindMobileToolbar({toolbar, send, ids?})` wires `pointerdown` handlers for an on-screen Ctrl/arrows/Tab/Enter/Esc toolbar (with sticky-Ctrl semantics and DECCKM-aware arrows), returning a `MobileToolbarController` exposing `applyStickyCtrl`, `setCtrlArmed`, `isCtrlArmed`, and `dispose`.
82
+ - **`mouse`** — SGR 1006 mouse + focus reporting encoder. `init`, `encodeSGR`, `MouseInputHandler`. Auto-gates on `mouseMode > 0`.
83
+ - **`scroll`** — Auto-follow tracker for the scroll container. `init`, `scrollToBottom`, `suppressScroll`, `isUserScrolledUp`, `isInUserScroll`.
84
+ - **`modes`** — DEC private mode state (synced from server's `ModesMessage`). `setModes`, `isBracketedPaste`, `isApplicationCursor`, `getMouseMode`, `isMouseSGR`, `isFocusReporting`, `isApplicationKeypad`, `isReverseVideo`.
85
+ - **`decodeWireBinary(buf)`** — Top-level decoder for the binary WebSocket frames. Returns a `ServerMessage` or `null` for invalid/truncated frames.
86
+ - **`connection`** — Client → server WebSocket lifecycle: owns the socket, exponential-backoff reconnect, and the resume/inputAck reliability layer (outbox + server-restart detection). `init(callbacks)`, `connect`, `sendBinary(bytes)`, `sendResize`, `reconnectNow`. The callbacks expose `onMessage(ServerMessage)`, `onOpen`/`onClose`/`onConnecting`/`onOutboxFull`/`onServerRestart`, a `computeSize()` provider, and an optional `wsPath` (defaults to `"/ws"`). It decodes frames internally and applies `modes.setModes` for you, so a consumer only needs to dispatch screen/scroll to `render`. Prefer this over wiring `WebSocket` + `decodeWireBinary` by hand unless you need full control.
87
+ - **`controlFrame(msg)` / `wsURL(proto, host, path?)`** — Low-level helpers for the client → server protocol (0x00-prefixed JSON control frames, WebSocket URL building). Used internally by `connection`; exported for advanced consumers.
88
+
89
+ Wire types (`WireRun`, `ScreenMessage`, `ScrollMessage`, `ModesMessage`, `TitleMessage`, `ResumeAckMessage`, `ServerMessage`, `ControlMessage`) are re-exported from the package root and match the Go server's wire format byte-for-byte.
90
+
91
+ ## Browser-only
92
+
93
+ This package depends on `document`, `HTMLElement`, `MessageChannel`, and other DOM APIs, so it only runs in browser-like environments. The companion Go server runs anywhere Go does.
94
+
95
+ ## License
96
+
97
+ GPL-3.0 — see [LICENSE](../LICENSE).
package/jsr.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@cplieger/web-terminal-engine",
3
+ "version": "1.2.0",
4
+ "exports": {
5
+ ".": "./src/index.ts"
6
+ },
7
+ "publish": {
8
+ "include": [
9
+ "LICENSE",
10
+ "README.md",
11
+ "src/**/*.ts"
12
+ ],
13
+ "exclude": [
14
+ "src/**/*.test.ts",
15
+ "src/**/__test-helpers__/**"
16
+ ]
17
+ }
18
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@cplieger/web-terminal-engine",
3
+ "version": "1.2.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "typecheck": "tsgo -p tsconfig.json",
7
+ "typecheck:tests": "tsgo -p tsconfig.test.json",
8
+ "test": "vitest --run"
9
+ },
10
+ "devDependencies": {
11
+ "@eslint/js": "10.0.1",
12
+ "@vitest/coverage-v8": "4.1.9",
13
+ "eslint": "10.5.0",
14
+ "fast-check": "4.8.0",
15
+ "happy-dom": "20.10.6",
16
+ "prettier": "3.8.4",
17
+ "typescript": "6.0.3",
18
+ "typescript-eslint": "8.62.0",
19
+ "vitest": "4.1.9"
20
+ },
21
+ "description": "Browser terminal engine: VT500 screen buffer, DOM renderer, and binary wire protocol",
22
+ "license": "GPL-3.0-or-later",
23
+ "exports": {
24
+ ".": "./src/index.ts"
25
+ },
26
+ "types": "./src/index.ts",
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/cplieger/web-terminal-engine.git",
33
+ "directory": "web"
34
+ },
35
+ "files": [
36
+ "src/",
37
+ "!src/**/*.test.ts",
38
+ "!src/**/__test-helpers__",
39
+ "!src/**/fc-strict-setup.ts",
40
+ "jsr.json"
41
+ ]
42
+ }