@tangle-network/sandbox-ui 0.105.0 → 0.105.1

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.
@@ -3,7 +3,7 @@ import { useState, useEffect, useRef, useCallback } from "react";
3
3
  function createEmptyBatch() {
4
4
  return { data: "", waiters: [] };
5
5
  }
6
- var WS_OPEN_TIMEOUT_MS = 1e4;
6
+ var WS_READY_TIMEOUT_MS = 1e4;
7
7
  function toWsUrl(apiUrl, sessionId) {
8
8
  try {
9
9
  const base = typeof window !== "undefined" ? window.location.href : void 0;
@@ -64,6 +64,7 @@ function usePtySession({
64
64
  const reconnectRef = useRef(null);
65
65
  const shouldDeleteSessionRef = useRef(false);
66
66
  const transportReadyRef = useRef(false);
67
+ const protocolFailureRef = useRef(false);
67
68
  const colsRef = useRef(DEFAULT_TERMINAL_COLS);
68
69
  const rowsRef = useRef(DEFAULT_TERMINAL_ROWS);
69
70
  const wsRef = useRef(null);
@@ -169,13 +170,25 @@ function usePtySession({
169
170
  resolve(ok);
170
171
  };
171
172
  const handshakeTimer = setTimeout(() => {
172
- if (opened) return;
173
173
  try {
174
174
  ws.close();
175
175
  } catch {
176
176
  }
177
177
  settle(false);
178
- }, WS_OPEN_TIMEOUT_MS);
178
+ }, WS_READY_TIMEOUT_MS);
179
+ const failProtocol = (message) => {
180
+ protocolFailureRef.current = true;
181
+ transportReadyRef.current = false;
182
+ if (wsRef.current === ws) wsRef.current = null;
183
+ setIsConnected(false);
184
+ setError(message);
185
+ rejectPendingInput(message);
186
+ try {
187
+ ws.close();
188
+ } catch {
189
+ }
190
+ settle(false);
191
+ };
179
192
  ws.onopen = () => {
180
193
  opened = true;
181
194
  if (pendingWsRef.current !== ws || !mountedRef.current) {
@@ -212,12 +225,8 @@ function usePtySession({
212
225
  return;
213
226
  }
214
227
  }
228
+ if (protocolFailureRef.current) return;
215
229
  wsRef.current = ws;
216
- transportReadyRef.current = true;
217
- setIsConnected(true);
218
- setError(null);
219
- retryCountRef.current = 0;
220
- settle(true);
221
230
  };
222
231
  ws.onmessage = (ev) => {
223
232
  if (!mountedRef.current) return;
@@ -239,17 +248,38 @@ function usePtySession({
239
248
  if (typeof data === "string") {
240
249
  try {
241
250
  const event = JSON.parse(text);
242
- if (event?.type === "ready") {
243
- return;
244
- }
245
- if (event?.type === "error") {
246
- const message = typeof event.message === "string" ? event.message : "Terminal WebSocket error";
247
- setError(message);
248
- return;
249
- }
250
- if (event?.type === "exit") {
251
- setIsConnected(false);
252
- return;
251
+ if (event !== null && typeof event === "object" && !Array.isArray(event)) {
252
+ const controlFrame = event;
253
+ switch (controlFrame.type) {
254
+ case "ready":
255
+ transportReadyRef.current = true;
256
+ setIsConnected(true);
257
+ setError(null);
258
+ retryCountRef.current = 0;
259
+ settle(true);
260
+ return;
261
+ case "error": {
262
+ const message = typeof controlFrame.message === "string" ? controlFrame.message : "Terminal WebSocket error";
263
+ if (!transportReadyRef.current) {
264
+ failProtocol(message);
265
+ } else {
266
+ setError(message);
267
+ }
268
+ return;
269
+ }
270
+ case "exit":
271
+ transportReadyRef.current = false;
272
+ setIsConnected(false);
273
+ return;
274
+ case "rec":
275
+ case "rec.done":
276
+ return;
277
+ default: {
278
+ const frameType = typeof controlFrame.type === "string" ? controlFrame.type : "<missing type>";
279
+ failProtocol(`Unknown terminal control frame: ${frameType}`);
280
+ return;
281
+ }
282
+ }
253
283
  }
254
284
  } catch {
255
285
  }
@@ -263,6 +293,7 @@ function usePtySession({
263
293
  pendingWsRef.current = null;
264
294
  }
265
295
  const wasActive = wsRef.current === ws;
296
+ const wasReady = wasActive && transportReadyRef.current;
266
297
  if (wasActive) {
267
298
  wsRef.current = null;
268
299
  transportReadyRef.current = false;
@@ -271,7 +302,11 @@ function usePtySession({
271
302
  settle(false);
272
303
  return;
273
304
  }
274
- if (!wasActive || !mountedRef.current) return;
305
+ if (!wasReady) {
306
+ settle(false);
307
+ return;
308
+ }
309
+ if (protocolFailureRef.current || !wasActive || !mountedRef.current) return;
275
310
  setIsConnected(false);
276
311
  if (sessionIdRef.current) {
277
312
  retryTimerRef.current = setTimeout(() => {
@@ -286,7 +321,7 @@ function usePtySession({
286
321
  }
287
322
  };
288
323
  });
289
- }, [apiUrl]);
324
+ }, [apiUrl, rejectPendingInput]);
290
325
  const connectStream = useCallback(async (sessionId) => {
291
326
  if (exactAttachRequiredRef.current) {
292
327
  throw new Error(
@@ -387,6 +422,7 @@ function usePtySession({
387
422
  const connect = useCallback(async () => {
388
423
  cleanup();
389
424
  const myGen = ++connectGenRef.current;
425
+ protocolFailureRef.current = false;
390
426
  retryCountRef.current = 0;
391
427
  setError(null);
392
428
  if (exactAttachRequiredRef.current && (!incarnationIdRef.current || !controlRef.current)) {
@@ -402,6 +438,7 @@ function usePtySession({
402
438
  inputAbortRef.current = new AbortController();
403
439
  const directWsOk = await connectWs(connectionId, { initOnOpen: true });
404
440
  if (!mountedRef.current || connectGenRef.current !== myGen) return;
441
+ if (protocolFailureRef.current) return;
405
442
  ensureDrainRunningRef.current?.();
406
443
  if (directWsOk) {
407
444
  return;
@@ -442,6 +479,7 @@ function usePtySession({
442
479
  inputAbortRef.current = new AbortController();
443
480
  const wsOk = await connectWs(sessionId, { initOnOpen: true });
444
481
  if (!mountedRef.current || connectGenRef.current !== myGen) return;
482
+ if (protocolFailureRef.current) return;
445
483
  ensureDrainRunningRef.current?.();
446
484
  if (wsOk) {
447
485
  return;
@@ -564,6 +602,10 @@ function usePtySession({
564
602
  resolve();
565
603
  return;
566
604
  }
605
+ if (protocolFailureRef.current) {
606
+ reject(new Error("Terminal protocol failure"));
607
+ return;
608
+ }
567
609
  pendingBatchRef.current.data += command;
568
610
  pendingBatchRef.current.waiters.push({ resolve, reject });
569
611
  ensureDrainRunning();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  usePtySession
3
- } from "./chunk-7KB22BLB.js";
3
+ } from "./chunk-FW77EXKG.js";
4
4
 
5
5
  // src/terminal/terminal-view.tsx
6
6
  import "@xterm/xterm/css/xterm.css";
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-K4Q4E7D7.js";
7
7
  import {
8
8
  TerminalView
9
- } from "./chunk-4VLVVKQZ.js";
9
+ } from "./chunk-MXQT46AZ.js";
10
10
  import {
11
11
  cn
12
12
  } from "./chunk-EI44GEQ5.js";
package/dist/hooks.d.ts CHANGED
@@ -51,8 +51,9 @@ interface UsePtySessionReturn {
51
51
  * - Server → client: BINARY frames carrying PTY output; TEXT frames
52
52
  * carrying lifecycle/control messages.
53
53
  * - Client → server: TEXT frames carrying JSON input/resize messages.
54
- * 2. If direct WS does not reach OPEN within WS_OPEN_TIMEOUT_MS, or it
55
- * errors before opening, fall back to the older terminal contract:
54
+ * 2. If direct WS does not reach server `ready` within
55
+ * WS_READY_TIMEOUT_MS, or it errors before ready, fall back to the older
56
+ * terminal contract:
56
57
  * - POST /terminals creates the session.
57
58
  * - GET /terminals/:id/ws tries the older WS transport.
58
59
  * - GET /terminals/:id/stream (SSE for output)
package/dist/hooks.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  } from "./chunk-3GX5BSD4.js";
27
27
  import {
28
28
  usePtySession
29
- } from "./chunk-7KB22BLB.js";
29
+ } from "./chunk-FW77EXKG.js";
30
30
  import "./chunk-CZ7CSFO4.js";
31
31
  export {
32
32
  RealtimeSessionRegistry,
package/dist/index.js CHANGED
@@ -153,7 +153,7 @@ import {
153
153
  buildUnifiedPatch,
154
154
  computeDiffStats,
155
155
  resolveLanguage
156
- } from "./chunk-NAWEV5UJ.js";
156
+ } from "./chunk-NT6SCOY2.js";
157
157
  import {
158
158
  FileArtifactPane,
159
159
  FilePreview,
@@ -238,10 +238,10 @@ import {
238
238
  UsageChart,
239
239
  formatPrice
240
240
  } from "./chunk-OMUIPJQZ.js";
241
- import "./chunk-4VLVVKQZ.js";
241
+ import "./chunk-MXQT46AZ.js";
242
242
  import {
243
243
  usePtySession
244
- } from "./chunk-7KB22BLB.js";
244
+ } from "./chunk-FW77EXKG.js";
245
245
  import {
246
246
  Avatar,
247
247
  AvatarFallback,
package/dist/terminal.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  DEFAULT_TERMINAL_THEME,
3
3
  TerminalView
4
- } from "./chunk-4VLVVKQZ.js";
5
- import "./chunk-7KB22BLB.js";
4
+ } from "./chunk-MXQT46AZ.js";
5
+ import "./chunk-FW77EXKG.js";
6
6
  import "./chunk-CZ7CSFO4.js";
7
7
  export {
8
8
  DEFAULT_TERMINAL_THEME,
package/dist/workbench.js CHANGED
@@ -12,12 +12,12 @@ import {
12
12
  buildUnifiedPatch,
13
13
  computeDiffStats,
14
14
  resolveLanguage
15
- } from "./chunk-NAWEV5UJ.js";
15
+ } from "./chunk-NT6SCOY2.js";
16
16
  import "./chunk-PZVUIUUW.js";
17
17
  import "./chunk-K4Q4E7D7.js";
18
18
  import "./chunk-OMUIPJQZ.js";
19
- import "./chunk-4VLVVKQZ.js";
20
- import "./chunk-7KB22BLB.js";
19
+ import "./chunk-MXQT46AZ.js";
20
+ import "./chunk-FW77EXKG.js";
21
21
  import "./chunk-2XPJ2XF7.js";
22
22
  import "./chunk-RQZRXKMR.js";
23
23
  import "./chunk-BGVEHENC.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.105.0",
3
+ "version": "0.105.1",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "repository": {
6
6
  "type": "git",