@tangle-network/sandbox-ui 0.105.0 → 0.105.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.
- package/dist/{chunk-7KB22BLB.js → chunk-F7LNWZQR.js} +89 -24
- package/dist/{chunk-4VLVVKQZ.js → chunk-LWSWKLI5.js} +1 -1
- package/dist/{chunk-NAWEV5UJ.js → chunk-X24MVW2R.js} +1 -1
- package/dist/hooks.d.ts +3 -2
- package/dist/hooks.js +1 -1
- package/dist/index.js +3 -3
- package/dist/terminal.js +2 -2
- package/dist/workbench.js +3 -3
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { useState, useEffect, useRef, useCallback } from "react";
|
|
|
3
3
|
function createEmptyBatch() {
|
|
4
4
|
return { data: "", waiters: [] };
|
|
5
5
|
}
|
|
6
|
-
var
|
|
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;
|
|
@@ -37,6 +37,20 @@ function createTerminalConnectionId() {
|
|
|
37
37
|
}
|
|
38
38
|
return `terminal-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
39
39
|
}
|
|
40
|
+
function interactiveIdentityKey(incarnationId, control) {
|
|
41
|
+
if (incarnationId === void 0 && control === void 0) return "plain";
|
|
42
|
+
if (incarnationId === void 0 || control === void 0) {
|
|
43
|
+
return `incomplete:${incarnationId ?? ""}`;
|
|
44
|
+
}
|
|
45
|
+
return [
|
|
46
|
+
incarnationId,
|
|
47
|
+
control.refDigest,
|
|
48
|
+
String(control.generation),
|
|
49
|
+
control.leaseId,
|
|
50
|
+
control.holderId,
|
|
51
|
+
control.expiresAt
|
|
52
|
+
].join("\0");
|
|
53
|
+
}
|
|
40
54
|
function usePtySession({
|
|
41
55
|
apiUrl,
|
|
42
56
|
token,
|
|
@@ -64,6 +78,7 @@ function usePtySession({
|
|
|
64
78
|
const reconnectRef = useRef(null);
|
|
65
79
|
const shouldDeleteSessionRef = useRef(false);
|
|
66
80
|
const transportReadyRef = useRef(false);
|
|
81
|
+
const protocolFailureRef = useRef(false);
|
|
67
82
|
const colsRef = useRef(DEFAULT_TERMINAL_COLS);
|
|
68
83
|
const rowsRef = useRef(DEFAULT_TERMINAL_ROWS);
|
|
69
84
|
const wsRef = useRef(null);
|
|
@@ -160,6 +175,7 @@ function usePtySession({
|
|
|
160
175
|
}
|
|
161
176
|
ws.binaryType = "arraybuffer";
|
|
162
177
|
pendingWsRef.current = ws;
|
|
178
|
+
const isCurrentSocket = () => wsRef.current === ws || pendingWsRef.current === ws;
|
|
163
179
|
let opened = false;
|
|
164
180
|
let settled = false;
|
|
165
181
|
const settle = (ok) => {
|
|
@@ -169,13 +185,25 @@ function usePtySession({
|
|
|
169
185
|
resolve(ok);
|
|
170
186
|
};
|
|
171
187
|
const handshakeTimer = setTimeout(() => {
|
|
172
|
-
if (opened) return;
|
|
173
188
|
try {
|
|
174
189
|
ws.close();
|
|
175
190
|
} catch {
|
|
176
191
|
}
|
|
177
192
|
settle(false);
|
|
178
|
-
},
|
|
193
|
+
}, WS_READY_TIMEOUT_MS);
|
|
194
|
+
const failProtocol = (message) => {
|
|
195
|
+
protocolFailureRef.current = true;
|
|
196
|
+
transportReadyRef.current = false;
|
|
197
|
+
if (wsRef.current === ws) wsRef.current = null;
|
|
198
|
+
setIsConnected(false);
|
|
199
|
+
setError(message);
|
|
200
|
+
rejectPendingInput(message);
|
|
201
|
+
try {
|
|
202
|
+
ws.close();
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
settle(false);
|
|
206
|
+
};
|
|
179
207
|
ws.onopen = () => {
|
|
180
208
|
opened = true;
|
|
181
209
|
if (pendingWsRef.current !== ws || !mountedRef.current) {
|
|
@@ -212,15 +240,11 @@ function usePtySession({
|
|
|
212
240
|
return;
|
|
213
241
|
}
|
|
214
242
|
}
|
|
243
|
+
if (protocolFailureRef.current) return;
|
|
215
244
|
wsRef.current = ws;
|
|
216
|
-
transportReadyRef.current = true;
|
|
217
|
-
setIsConnected(true);
|
|
218
|
-
setError(null);
|
|
219
|
-
retryCountRef.current = 0;
|
|
220
|
-
settle(true);
|
|
221
245
|
};
|
|
222
246
|
ws.onmessage = (ev) => {
|
|
223
|
-
if (!mountedRef.current) return;
|
|
247
|
+
if (!mountedRef.current || !isCurrentSocket()) return;
|
|
224
248
|
const data = ev.data;
|
|
225
249
|
let text;
|
|
226
250
|
if (typeof data === "string") {
|
|
@@ -231,7 +255,7 @@ function usePtySession({
|
|
|
231
255
|
text = new TextDecoder().decode(data);
|
|
232
256
|
} else {
|
|
233
257
|
data.text().then((t) => {
|
|
234
|
-
if (mountedRef.current) onDataRef.current(t);
|
|
258
|
+
if (mountedRef.current && isCurrentSocket()) onDataRef.current(t);
|
|
235
259
|
}).catch(() => {
|
|
236
260
|
});
|
|
237
261
|
return;
|
|
@@ -239,17 +263,38 @@ function usePtySession({
|
|
|
239
263
|
if (typeof data === "string") {
|
|
240
264
|
try {
|
|
241
265
|
const event = JSON.parse(text);
|
|
242
|
-
if (event
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
266
|
+
if (event !== null && typeof event === "object" && !Array.isArray(event)) {
|
|
267
|
+
const controlFrame = event;
|
|
268
|
+
switch (controlFrame.type) {
|
|
269
|
+
case "ready":
|
|
270
|
+
transportReadyRef.current = true;
|
|
271
|
+
setIsConnected(true);
|
|
272
|
+
setError(null);
|
|
273
|
+
retryCountRef.current = 0;
|
|
274
|
+
settle(true);
|
|
275
|
+
return;
|
|
276
|
+
case "error": {
|
|
277
|
+
const message = typeof controlFrame.message === "string" ? controlFrame.message : "Terminal WebSocket error";
|
|
278
|
+
if (!transportReadyRef.current) {
|
|
279
|
+
failProtocol(message);
|
|
280
|
+
} else {
|
|
281
|
+
setError(message);
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
case "exit":
|
|
286
|
+
transportReadyRef.current = false;
|
|
287
|
+
setIsConnected(false);
|
|
288
|
+
return;
|
|
289
|
+
case "rec":
|
|
290
|
+
case "rec.done":
|
|
291
|
+
return;
|
|
292
|
+
default: {
|
|
293
|
+
const frameType = typeof controlFrame.type === "string" ? controlFrame.type : "<missing type>";
|
|
294
|
+
failProtocol(`Unknown terminal control frame: ${frameType}`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
253
298
|
}
|
|
254
299
|
} catch {
|
|
255
300
|
}
|
|
@@ -263,6 +308,7 @@ function usePtySession({
|
|
|
263
308
|
pendingWsRef.current = null;
|
|
264
309
|
}
|
|
265
310
|
const wasActive = wsRef.current === ws;
|
|
311
|
+
const wasReady = wasActive && transportReadyRef.current;
|
|
266
312
|
if (wasActive) {
|
|
267
313
|
wsRef.current = null;
|
|
268
314
|
transportReadyRef.current = false;
|
|
@@ -271,7 +317,11 @@ function usePtySession({
|
|
|
271
317
|
settle(false);
|
|
272
318
|
return;
|
|
273
319
|
}
|
|
274
|
-
if (!
|
|
320
|
+
if (!wasReady) {
|
|
321
|
+
settle(false);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (protocolFailureRef.current || !wasActive || !mountedRef.current) return;
|
|
275
325
|
setIsConnected(false);
|
|
276
326
|
if (sessionIdRef.current) {
|
|
277
327
|
retryTimerRef.current = setTimeout(() => {
|
|
@@ -286,7 +336,7 @@ function usePtySession({
|
|
|
286
336
|
}
|
|
287
337
|
};
|
|
288
338
|
});
|
|
289
|
-
}, [apiUrl]);
|
|
339
|
+
}, [apiUrl, rejectPendingInput]);
|
|
290
340
|
const connectStream = useCallback(async (sessionId) => {
|
|
291
341
|
if (exactAttachRequiredRef.current) {
|
|
292
342
|
throw new Error(
|
|
@@ -384,9 +434,11 @@ function usePtySession({
|
|
|
384
434
|
controlRef.current = control;
|
|
385
435
|
exactAttachRequiredRef.current = incarnationId !== void 0 || control !== void 0;
|
|
386
436
|
connectStreamRef.current = connectStream;
|
|
437
|
+
const exactIdentityKey = interactiveIdentityKey(incarnationId, control);
|
|
387
438
|
const connect = useCallback(async () => {
|
|
388
439
|
cleanup();
|
|
389
440
|
const myGen = ++connectGenRef.current;
|
|
441
|
+
protocolFailureRef.current = false;
|
|
390
442
|
retryCountRef.current = 0;
|
|
391
443
|
setError(null);
|
|
392
444
|
if (exactAttachRequiredRef.current && (!incarnationIdRef.current || !controlRef.current)) {
|
|
@@ -402,6 +454,7 @@ function usePtySession({
|
|
|
402
454
|
inputAbortRef.current = new AbortController();
|
|
403
455
|
const directWsOk = await connectWs(connectionId, { initOnOpen: true });
|
|
404
456
|
if (!mountedRef.current || connectGenRef.current !== myGen) return;
|
|
457
|
+
if (protocolFailureRef.current) return;
|
|
405
458
|
ensureDrainRunningRef.current?.();
|
|
406
459
|
if (directWsOk) {
|
|
407
460
|
return;
|
|
@@ -442,6 +495,7 @@ function usePtySession({
|
|
|
442
495
|
inputAbortRef.current = new AbortController();
|
|
443
496
|
const wsOk = await connectWs(sessionId, { initOnOpen: true });
|
|
444
497
|
if (!mountedRef.current || connectGenRef.current !== myGen) return;
|
|
498
|
+
if (protocolFailureRef.current) return;
|
|
445
499
|
ensureDrainRunningRef.current?.();
|
|
446
500
|
if (wsOk) {
|
|
447
501
|
return;
|
|
@@ -456,7 +510,14 @@ function usePtySession({
|
|
|
456
510
|
setIsConnected(false);
|
|
457
511
|
}
|
|
458
512
|
}
|
|
459
|
-
}, [
|
|
513
|
+
}, [
|
|
514
|
+
apiUrl,
|
|
515
|
+
providedConnectionId,
|
|
516
|
+
cleanup,
|
|
517
|
+
connectWs,
|
|
518
|
+
connectStream,
|
|
519
|
+
exactIdentityKey
|
|
520
|
+
]);
|
|
460
521
|
reconnectRef.current = connect;
|
|
461
522
|
const resizeTerminal = useCallback(async (cols, rows) => {
|
|
462
523
|
if (cols > 0) colsRef.current = cols;
|
|
@@ -564,6 +625,10 @@ function usePtySession({
|
|
|
564
625
|
resolve();
|
|
565
626
|
return;
|
|
566
627
|
}
|
|
628
|
+
if (protocolFailureRef.current) {
|
|
629
|
+
reject(new Error("Terminal protocol failure"));
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
567
632
|
pendingBatchRef.current.data += command;
|
|
568
633
|
pendingBatchRef.current.waiters.push({ resolve, reject });
|
|
569
634
|
ensureDrainRunning();
|
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
|
|
55
|
-
* errors before
|
|
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
package/dist/index.js
CHANGED
|
@@ -153,7 +153,7 @@ import {
|
|
|
153
153
|
buildUnifiedPatch,
|
|
154
154
|
computeDiffStats,
|
|
155
155
|
resolveLanguage
|
|
156
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-X24MVW2R.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-
|
|
241
|
+
import "./chunk-LWSWKLI5.js";
|
|
242
242
|
import {
|
|
243
243
|
usePtySession
|
|
244
|
-
} from "./chunk-
|
|
244
|
+
} from "./chunk-F7LNWZQR.js";
|
|
245
245
|
import {
|
|
246
246
|
Avatar,
|
|
247
247
|
AvatarFallback,
|
package/dist/terminal.js
CHANGED
package/dist/workbench.js
CHANGED
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
buildUnifiedPatch,
|
|
13
13
|
computeDiffStats,
|
|
14
14
|
resolveLanguage
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-X24MVW2R.js";
|
|
16
16
|
import "./chunk-PZVUIUUW.js";
|
|
17
17
|
import "./chunk-K4Q4E7D7.js";
|
|
18
18
|
import "./chunk-OMUIPJQZ.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-LWSWKLI5.js";
|
|
20
|
+
import "./chunk-F7LNWZQR.js";
|
|
21
21
|
import "./chunk-2XPJ2XF7.js";
|
|
22
22
|
import "./chunk-RQZRXKMR.js";
|
|
23
23
|
import "./chunk-BGVEHENC.js";
|
package/package.json
CHANGED