@tangle-network/sandbox 0.11.1-develop.20260718152243.786d70a → 0.11.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.
- package/README.md +16 -39
- package/dist/agent/index.d.ts +3 -3
- package/dist/{client-zbqfunVS.d.ts → client-DBioX_CL.d.ts} +2 -2
- package/dist/{client-BPKkPBc0.js → client-D_67csnK.js} +6 -14
- package/dist/core.d.ts +3 -3
- package/dist/core.js +2 -2
- package/dist/{index-Cy9eyvmJ.d.ts → index-Dj8LzvId.d.ts} +2 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.js +6 -6
- package/dist/{runtime-api-fqaQ3CN2.js → runtime-api-kukaWPtF.js} +4 -4
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/dist/{sandbox-Bv_ZM6OW.d.ts → sandbox-BRoxCvpS.d.ts} +22 -71
- package/dist/{sandbox-BfmGTfbd.js → sandbox-DaLPTCRA.js} +23 -105
- package/dist/session-gateway/index.d.ts +13 -82
- package/dist/session-gateway/index.js +144 -343
- package/dist/tangle/index.d.ts +1 -1
- package/dist/tangle/index.js +1 -1
- package/dist/{tangle-DuiNiJxp.js → tangle-DHOkbr5a.js} +3 -3
- package/dist/{types-C5sMDbeg.d.ts → types-D2C72ySk.d.ts} +26 -75
- package/package.json +1 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as normalizeRuntimeBackendConfig, n as normalizeSessionInfo, o as combineAbortSignals, r as uploadChunked, s as encodePromptForWire, t as SandboxRuntimeApi
|
|
1
|
+
import { l as normalizeRuntimeBackendConfig, n as normalizeSessionInfo, o as combineAbortSignals, r as uploadChunked, s as encodePromptForWire, t as SandboxRuntimeApi } from "./runtime-api-kukaWPtF.js";
|
|
2
2
|
import { c as SandboxError, d as TimeoutError, f as ValidationError, i as NetworkError, l as ServerError, n as CapabilityError, p as parseErrorResponse, s as QuotaError, t as AuthError, u as StateError } from "./errors-Cbs78OlF.js";
|
|
3
3
|
import { addTokenUsage, readTokenCostUsd, readTokenUsage } from "@tangle-network/agent-core";
|
|
4
4
|
//#region src/lib/sse-parser.ts
|
|
@@ -434,8 +434,8 @@ var InteractiveSessionHandle = class {
|
|
|
434
434
|
/**
|
|
435
435
|
* Spawn the harness's interactive TUI for this session. Returns the
|
|
436
436
|
* `streamUrl` to attach a terminal client to. Throws if the harness has no
|
|
437
|
-
* interactive entrypoint (e.g.
|
|
438
|
-
*
|
|
437
|
+
* interactive entrypoint (e.g. opencode), the binary is not installed, or a
|
|
438
|
+
* session is already running for this id.
|
|
439
439
|
*/
|
|
440
440
|
start(options) {
|
|
441
441
|
return this.host._startInteractive(this.sessionId, options);
|
|
@@ -444,16 +444,6 @@ var InteractiveSessionHandle = class {
|
|
|
444
444
|
sendPrompt(prompt) {
|
|
445
445
|
return this.host._sendInteractivePrompt(this.sessionId, prompt);
|
|
446
446
|
}
|
|
447
|
-
/**
|
|
448
|
-
* Observe the session: running, exited (with its exit code), or `null`
|
|
449
|
-
* when the sidecar no longer knows the id. Poll this to detect completion —
|
|
450
|
-
* an interactive session has no structured result stream, so the exit
|
|
451
|
-
* tombstone is the completion signal.
|
|
452
|
-
*/
|
|
453
|
-
status() {
|
|
454
|
-
if (!this.host._interactiveStatus) return Promise.reject(/* @__PURE__ */ new Error("Interactive session status is not supported by this host"));
|
|
455
|
-
return this.host._interactiveStatus(this.sessionId);
|
|
456
|
-
}
|
|
457
447
|
/** Stop the interactive harness and reap its PTY. */
|
|
458
448
|
stop() {
|
|
459
449
|
return this.host._stopInteractive(this.sessionId);
|
|
@@ -745,10 +735,6 @@ const SNAPSHOT_RESTORE_POLL_INTERVAL_MS = 1e3;
|
|
|
745
735
|
const SNAPSHOT_RESTORE_TIMEOUT_MS = 600 * 1e3;
|
|
746
736
|
const SNAPSHOT_VISIBILITY_POLL_INTERVAL_MS = 1e3;
|
|
747
737
|
const SNAPSHOT_VISIBILITY_TIMEOUT_MS = 120 * 1e3;
|
|
748
|
-
const EXEC_DEFAULT_TIMEOUT_MS = 3e4;
|
|
749
|
-
const EXEC_MIN_TIMEOUT_MS = 100;
|
|
750
|
-
const EXEC_MAX_TIMEOUT_MS = 6e5;
|
|
751
|
-
const EXEC_TRANSPORT_MARGIN_MS = 15e3;
|
|
752
738
|
const SNAPSHOT_CREATE_REQUEST_TIMEOUT_MS = 600 * 1e3;
|
|
753
739
|
function toSnapshotResult(data) {
|
|
754
740
|
return {
|
|
@@ -965,14 +951,6 @@ function parseTextFileReadResponse(body) {
|
|
|
965
951
|
return payload.data.content;
|
|
966
952
|
}
|
|
967
953
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
968
|
-
const SANDBOX_STATUS_FRESHNESS_MS = 1e3;
|
|
969
|
-
const sandboxStatusObservedAt = /* @__PURE__ */ new WeakMap();
|
|
970
|
-
const directRuntimeInstances = /* @__PURE__ */ new WeakSet();
|
|
971
|
-
function createSandboxInstanceFromResponse(client, info, defaultRuntimeBackend) {
|
|
972
|
-
const instance = new SandboxInstance(client, info, defaultRuntimeBackend);
|
|
973
|
-
sandboxStatusObservedAt.set(instance, Date.now());
|
|
974
|
-
return instance;
|
|
975
|
-
}
|
|
976
954
|
/** Transient file-write failures worth retrying: rate-limit (quota), 5xx,
|
|
977
955
|
* transport (network), and request timeouts. A non-transient error (bad path,
|
|
978
956
|
* auth, validation) fails loud immediately. */
|
|
@@ -985,7 +963,6 @@ function isTransientWriteError(err) {
|
|
|
985
963
|
var SandboxInstance = class SandboxInstance {
|
|
986
964
|
client;
|
|
987
965
|
info;
|
|
988
|
-
refreshInFlight;
|
|
989
966
|
defaultRuntimeBackend;
|
|
990
967
|
runtime;
|
|
991
968
|
constructor(client, info, defaultRuntimeBackend) {
|
|
@@ -1118,7 +1095,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
1118
1095
|
const client = this.client;
|
|
1119
1096
|
if (next && typeof client._emitTokenRefresh === "function") client._emitTokenRefresh(this.id, next);
|
|
1120
1097
|
}), { ...this.info }, this.defaultRuntimeBackend);
|
|
1121
|
-
directRuntimeInstances.add(directInstance);
|
|
1122
1098
|
return directInstance;
|
|
1123
1099
|
}
|
|
1124
1100
|
/**
|
|
@@ -1158,19 +1134,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
1158
1134
|
* Refresh sandbox information from the server.
|
|
1159
1135
|
*/
|
|
1160
1136
|
async refresh() {
|
|
1161
|
-
if (this.refreshInFlight) {
|
|
1162
|
-
await this.refreshInFlight;
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
const refresh = this.refreshInfo();
|
|
1166
|
-
this.refreshInFlight = refresh;
|
|
1167
|
-
try {
|
|
1168
|
-
await refresh;
|
|
1169
|
-
} finally {
|
|
1170
|
-
if (this.refreshInFlight === refresh) this.refreshInFlight = void 0;
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
async refreshInfo() {
|
|
1174
1137
|
const response = await this.client.fetch(`/v1/sandboxes/${this.id}`);
|
|
1175
1138
|
if (!response.ok) {
|
|
1176
1139
|
const body = await response.text();
|
|
@@ -1178,7 +1141,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
1178
1141
|
}
|
|
1179
1142
|
const data = await response.json();
|
|
1180
1143
|
this.info = this.parseInfo(data);
|
|
1181
|
-
sandboxStatusObservedAt.set(this, Date.now());
|
|
1182
1144
|
}
|
|
1183
1145
|
/**
|
|
1184
1146
|
* Fetch fresh TEE attestation evidence for this sandbox.
|
|
@@ -1308,31 +1270,28 @@ var SandboxInstance = class SandboxInstance {
|
|
|
1308
1270
|
*/
|
|
1309
1271
|
async exec(command, options) {
|
|
1310
1272
|
await this.ensureRunning();
|
|
1311
|
-
const timeoutMs = options?.timeoutMs ?? EXEC_DEFAULT_TIMEOUT_MS;
|
|
1312
|
-
if (!Number.isInteger(timeoutMs) || timeoutMs < EXEC_MIN_TIMEOUT_MS || timeoutMs > EXEC_MAX_TIMEOUT_MS) throw new ValidationError(`exec timeoutMs must be an integer between ${EXEC_MIN_TIMEOUT_MS} and ${EXEC_MAX_TIMEOUT_MS}`);
|
|
1313
1273
|
const headers = {};
|
|
1314
1274
|
if (options?.sessionId) headers["X-Session-Id"] = options.sessionId;
|
|
1315
|
-
const response = await this.runtimeFetch("/
|
|
1275
|
+
const response = await this.runtimeFetch("/terminals/commands", {
|
|
1316
1276
|
method: "POST",
|
|
1317
1277
|
headers,
|
|
1318
1278
|
body: JSON.stringify({
|
|
1319
1279
|
command,
|
|
1320
1280
|
cwd: options?.cwd,
|
|
1321
1281
|
env: options?.env,
|
|
1322
|
-
timeoutMs
|
|
1323
|
-
blocking: true
|
|
1282
|
+
timeout: options?.timeoutMs
|
|
1324
1283
|
})
|
|
1325
|
-
}
|
|
1284
|
+
});
|
|
1326
1285
|
if (!response.ok) {
|
|
1327
1286
|
const body = await response.text();
|
|
1328
1287
|
throw parseErrorResponse(response.status, body, void 0, response.headers);
|
|
1329
1288
|
}
|
|
1330
|
-
const
|
|
1331
|
-
|
|
1289
|
+
const data = await response.json();
|
|
1290
|
+
const result = data.result ?? data;
|
|
1332
1291
|
return {
|
|
1333
|
-
exitCode: result.exitCode,
|
|
1334
|
-
stdout: result.stdout,
|
|
1335
|
-
stderr: result.stderr
|
|
1292
|
+
exitCode: result.exitCode ?? 0,
|
|
1293
|
+
stdout: result.stdout ?? "",
|
|
1294
|
+
stderr: result.stderr ?? ""
|
|
1336
1295
|
};
|
|
1337
1296
|
}
|
|
1338
1297
|
/**
|
|
@@ -1690,8 +1649,7 @@ var SandboxInstance = class SandboxInstance {
|
|
|
1690
1649
|
requireVisibleAssistantOutput: options?.requireVisibleAssistantOutput,
|
|
1691
1650
|
...timeoutMs ? { timeoutMs } : {},
|
|
1692
1651
|
...options?.detach ? { detach: true } : {},
|
|
1693
|
-
backend: normalizeRuntimeBackendConfig(options?.backend ?? this.defaultRuntimeBackend)
|
|
1694
|
-
...options?.model ? { model: normalizeRuntimeModelOverride(options.model) } : {}
|
|
1652
|
+
backend: normalizeRuntimeBackendConfig(options?.backend ?? this.defaultRuntimeBackend, { model: options?.model })
|
|
1695
1653
|
})
|
|
1696
1654
|
};
|
|
1697
1655
|
response = await this.runtimeFetch(requestEndpoint, request);
|
|
@@ -3046,7 +3004,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
3046
3004
|
*/
|
|
3047
3005
|
get process() {
|
|
3048
3006
|
return {
|
|
3049
|
-
ensureDevServer: (options) => this.processEnsureDevServer(options),
|
|
3050
3007
|
spawn: (command, options) => this.processSpawn(command, options),
|
|
3051
3008
|
spawnExact: (executable, args, options) => this.processSpawnExact(executable, args, options),
|
|
3052
3009
|
runCode: (code, options) => this.processRunCode(code, options),
|
|
@@ -3054,26 +3011,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
3054
3011
|
get: (pid) => this.processGet(pid)
|
|
3055
3012
|
};
|
|
3056
3013
|
}
|
|
3057
|
-
async processEnsureDevServer(options) {
|
|
3058
|
-
if (options?.sessionId !== void 0) assertValidSessionId(options.sessionId);
|
|
3059
|
-
if (options?.cwd !== void 0 && (typeof options.cwd !== "string" || options.cwd.trim().length === 0)) throw new ValidationError("Dev server cwd must be a non-empty string");
|
|
3060
|
-
await this.ensureRunning();
|
|
3061
|
-
const headers = options?.sessionId ? { "X-Session-Id": options.sessionId } : void 0;
|
|
3062
|
-
const response = await this.runtimeFetch("/process/ensure-dev-server", {
|
|
3063
|
-
method: "POST",
|
|
3064
|
-
headers,
|
|
3065
|
-
body: JSON.stringify(options?.cwd ? { cwd: options.cwd } : {})
|
|
3066
|
-
});
|
|
3067
|
-
if (!response.ok) {
|
|
3068
|
-
const body = await response.text();
|
|
3069
|
-
throw parseErrorResponse(response.status, body, void 0, response.headers);
|
|
3070
|
-
}
|
|
3071
|
-
const payload = await response.json();
|
|
3072
|
-
return {
|
|
3073
|
-
...payload.data,
|
|
3074
|
-
startedAt: new Date(payload.data.startedAt)
|
|
3075
|
-
};
|
|
3076
|
-
}
|
|
3077
3014
|
async processSpawn(command, options) {
|
|
3078
3015
|
await this.ensureRunning();
|
|
3079
3016
|
const response = await this.runtimeFetch("/process/spawn", {
|
|
@@ -3102,7 +3039,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
3102
3039
|
args,
|
|
3103
3040
|
cwd: options?.cwd,
|
|
3104
3041
|
env: options?.env,
|
|
3105
|
-
inheritEnv: options?.inheritEnv,
|
|
3106
3042
|
timeoutMs: options?.timeoutMs,
|
|
3107
3043
|
stdin: options?.stdin,
|
|
3108
3044
|
blocking: false
|
|
@@ -3893,7 +3829,7 @@ var SandboxInstance = class SandboxInstance {
|
|
|
3893
3829
|
const body = await response.text();
|
|
3894
3830
|
throw parseErrorResponse(response.status, body, void 0, response.headers);
|
|
3895
3831
|
}
|
|
3896
|
-
return ((await response.json()).children ?? []).map((child) =>
|
|
3832
|
+
return ((await response.json()).children ?? []).map((child) => new SandboxInstance(this.client, this.parseInfo(child), this.defaultRuntimeBackend));
|
|
3897
3833
|
}
|
|
3898
3834
|
/**
|
|
3899
3835
|
* Speculative rollouts: branch this RUNNING sandbox into `n` copy-on-write
|
|
@@ -4026,7 +3962,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
4026
3962
|
}
|
|
4027
3963
|
const diagnostics = await this.readLifecycleDiagnostics(response);
|
|
4028
3964
|
if (diagnostics) this.info.startupDiagnostics = diagnostics;
|
|
4029
|
-
sandboxStatusObservedAt.delete(this);
|
|
4030
3965
|
}
|
|
4031
3966
|
/**
|
|
4032
3967
|
* Read the per-phase lifecycle breakdown off a stop/resume/delete response
|
|
@@ -4235,15 +4170,12 @@ var SandboxInstance = class SandboxInstance {
|
|
|
4235
4170
|
}
|
|
4236
4171
|
}
|
|
4237
4172
|
async ensureRunning() {
|
|
4238
|
-
|
|
4239
|
-
const statusAgeMs = Date.now() - statusObservedAt;
|
|
4240
|
-
if (directRuntimeInstances.has(this) || statusObservedAt <= 0 || statusAgeMs < 0 || statusAgeMs >= SANDBOX_STATUS_FRESHNESS_MS) await this.refresh();
|
|
4173
|
+
await this.refresh();
|
|
4241
4174
|
if (this.status !== "running") throw new StateError(`Sandbox is not running (status: ${this.status})`, this.status, "running");
|
|
4242
4175
|
}
|
|
4243
|
-
async runtimeFetch(path, options
|
|
4176
|
+
async runtimeFetch(path, options) {
|
|
4244
4177
|
const url = `/v1/sandboxes/${encodeURIComponent(this.id)}/runtime${path}`;
|
|
4245
4178
|
try {
|
|
4246
|
-
if (fetchOptions) return await this.client.fetch(url, options, fetchOptions);
|
|
4247
4179
|
return options ? await this.client.fetch(url, options) : await this.client.fetch(url);
|
|
4248
4180
|
} catch (err) {
|
|
4249
4181
|
throw new NetworkError(`Failed to connect to sandbox: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0, {
|
|
@@ -4281,16 +4213,17 @@ var SandboxInstance = class SandboxInstance {
|
|
|
4281
4213
|
* ```typescript
|
|
4282
4214
|
* await box.registerSessionMapping({
|
|
4283
4215
|
* sessionId: "sess_abc",
|
|
4284
|
-
*
|
|
4216
|
+
* userId: "user_123",
|
|
4285
4217
|
* });
|
|
4286
4218
|
* ```
|
|
4287
4219
|
*/
|
|
4288
4220
|
async registerSessionMapping(opts) {
|
|
4289
4221
|
const response = await this.client.fetch(`/v1/session/${encodeURIComponent(opts.sessionId)}/mapping`, {
|
|
4290
4222
|
method: "PUT",
|
|
4223
|
+
headers: { "x-user-id": opts.userId },
|
|
4291
4224
|
body: JSON.stringify({
|
|
4292
4225
|
sidecarSessionId: opts.runtimeSessionId,
|
|
4293
|
-
sidecarId: opts.sidecarId
|
|
4226
|
+
...opts.sidecarId ? { sidecarId: opts.sidecarId } : {},
|
|
4294
4227
|
...opts.projectRef ? { projectRef: opts.projectRef } : {}
|
|
4295
4228
|
})
|
|
4296
4229
|
});
|
|
@@ -4319,7 +4252,10 @@ var SandboxInstance = class SandboxInstance {
|
|
|
4319
4252
|
* sandbox stays alive.
|
|
4320
4253
|
*/
|
|
4321
4254
|
async unregisterSessionMapping(opts) {
|
|
4322
|
-
const response = await this.client.fetch(`/v1/session/${encodeURIComponent(opts.sessionId)}/mapping`, {
|
|
4255
|
+
const response = await this.client.fetch(`/v1/session/${encodeURIComponent(opts.sessionId)}/mapping`, {
|
|
4256
|
+
method: "DELETE",
|
|
4257
|
+
headers: { "x-user-id": opts.userId }
|
|
4258
|
+
});
|
|
4323
4259
|
if (!response.ok) {
|
|
4324
4260
|
const body = await response.text();
|
|
4325
4261
|
throw parseErrorResponse(response.status, body, void 0, response.headers);
|
|
@@ -4601,14 +4537,12 @@ var SandboxInstance = class SandboxInstance {
|
|
|
4601
4537
|
*/
|
|
4602
4538
|
async mintScopedToken(opts) {
|
|
4603
4539
|
if ((opts.scope === "session" || opts.scope === "session-runtime") && !opts.sessionId) throw new ValidationError(`${opts.scope} scope requires a sessionId`);
|
|
4604
|
-
if (opts.scope === "session" && !opts.runtimeSessionId) throw new ValidationError("session scope requires the actual runtimeSessionId");
|
|
4605
4540
|
const response = await this.client.fetch(`/v1/sandboxes/${encodeURIComponent(this.id)}/scoped-token`, {
|
|
4606
4541
|
method: "POST",
|
|
4607
4542
|
headers: { "Content-Type": "application/json" },
|
|
4608
4543
|
body: JSON.stringify({
|
|
4609
4544
|
scope: opts.scope,
|
|
4610
4545
|
...opts.sessionId ? { sessionId: opts.sessionId } : {},
|
|
4611
|
-
...opts.scope === "session" ? { runtimeSessionId: opts.runtimeSessionId } : {},
|
|
4612
4546
|
...opts.ttlMinutes ? { ttlMinutes: opts.ttlMinutes } : {}
|
|
4613
4547
|
})
|
|
4614
4548
|
});
|
|
@@ -4758,22 +4692,6 @@ var SandboxInstance = class SandboxInstance {
|
|
|
4758
4692
|
throw parseErrorResponse(response.status, body, void 0, response.headers);
|
|
4759
4693
|
}
|
|
4760
4694
|
}
|
|
4761
|
-
/** @internal — invoked by InteractiveSessionHandle.status(). */
|
|
4762
|
-
async _interactiveStatus(id) {
|
|
4763
|
-
await this.ensureRunning();
|
|
4764
|
-
const response = await this.runtimeFetch(`/agents/sessions/${encodeURIComponent(id)}/interactive`, { method: "GET" });
|
|
4765
|
-
if (response.status === 404) return null;
|
|
4766
|
-
if (!response.ok) {
|
|
4767
|
-
const body = await response.text();
|
|
4768
|
-
throw parseErrorResponse(response.status, body, void 0, response.headers);
|
|
4769
|
-
}
|
|
4770
|
-
const data = (await response.json())?.data;
|
|
4771
|
-
if (!data || data.state !== "running" && data.state !== "exited") throw new ServerError("Interactive status response missing data", 502, {
|
|
4772
|
-
endpoint: `/agents/sessions/${encodeURIComponent(id)}/interactive`,
|
|
4773
|
-
origin: "runtime"
|
|
4774
|
-
});
|
|
4775
|
-
return data;
|
|
4776
|
-
}
|
|
4777
4695
|
/** @internal — invoked by InteractiveSessionHandle.stop(). */
|
|
4778
4696
|
async _stopInteractive(id) {
|
|
4779
4697
|
await this.ensureRunning();
|
|
@@ -4983,4 +4901,4 @@ function quoteForShell(value) {
|
|
|
4983
4901
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
4984
4902
|
}
|
|
4985
4903
|
//#endregion
|
|
4986
|
-
export {
|
|
4904
|
+
export { InteractiveSessionHandle as a, getSandboxEventText as c, exportTraceBundle as d, otelTraceIdForTangleTrace as f, SandboxSession as i, normalizeConnection as l, parseSSEStream as m, normalizeStartupDiagnostics as n, applySandboxEventText as o, toOtelJson as p, SandboxTaskSession as r, collectAgentResponseText as s, SandboxInstance as t, buildTraceExportPayload as u };
|
|
@@ -40,24 +40,16 @@ interface ReplayOptions {
|
|
|
40
40
|
lastEventId?: string;
|
|
41
41
|
/** Execution ID to replay events for */
|
|
42
42
|
executionId?: string;
|
|
43
|
-
/**
|
|
43
|
+
/** Session ID context for replay */
|
|
44
44
|
sessionId?: string;
|
|
45
45
|
}
|
|
46
|
-
interface SubscriptionDenial {
|
|
47
|
-
channel: string;
|
|
48
|
-
reason: string;
|
|
49
|
-
}
|
|
50
|
-
interface SubscriptionAcknowledgement {
|
|
51
|
-
channels: string[];
|
|
52
|
-
denied?: SubscriptionDenial[];
|
|
53
|
-
}
|
|
54
46
|
/**
|
|
55
47
|
* Base fields present on all server messages.
|
|
56
48
|
*/
|
|
57
49
|
interface ServerMessageBase {
|
|
58
50
|
id?: string;
|
|
59
51
|
timestamp?: number;
|
|
60
|
-
/** Monotonic
|
|
52
|
+
/** Monotonic sequence number for gap detection (per session) */
|
|
61
53
|
seq?: number;
|
|
62
54
|
}
|
|
63
55
|
/**
|
|
@@ -68,11 +60,12 @@ type ServerMessage = (ServerMessageBase & {
|
|
|
68
60
|
messageType?: string;
|
|
69
61
|
data: {
|
|
70
62
|
sessionId: string;
|
|
71
|
-
hydratedCount?: number;
|
|
72
63
|
};
|
|
73
64
|
}) | (ServerMessageBase & {
|
|
74
65
|
type: "subscribed";
|
|
75
|
-
data:
|
|
66
|
+
data: {
|
|
67
|
+
channels: string[];
|
|
68
|
+
};
|
|
76
69
|
}) | (ServerMessageBase & {
|
|
77
70
|
type: "unsubscribed";
|
|
78
71
|
data: {
|
|
@@ -93,19 +86,6 @@ type ServerMessage = (ServerMessageBase & {
|
|
|
93
86
|
sandboxId: string;
|
|
94
87
|
error?: string;
|
|
95
88
|
};
|
|
96
|
-
}) | (ServerMessageBase & {
|
|
97
|
-
type: "runtime.reconnecting";
|
|
98
|
-
data: {
|
|
99
|
-
sandboxId: string;
|
|
100
|
-
attempt: number;
|
|
101
|
-
delayMs: number;
|
|
102
|
-
};
|
|
103
|
-
}) | (ServerMessageBase & {
|
|
104
|
-
type: "runtime.removed";
|
|
105
|
-
data: {
|
|
106
|
-
sandboxId: string;
|
|
107
|
-
reason: string;
|
|
108
|
-
};
|
|
109
89
|
}) | (ServerMessageBase & {
|
|
110
90
|
type: "runtime.not_found";
|
|
111
91
|
data: {
|
|
@@ -142,7 +122,7 @@ type ServerMessage = (ServerMessageBase & {
|
|
|
142
122
|
}) | (ServerMessageBase & {
|
|
143
123
|
type: "agent.event";
|
|
144
124
|
channel: string;
|
|
145
|
-
data: unknown;
|
|
125
|
+
data: unknown;
|
|
146
126
|
sequenceId?: number;
|
|
147
127
|
}) | (ServerMessageBase & {
|
|
148
128
|
type: "replay.start";
|
|
@@ -176,20 +156,6 @@ type ServerMessage = (ServerMessageBase & {
|
|
|
176
156
|
totalDropped: number; /** Hint that client should request a replay */
|
|
177
157
|
suggestReplay: boolean;
|
|
178
158
|
};
|
|
179
|
-
}) | (ServerMessageBase & {
|
|
180
|
-
type: "terminal.input.error";
|
|
181
|
-
data: {
|
|
182
|
-
terminalId: string;
|
|
183
|
-
code: string;
|
|
184
|
-
message: string;
|
|
185
|
-
};
|
|
186
|
-
}) | (ServerMessageBase & {
|
|
187
|
-
type: `project.${string}`;
|
|
188
|
-
channel?: string;
|
|
189
|
-
data: unknown;
|
|
190
|
-
}) | (ServerMessageBase & {
|
|
191
|
-
type: "heartbeat";
|
|
192
|
-
data?: unknown;
|
|
193
159
|
});
|
|
194
160
|
interface PortEventData {
|
|
195
161
|
type: "opened" | "closed";
|
|
@@ -197,30 +163,6 @@ interface PortEventData {
|
|
|
197
163
|
protocol: string;
|
|
198
164
|
processName?: string;
|
|
199
165
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Inbound WebSocket frame before normalization. The server may emit a
|
|
202
|
-
* legacy `messageType` discriminant instead of `type`, and may carry a
|
|
203
|
-
* top-level `channel` plus arbitrary extra fields. `handleMessage`
|
|
204
|
-
* normalizes a `RawWireMessage` into a `ServerMessage` before dispatch:
|
|
205
|
-
* `type` and `data` are mutable here because normalization rewrites them.
|
|
206
|
-
*/
|
|
207
|
-
interface RawWireMessage {
|
|
208
|
-
type?: string;
|
|
209
|
-
messageType?: string;
|
|
210
|
-
channel?: string;
|
|
211
|
-
data?: unknown;
|
|
212
|
-
id?: string;
|
|
213
|
-
message?: string;
|
|
214
|
-
code?: string;
|
|
215
|
-
timestamp?: number;
|
|
216
|
-
seq?: number;
|
|
217
|
-
sequenceId?: number;
|
|
218
|
-
[key: string]: unknown;
|
|
219
|
-
}
|
|
220
|
-
/** Every inbound frame after legacy names and sequence fields are normalized. */
|
|
221
|
-
interface NormalizedServerMessage extends RawWireMessage {
|
|
222
|
-
type: string;
|
|
223
|
-
}
|
|
224
166
|
/**
|
|
225
167
|
* Connection state for the WebSocket client.
|
|
226
168
|
*/
|
|
@@ -273,8 +215,6 @@ interface TokenRefreshResult {
|
|
|
273
215
|
* Event handlers for session gateway events.
|
|
274
216
|
*/
|
|
275
217
|
interface SessionGatewayEventHandlers {
|
|
276
|
-
/** Called after internal processing for every non-duplicate normalized frame. */
|
|
277
|
-
onMessage?: (message: NormalizedServerMessage) => void;
|
|
278
218
|
onConnect?: (sessionId: string) => void;
|
|
279
219
|
onDisconnect?: (code: number, reason: string) => void;
|
|
280
220
|
onReconnect?: () => void;
|
|
@@ -297,7 +237,7 @@ interface SessionGatewayEventHandlers {
|
|
|
297
237
|
}) => void;
|
|
298
238
|
onPortOpened?: (port: number, protocol: string, processName?: string) => void;
|
|
299
239
|
onPortClosed?: (port: number) => void;
|
|
300
|
-
onAgentEvent?: (channel: string, data: unknown,
|
|
240
|
+
onAgentEvent?: (channel: string, data: unknown, sequenceId?: number) => void;
|
|
301
241
|
onError?: (message: string, code?: string) => void;
|
|
302
242
|
onStateChange?: (state: ConnectionState) => void;
|
|
303
243
|
onMetricsChange?: (metrics: ConnectionMetrics) => void;
|
|
@@ -330,11 +270,11 @@ interface SessionGatewayClientConfig {
|
|
|
330
270
|
token: string;
|
|
331
271
|
/** Callback to refresh the token when it's about to expire */
|
|
332
272
|
onTokenRefresh?: () => Promise<TokenRefreshResult>;
|
|
333
|
-
/**
|
|
273
|
+
/** Session ID to connect to */
|
|
334
274
|
sessionId: string;
|
|
335
275
|
/** Transport mode (default: "websocket") */
|
|
336
276
|
transport?: TransportMode;
|
|
337
|
-
/**
|
|
277
|
+
/** Channels to subscribe to (default: ["*"]) */
|
|
338
278
|
channels?: string[];
|
|
339
279
|
/** Auto-reconnect on disconnect (default: true) */
|
|
340
280
|
autoReconnect?: boolean;
|
|
@@ -362,8 +302,6 @@ interface SessionGatewayClientConfig {
|
|
|
362
302
|
replayStorageKeyPrefix?: string;
|
|
363
303
|
/** Number of latency samples to track for averaging (default: 10) */
|
|
364
304
|
latencyHistorySize?: number;
|
|
365
|
-
/** Maximum wait for `connection.established` (default: 10000 ms) */
|
|
366
|
-
connectionEstablishmentTimeoutMs?: number;
|
|
367
305
|
/** Event handlers */
|
|
368
306
|
handlers?: SessionGatewayEventHandlers;
|
|
369
307
|
}
|
|
@@ -397,13 +335,11 @@ declare class SessionGatewayClient {
|
|
|
397
335
|
private ws;
|
|
398
336
|
private readonly config;
|
|
399
337
|
private readonly handlers;
|
|
400
|
-
private readonly replayStateStore;
|
|
401
|
-
private readonly tokenRefresher;
|
|
402
338
|
private currentToken;
|
|
339
|
+
private isRefreshingToken;
|
|
403
340
|
private state;
|
|
404
341
|
private connectedAt;
|
|
405
342
|
private hasConnectedBefore;
|
|
406
|
-
private connectionEstablishedForSocket;
|
|
407
343
|
private lastPingAt;
|
|
408
344
|
private lastPongAt;
|
|
409
345
|
private lastPingSentAt;
|
|
@@ -417,7 +353,6 @@ declare class SessionGatewayClient {
|
|
|
417
353
|
private pingInterval;
|
|
418
354
|
private pongTimeout;
|
|
419
355
|
private pendingCallbacks;
|
|
420
|
-
private readonly connectionWaiters;
|
|
421
356
|
private messageIdCounter;
|
|
422
357
|
private processedEventIds;
|
|
423
358
|
private pingLatencyHistory;
|
|
@@ -452,7 +387,7 @@ declare class SessionGatewayClient {
|
|
|
452
387
|
/**
|
|
453
388
|
* Request replay of events since a timestamp.
|
|
454
389
|
*/
|
|
455
|
-
replay(since: number):
|
|
390
|
+
replay(since: number): void;
|
|
456
391
|
/**
|
|
457
392
|
* Send terminal input via WebSocket.
|
|
458
393
|
*/
|
|
@@ -488,18 +423,14 @@ declare class SessionGatewayClient {
|
|
|
488
423
|
getToken(): string;
|
|
489
424
|
private setState;
|
|
490
425
|
private handleOpen;
|
|
491
|
-
private handleConnectionEstablished;
|
|
492
426
|
private handleClose;
|
|
493
|
-
private handleError;
|
|
494
|
-
private closeBeforeEstablishment;
|
|
495
427
|
private handleMessage;
|
|
496
428
|
private handlePong;
|
|
497
429
|
private dispatchMessage;
|
|
498
|
-
private deliverMessage;
|
|
499
430
|
private trackExecutionContext;
|
|
431
|
+
private handleTokenExpiring;
|
|
500
432
|
private send;
|
|
501
433
|
private sendWithResponse;
|
|
502
|
-
private waitForConnectionEstablished;
|
|
503
434
|
private restoreSubscriptions;
|
|
504
435
|
private startPingInterval;
|
|
505
436
|
private stopPingInterval;
|
|
@@ -514,4 +445,4 @@ declare class SessionGatewayClient {
|
|
|
514
445
|
private saveReplayState;
|
|
515
446
|
}
|
|
516
447
|
//#endregion
|
|
517
|
-
export { type ClientMessage, type ConnectionMetrics, type ConnectionQuality, type ConnectionState, INITIAL_METRICS, type
|
|
448
|
+
export { type ClientMessage, type ConnectionMetrics, type ConnectionQuality, type ConnectionState, INITIAL_METRICS, type PortEventData, type ReplayOptions, type ReplayState, type ReplayStateStorage, type ServerMessage, SessionGatewayClient, type SessionGatewayClientConfig, type SessionGatewayEventHandlers, type SessionGatewayStats, type TokenRefreshResult, type TransportMode, calculateConnectionQuality };
|