You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(websocket): prevent duplicate lines on reconnect via replay snapshot
Server now sends scrollback (and any alt-screen re-entry) as a single
`replay` message instead of an `output`. Client treats `replay` as an
authoritative snapshot — drops pending writes and resets the terminal
before applying it — so preserved xterm.js content no longer gets
appended-onto on reconnect, fixing duplicate-line artefacts in plain
shells. Also adds a stale-socket guard to onmessage handlers and updates
the API docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: packages/site/src/content/docs/api.md
+11-2Lines changed: 11 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1033,11 +1033,12 @@ The preview proxies **one port at a time** via HTTP only. It does not proxy WebS
1033
1033
1034
1034
<!-- prettier-ignore -->
1035
1035
:::tip[Limitations when accessed through a tunnel]
1036
+
1036
1037
-**Server-rendered apps** (Next.js SSR, Rails, Django) work best — the browser receives complete HTML with no extra fetches.
1037
1038
-**Client-side SPAs** may break if they make API calls to a different port or use hardcoded `localhost` URLs. Apps that use a single point with an internal reverse proxy (e.g., nginx proxying `/api` to a backend) work fine.
1038
1039
-**Multi-port architectures** (e.g., frontend on port 3000 making API calls to port 4000) won't work unless the app routes all requests through TermBeam's preview proxy (e.g., `/preview/4000/api` instead of `localhost:4000/api`).
1039
1040
- The upstream service must be listening on `127.0.0.1` (localhost) on the machine running TermBeam.
1040
-
:::
1041
+
:::
1041
1042
1042
1043
**Response:** The upstream response is streamed back with its original status code and headers.
1043
1044
@@ -1187,7 +1188,7 @@ The connection is closed after sending this message. Sending any non-auth messag
1187
1188
{ "type": "attach", "sessionId": "a1b2c3d4" }
1188
1189
```
1189
1190
1190
-
After a successful `attached` response, the server immediately sends an `output` message containing the session's scrollback buffer (up to ~1,000,000 characters). When the buffer grows beyond this size, it is trimmed back to ~500,000 characters to keep memory usage bounded, allowing the client to display recent terminal output.
1191
+
After a successful attach, the server sends a single `replay` message containing the session's sanitized scrollback buffer (up to ~1,000,000 characters; trimmed back to ~500,000 when it grows beyond that), followed by the `attached` confirmation. Clients should treat `replay` as an authoritative state snapshot and reset their terminal before applying it — this prevents duplicated content on reconnect when the terminal UI is preserved across socket lifecycles.
1191
1192
1192
1193
#### Send Input
1193
1194
@@ -1211,6 +1212,14 @@ The server validates resize dimensions: `cols` must be between 1–500 and `rows
1211
1212
{ "type": "output", "data": "..." }
1212
1213
```
1213
1214
1215
+
#### Replay Snapshot
1216
+
1217
+
Sent on attach. Contains sanitized scrollback (and an alt-screen re-entry sequence when the session is currently in alt-screen). Clients should drop pending writes, reset their terminal, and write this payload — do not append it on top of preserved terminal content.
0 commit comments