tensorlake 0.4.50 → 0.5.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/dist/bin/darwin-arm64/tensorlake +0 -0
- package/dist/bin/darwin-arm64/tl +0 -0
- package/dist/bin/linux-x64/tensorlake +0 -0
- package/dist/bin/linux-x64/tl +0 -0
- package/dist/bin/win32-x64/tensorlake.exe +0 -0
- package/dist/bin/win32-x64/tl.exe +0 -0
- package/dist/index.cjs +312 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +185 -8
- package/dist/index.d.ts +185 -8
- package/dist/index.js +312 -28
- package/dist/index.js.map +1 -1
- package/dist/{sandbox-image-C79FXqQk.d.cts → sandbox-image-CMJ_FOOV.d.cts} +17 -1
- package/dist/{sandbox-image-C79FXqQk.d.ts → sandbox-image-CMJ_FOOV.d.ts} +17 -1
- package/dist/sandbox-image.cjs +299 -15
- package/dist/sandbox-image.cjs.map +1 -1
- package/dist/sandbox-image.d.cts +1 -1
- package/dist/sandbox-image.d.ts +1 -1
- package/dist/sandbox-image.js +304 -15
- package/dist/sandbox-image.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,10 +9,11 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
// src/defaults.ts
|
|
12
|
-
var API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS, RETRYABLE_STATUS_CODES;
|
|
12
|
+
var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS, RETRYABLE_STATUS_CODES;
|
|
13
13
|
var init_defaults = __esm({
|
|
14
14
|
"src/defaults.ts"() {
|
|
15
15
|
"use strict";
|
|
16
|
+
SDK_VERSION = "0.4.49";
|
|
16
17
|
API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
|
|
17
18
|
API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
|
|
18
19
|
NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
|
|
@@ -115,6 +116,12 @@ import {
|
|
|
115
116
|
fetch as undiciFetch,
|
|
116
117
|
setGlobalDispatcher
|
|
117
118
|
} from "undici";
|
|
119
|
+
function withTraceId(value, traceId) {
|
|
120
|
+
if (value == null) {
|
|
121
|
+
return { traceId };
|
|
122
|
+
}
|
|
123
|
+
return Object.assign(value, { traceId });
|
|
124
|
+
}
|
|
118
125
|
function hasHeader(headers, name) {
|
|
119
126
|
const lowered = name.toLowerCase();
|
|
120
127
|
return Object.keys(headers).some((key) => key.toLowerCase() === lowered);
|
|
@@ -183,7 +190,7 @@ var init_http = __esm({
|
|
|
183
190
|
allowH2: true
|
|
184
191
|
})
|
|
185
192
|
);
|
|
186
|
-
HttpClient = class {
|
|
193
|
+
HttpClient = class _HttpClient {
|
|
187
194
|
baseUrl;
|
|
188
195
|
headers;
|
|
189
196
|
maxRetries;
|
|
@@ -196,7 +203,9 @@ var init_http = __esm({
|
|
|
196
203
|
this.maxRetries = options.maxRetries ?? MAX_RETRIES;
|
|
197
204
|
this.retryBackoffMs = options.retryBackoffMs ?? RETRY_BACKOFF_MS;
|
|
198
205
|
this.timeoutMs = options.timeoutMs ?? DEFAULT_HTTP_TIMEOUT_MS;
|
|
199
|
-
this.headers = {
|
|
206
|
+
this.headers = {
|
|
207
|
+
"User-Agent": `tensorlake-typescript-sdk/${SDK_VERSION}`
|
|
208
|
+
};
|
|
200
209
|
if (options.apiKey) {
|
|
201
210
|
this.headers["Authorization"] = `Bearer ${options.apiKey}`;
|
|
202
211
|
}
|
|
@@ -225,8 +234,8 @@ var init_http = __esm({
|
|
|
225
234
|
signal: options?.signal
|
|
226
235
|
});
|
|
227
236
|
const text = await response.text();
|
|
228
|
-
|
|
229
|
-
return
|
|
237
|
+
const data = text ? JSON.parse(text) : void 0;
|
|
238
|
+
return withTraceId(data, response.traceId);
|
|
230
239
|
}
|
|
231
240
|
/** Make a request returning raw bytes. */
|
|
232
241
|
async requestBytes(method, path2, options) {
|
|
@@ -240,7 +249,7 @@ var init_http = __esm({
|
|
|
240
249
|
signal: options?.signal
|
|
241
250
|
});
|
|
242
251
|
const buffer = await response.arrayBuffer();
|
|
243
|
-
return new Uint8Array(buffer);
|
|
252
|
+
return withTraceId(new Uint8Array(buffer), response.traceId);
|
|
244
253
|
}
|
|
245
254
|
/** Make a request and return the response body as an SSE stream. */
|
|
246
255
|
async requestStream(method, path2, options) {
|
|
@@ -255,7 +264,7 @@ var init_http = __esm({
|
|
|
255
264
|
"No response body for SSE stream"
|
|
256
265
|
);
|
|
257
266
|
}
|
|
258
|
-
return response.body;
|
|
267
|
+
return withTraceId(response.body, response.traceId);
|
|
259
268
|
}
|
|
260
269
|
/** Make a request and return the raw Response. */
|
|
261
270
|
async requestResponse(method, path2, options) {
|
|
@@ -268,7 +277,7 @@ var init_http = __esm({
|
|
|
268
277
|
headers["Content-Type"] = "application/json";
|
|
269
278
|
}
|
|
270
279
|
const body = hasJsonBody ? JSON.stringify(options?.json) : normalizeRequestBody(options?.body);
|
|
271
|
-
|
|
280
|
+
const { response, traceId } = await this.doFetch(
|
|
272
281
|
method,
|
|
273
282
|
path2,
|
|
274
283
|
body,
|
|
@@ -276,9 +285,18 @@ var init_http = __esm({
|
|
|
276
285
|
options?.signal,
|
|
277
286
|
options?.allowHttpErrors ?? false
|
|
278
287
|
);
|
|
288
|
+
return withTraceId(response, traceId);
|
|
289
|
+
}
|
|
290
|
+
static makeTraceparent() {
|
|
291
|
+
const randomHex = (bytes) => Array.from(crypto.getRandomValues(new Uint8Array(bytes))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
292
|
+
const traceId = randomHex(16);
|
|
293
|
+
const spanId = randomHex(8);
|
|
294
|
+
return { traceparent: `00-${traceId}-${spanId}-01`, traceId };
|
|
279
295
|
}
|
|
280
296
|
async doFetch(method, path2, body, headers, signal, allowHttpErrors = false) {
|
|
281
297
|
const url = `${this.baseUrl}${path2}`;
|
|
298
|
+
const { traceparent, traceId } = _HttpClient.makeTraceparent();
|
|
299
|
+
headers["traceparent"] = traceparent;
|
|
282
300
|
let lastError;
|
|
283
301
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
284
302
|
if (attempt > 0) {
|
|
@@ -299,7 +317,7 @@ var init_http = __esm({
|
|
|
299
317
|
signal: combinedSignal
|
|
300
318
|
});
|
|
301
319
|
clearTimeout(timeoutId);
|
|
302
|
-
if (response.ok) return response;
|
|
320
|
+
if (response.ok) return { response, traceId };
|
|
303
321
|
if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < this.maxRetries) {
|
|
304
322
|
lastError = new RemoteAPIError(
|
|
305
323
|
response.status,
|
|
@@ -308,7 +326,7 @@ var init_http = __esm({
|
|
|
308
326
|
continue;
|
|
309
327
|
}
|
|
310
328
|
if (allowHttpErrors) {
|
|
311
|
-
return response;
|
|
329
|
+
return { response, traceId };
|
|
312
330
|
}
|
|
313
331
|
const errorBody = await response.text().catch(() => "");
|
|
314
332
|
throwMappedError(response.status, errorBody, path2);
|
|
@@ -378,20 +396,20 @@ var SandboxStatus, SnapshotStatus, ProcessStatus, StdinMode, OutputMode, Contain
|
|
|
378
396
|
var init_models = __esm({
|
|
379
397
|
"src/models.ts"() {
|
|
380
398
|
"use strict";
|
|
381
|
-
SandboxStatus = /* @__PURE__ */ ((
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return
|
|
399
|
+
SandboxStatus = /* @__PURE__ */ ((SandboxStatus3) => {
|
|
400
|
+
SandboxStatus3["PENDING"] = "pending";
|
|
401
|
+
SandboxStatus3["RUNNING"] = "running";
|
|
402
|
+
SandboxStatus3["SNAPSHOTTING"] = "snapshotting";
|
|
403
|
+
SandboxStatus3["SUSPENDING"] = "suspending";
|
|
404
|
+
SandboxStatus3["SUSPENDED"] = "suspended";
|
|
405
|
+
SandboxStatus3["TERMINATED"] = "terminated";
|
|
406
|
+
return SandboxStatus3;
|
|
389
407
|
})(SandboxStatus || {});
|
|
390
|
-
SnapshotStatus = /* @__PURE__ */ ((
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
return
|
|
408
|
+
SnapshotStatus = /* @__PURE__ */ ((SnapshotStatus3) => {
|
|
409
|
+
SnapshotStatus3["IN_PROGRESS"] = "in_progress";
|
|
410
|
+
SnapshotStatus3["COMPLETED"] = "completed";
|
|
411
|
+
SnapshotStatus3["FAILED"] = "failed";
|
|
412
|
+
return SnapshotStatus3;
|
|
395
413
|
})(SnapshotStatus || {});
|
|
396
414
|
ProcessStatus = /* @__PURE__ */ ((ProcessStatus2) => {
|
|
397
415
|
ProcessStatus2["RUNNING"] = "running";
|
|
@@ -3140,6 +3158,7 @@ var init_sandbox = __esm({
|
|
|
3140
3158
|
};
|
|
3141
3159
|
Sandbox = class {
|
|
3142
3160
|
sandboxId;
|
|
3161
|
+
traceId = null;
|
|
3143
3162
|
http;
|
|
3144
3163
|
baseUrl;
|
|
3145
3164
|
wsHeaders;
|
|
@@ -3177,9 +3196,126 @@ var init_sandbox = __esm({
|
|
|
3177
3196
|
this.ownsSandbox = true;
|
|
3178
3197
|
this.lifecycleClient = client;
|
|
3179
3198
|
}
|
|
3199
|
+
// --- Static factory methods ---
|
|
3200
|
+
/**
|
|
3201
|
+
* Create a new sandbox and return a connected, running handle.
|
|
3202
|
+
*
|
|
3203
|
+
* Covers both fresh sandbox creation and restore-from-snapshot (set
|
|
3204
|
+
* `snapshotId`). Blocks until the sandbox is `Running`.
|
|
3205
|
+
*/
|
|
3206
|
+
static async create(options) {
|
|
3207
|
+
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3208
|
+
const client = new SandboxClient2(
|
|
3209
|
+
options,
|
|
3210
|
+
/* _internal */
|
|
3211
|
+
true
|
|
3212
|
+
);
|
|
3213
|
+
const sandbox = await client.createAndConnect(options);
|
|
3214
|
+
sandbox.lifecycleClient = client;
|
|
3215
|
+
return sandbox;
|
|
3216
|
+
}
|
|
3217
|
+
/**
|
|
3218
|
+
* Attach to an existing sandbox and return a connected handle.
|
|
3219
|
+
*
|
|
3220
|
+
* Verifies the sandbox exists via a server GET call, then returns a handle
|
|
3221
|
+
* in whatever state the sandbox is in. Does **not** auto-resume a suspended
|
|
3222
|
+
* sandbox — call `sandbox.resume()` explicitly.
|
|
3223
|
+
*/
|
|
3224
|
+
static async connect(options) {
|
|
3225
|
+
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3226
|
+
const client = new SandboxClient2(
|
|
3227
|
+
options,
|
|
3228
|
+
/* _internal */
|
|
3229
|
+
true
|
|
3230
|
+
);
|
|
3231
|
+
await client.get(options.sandboxId);
|
|
3232
|
+
const sandbox = client.connect(options.sandboxId, options.proxyUrl, options.routingHint);
|
|
3233
|
+
sandbox.lifecycleClient = client;
|
|
3234
|
+
return sandbox;
|
|
3235
|
+
}
|
|
3236
|
+
// --- Static snapshot management ---
|
|
3237
|
+
/** Get information about a snapshot by ID. No sandbox handle needed. */
|
|
3238
|
+
static async getSnapshot(snapshotId, options) {
|
|
3239
|
+
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3240
|
+
const client = new SandboxClient2(
|
|
3241
|
+
options,
|
|
3242
|
+
/* _internal */
|
|
3243
|
+
true
|
|
3244
|
+
);
|
|
3245
|
+
return client.getSnapshot(snapshotId);
|
|
3246
|
+
}
|
|
3247
|
+
/** Delete a snapshot by ID. No sandbox handle needed. */
|
|
3248
|
+
static async deleteSnapshot(snapshotId, options) {
|
|
3249
|
+
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3250
|
+
const client = new SandboxClient2(
|
|
3251
|
+
options,
|
|
3252
|
+
/* _internal */
|
|
3253
|
+
true
|
|
3254
|
+
);
|
|
3255
|
+
await client.deleteSnapshot(snapshotId);
|
|
3256
|
+
}
|
|
3257
|
+
// --- Instance lifecycle methods ---
|
|
3258
|
+
requireLifecycleClient(operation) {
|
|
3259
|
+
if (!this.lifecycleClient) {
|
|
3260
|
+
throw new SandboxError(
|
|
3261
|
+
`Cannot ${operation}: no lifecycle client available. Use Sandbox.create() or Sandbox.connect() to get a lifecycle-aware handle.`
|
|
3262
|
+
);
|
|
3263
|
+
}
|
|
3264
|
+
return this.lifecycleClient;
|
|
3265
|
+
}
|
|
3266
|
+
/**
|
|
3267
|
+
* Suspend this sandbox.
|
|
3268
|
+
*
|
|
3269
|
+
* By default blocks until the sandbox is fully `Suspended`. Pass
|
|
3270
|
+
* `{ wait: false }` for fire-and-return.
|
|
3271
|
+
*/
|
|
3272
|
+
async suspend(options) {
|
|
3273
|
+
const client = this.requireLifecycleClient("suspend");
|
|
3274
|
+
await client.suspend(this.sandboxId, options);
|
|
3275
|
+
}
|
|
3276
|
+
/**
|
|
3277
|
+
* Resume this sandbox.
|
|
3278
|
+
*
|
|
3279
|
+
* By default blocks until the sandbox is `Running` and routable. Pass
|
|
3280
|
+
* `{ wait: false }` for fire-and-return.
|
|
3281
|
+
*/
|
|
3282
|
+
async resume(options) {
|
|
3283
|
+
const client = this.requireLifecycleClient("resume");
|
|
3284
|
+
await client.resume(this.sandboxId, options);
|
|
3285
|
+
}
|
|
3286
|
+
/**
|
|
3287
|
+
* Create a snapshot of this sandbox's filesystem and wait for it to
|
|
3288
|
+
* be committed.
|
|
3289
|
+
*
|
|
3290
|
+
* By default blocks until the snapshot artifact is ready and returns
|
|
3291
|
+
* the completed `SnapshotInfo`. Pass `{ wait: false }` to fire-and-return
|
|
3292
|
+
* (returns `undefined`).
|
|
3293
|
+
*/
|
|
3294
|
+
async checkpoint(options) {
|
|
3295
|
+
const client = this.requireLifecycleClient("checkpoint");
|
|
3296
|
+
if (options?.wait === false) {
|
|
3297
|
+
await client.snapshot(this.sandboxId, { contentMode: options.contentMode });
|
|
3298
|
+
return void 0;
|
|
3299
|
+
}
|
|
3300
|
+
return client.snapshotAndWait(this.sandboxId, {
|
|
3301
|
+
timeout: options?.timeout,
|
|
3302
|
+
pollInterval: options?.pollInterval,
|
|
3303
|
+
contentMode: options?.contentMode
|
|
3304
|
+
});
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* List snapshots taken from this sandbox.
|
|
3308
|
+
*/
|
|
3309
|
+
async listSnapshots() {
|
|
3310
|
+
const client = this.requireLifecycleClient("listSnapshots");
|
|
3311
|
+
const all = await client.listSnapshots();
|
|
3312
|
+
return all.filter((s) => s.sandboxId === this.sandboxId);
|
|
3313
|
+
}
|
|
3314
|
+
/** Close the HTTP client. The sandbox keeps running. */
|
|
3180
3315
|
close() {
|
|
3181
3316
|
this.http.close();
|
|
3182
3317
|
}
|
|
3318
|
+
/** Terminate the sandbox and release all resources. */
|
|
3183
3319
|
async terminate() {
|
|
3184
3320
|
const client = this.lifecycleClient;
|
|
3185
3321
|
this.ownsSandbox = false;
|
|
@@ -3232,6 +3368,14 @@ var init_sandbox = __esm({
|
|
|
3232
3368
|
};
|
|
3233
3369
|
}
|
|
3234
3370
|
// --- Process management ---
|
|
3371
|
+
/**
|
|
3372
|
+
* Start a process in the sandbox without waiting for it to exit.
|
|
3373
|
+
*
|
|
3374
|
+
* Returns a `ProcessInfo` with the assigned `pid`. Use `getProcess()` to
|
|
3375
|
+
* poll status, or `followStdout()` / `followOutput()` to stream output
|
|
3376
|
+
* until the process exits. Use `run()` instead to block until completion
|
|
3377
|
+
* and get combined output in one call.
|
|
3378
|
+
*/
|
|
3235
3379
|
async startProcess(command, options) {
|
|
3236
3380
|
const payload = { command };
|
|
3237
3381
|
if (options?.args != null) payload.args = options.args;
|
|
@@ -3253,6 +3397,7 @@ var init_sandbox = __esm({
|
|
|
3253
3397
|
);
|
|
3254
3398
|
return fromSnakeKeys(raw);
|
|
3255
3399
|
}
|
|
3400
|
+
/** List all processes (running and exited) tracked by the sandbox daemon. */
|
|
3256
3401
|
async listProcesses() {
|
|
3257
3402
|
const raw = await this.http.requestJson(
|
|
3258
3403
|
"GET",
|
|
@@ -3260,6 +3405,7 @@ var init_sandbox = __esm({
|
|
|
3260
3405
|
);
|
|
3261
3406
|
return (raw.processes ?? []).map((p) => fromSnakeKeys(p));
|
|
3262
3407
|
}
|
|
3408
|
+
/** Get current status and metadata for a process by PID. */
|
|
3263
3409
|
async getProcess(pid) {
|
|
3264
3410
|
const raw = await this.http.requestJson(
|
|
3265
3411
|
"GET",
|
|
@@ -3267,9 +3413,11 @@ var init_sandbox = __esm({
|
|
|
3267
3413
|
);
|
|
3268
3414
|
return fromSnakeKeys(raw);
|
|
3269
3415
|
}
|
|
3416
|
+
/** Send SIGKILL to a process. */
|
|
3270
3417
|
async killProcess(pid) {
|
|
3271
3418
|
await this.http.requestJson("DELETE", `/api/v1/processes/${pid}`);
|
|
3272
3419
|
}
|
|
3420
|
+
/** Send an arbitrary signal to a process (e.g. `15` for SIGTERM, `9` for SIGKILL). */
|
|
3273
3421
|
async sendSignal(pid, signal) {
|
|
3274
3422
|
const raw = await this.http.requestJson(
|
|
3275
3423
|
"POST",
|
|
@@ -3279,15 +3427,18 @@ var init_sandbox = __esm({
|
|
|
3279
3427
|
return fromSnakeKeys(raw);
|
|
3280
3428
|
}
|
|
3281
3429
|
// --- Process I/O ---
|
|
3430
|
+
/** Write bytes to a process's stdin. The process must have been started with `stdinMode: StdinMode.PIPE`. */
|
|
3282
3431
|
async writeStdin(pid, data) {
|
|
3283
3432
|
await this.http.requestBytes("POST", `/api/v1/processes/${pid}/stdin`, {
|
|
3284
3433
|
body: data,
|
|
3285
3434
|
contentType: "application/octet-stream"
|
|
3286
3435
|
});
|
|
3287
3436
|
}
|
|
3437
|
+
/** Close a process's stdin pipe, signalling EOF to the process. */
|
|
3288
3438
|
async closeStdin(pid) {
|
|
3289
3439
|
await this.http.requestJson("POST", `/api/v1/processes/${pid}/stdin/close`);
|
|
3290
3440
|
}
|
|
3441
|
+
/** Return all captured stdout lines produced so far by a process. */
|
|
3291
3442
|
async getStdout(pid) {
|
|
3292
3443
|
const raw = await this.http.requestJson(
|
|
3293
3444
|
"GET",
|
|
@@ -3295,6 +3446,7 @@ var init_sandbox = __esm({
|
|
|
3295
3446
|
);
|
|
3296
3447
|
return fromSnakeKeys(raw);
|
|
3297
3448
|
}
|
|
3449
|
+
/** Return all captured stderr lines produced so far by a process. */
|
|
3298
3450
|
async getStderr(pid) {
|
|
3299
3451
|
const raw = await this.http.requestJson(
|
|
3300
3452
|
"GET",
|
|
@@ -3302,6 +3454,7 @@ var init_sandbox = __esm({
|
|
|
3302
3454
|
);
|
|
3303
3455
|
return fromSnakeKeys(raw);
|
|
3304
3456
|
}
|
|
3457
|
+
/** Return all captured stdout+stderr lines produced so far by a process. */
|
|
3305
3458
|
async getOutput(pid) {
|
|
3306
3459
|
const raw = await this.http.requestJson(
|
|
3307
3460
|
"GET",
|
|
@@ -3310,6 +3463,7 @@ var init_sandbox = __esm({
|
|
|
3310
3463
|
return fromSnakeKeys(raw);
|
|
3311
3464
|
}
|
|
3312
3465
|
// --- Streaming (SSE) ---
|
|
3466
|
+
/** Stream stdout events from a process until it exits. Yields one `OutputEvent` per line. */
|
|
3313
3467
|
async *followStdout(pid, options) {
|
|
3314
3468
|
const stream = await this.http.requestStream(
|
|
3315
3469
|
"GET",
|
|
@@ -3323,6 +3477,7 @@ var init_sandbox = __esm({
|
|
|
3323
3477
|
yield fromSnakeKeys(raw);
|
|
3324
3478
|
}
|
|
3325
3479
|
}
|
|
3480
|
+
/** Stream stderr events from a process until it exits. Yields one `OutputEvent` per line. */
|
|
3326
3481
|
async *followStderr(pid, options) {
|
|
3327
3482
|
const stream = await this.http.requestStream(
|
|
3328
3483
|
"GET",
|
|
@@ -3336,6 +3491,7 @@ var init_sandbox = __esm({
|
|
|
3336
3491
|
yield fromSnakeKeys(raw);
|
|
3337
3492
|
}
|
|
3338
3493
|
}
|
|
3494
|
+
/** Stream combined stdout+stderr events from a process until it exits. Yields one `OutputEvent` per line. */
|
|
3339
3495
|
async *followOutput(pid, options) {
|
|
3340
3496
|
const stream = await this.http.requestStream(
|
|
3341
3497
|
"GET",
|
|
@@ -3350,12 +3506,14 @@ var init_sandbox = __esm({
|
|
|
3350
3506
|
}
|
|
3351
3507
|
}
|
|
3352
3508
|
// --- File operations ---
|
|
3509
|
+
/** Read a file from the sandbox and return its raw bytes. */
|
|
3353
3510
|
async readFile(path2) {
|
|
3354
3511
|
return this.http.requestBytes(
|
|
3355
3512
|
"GET",
|
|
3356
3513
|
`/api/v1/files?path=${encodeURIComponent(path2)}`
|
|
3357
3514
|
);
|
|
3358
3515
|
}
|
|
3516
|
+
/** Write raw bytes to a file in the sandbox, creating it if it does not exist. */
|
|
3359
3517
|
async writeFile(path2, content) {
|
|
3360
3518
|
await this.http.requestBytes(
|
|
3361
3519
|
"PUT",
|
|
@@ -3363,12 +3521,14 @@ var init_sandbox = __esm({
|
|
|
3363
3521
|
{ body: content, contentType: "application/octet-stream" }
|
|
3364
3522
|
);
|
|
3365
3523
|
}
|
|
3524
|
+
/** Delete a file from the sandbox. */
|
|
3366
3525
|
async deleteFile(path2) {
|
|
3367
3526
|
await this.http.requestJson(
|
|
3368
3527
|
"DELETE",
|
|
3369
3528
|
`/api/v1/files?path=${encodeURIComponent(path2)}`
|
|
3370
3529
|
);
|
|
3371
3530
|
}
|
|
3531
|
+
/** List the contents of a directory in the sandbox. */
|
|
3372
3532
|
async listDirectory(path2) {
|
|
3373
3533
|
const raw = await this.http.requestJson(
|
|
3374
3534
|
"GET",
|
|
@@ -3377,6 +3537,7 @@ var init_sandbox = __esm({
|
|
|
3377
3537
|
return fromSnakeKeys(raw);
|
|
3378
3538
|
}
|
|
3379
3539
|
// --- PTY ---
|
|
3540
|
+
/** Create an interactive PTY session. Returns a `sessionId` and `token` for WebSocket connection via `connectPty()`. */
|
|
3380
3541
|
async createPtySession(options) {
|
|
3381
3542
|
const payload = {
|
|
3382
3543
|
command: options.command,
|
|
@@ -3393,6 +3554,7 @@ var init_sandbox = __esm({
|
|
|
3393
3554
|
);
|
|
3394
3555
|
return fromSnakeKeys(raw);
|
|
3395
3556
|
}
|
|
3557
|
+
/** Create a PTY session and connect to it immediately. Cleans up the session if the WebSocket connection fails. */
|
|
3396
3558
|
async createPty(options) {
|
|
3397
3559
|
const { onData, onExit, ...createOptions } = options;
|
|
3398
3560
|
const session = await this.createPtySession(createOptions);
|
|
@@ -3406,6 +3568,7 @@ var init_sandbox = __esm({
|
|
|
3406
3568
|
throw error;
|
|
3407
3569
|
}
|
|
3408
3570
|
}
|
|
3571
|
+
/** Attach to an existing PTY session by ID and token and return a connected `Pty` handle. */
|
|
3409
3572
|
async connectPty(sessionId, token, options) {
|
|
3410
3573
|
const wsUrl = new URL(this.ptyWsUrl(sessionId, token));
|
|
3411
3574
|
const authToken = wsUrl.searchParams.get("token") ?? token;
|
|
@@ -3430,6 +3593,7 @@ var init_sandbox = __esm({
|
|
|
3430
3593
|
await pty.connect();
|
|
3431
3594
|
return pty;
|
|
3432
3595
|
}
|
|
3596
|
+
/** Open a TCP tunnel to a port inside the sandbox and return the local listener. */
|
|
3433
3597
|
async createTunnel(remotePort, options) {
|
|
3434
3598
|
return TcpTunnel.listen({
|
|
3435
3599
|
baseUrl: this.baseUrl,
|
|
@@ -3440,6 +3604,7 @@ var init_sandbox = __esm({
|
|
|
3440
3604
|
connectTimeout: options?.connectTimeout
|
|
3441
3605
|
});
|
|
3442
3606
|
}
|
|
3607
|
+
/** Connect to a sandbox VNC session for programmatic desktop control. */
|
|
3443
3608
|
async connectDesktop(options) {
|
|
3444
3609
|
return Desktop.connect({
|
|
3445
3610
|
baseUrl: this.baseUrl,
|
|
@@ -3462,6 +3627,7 @@ var init_sandbox = __esm({
|
|
|
3462
3627
|
return `${wsBase}/api/v1/pty/${sessionId}/ws?token=${token}`;
|
|
3463
3628
|
}
|
|
3464
3629
|
// --- Health ---
|
|
3630
|
+
/** Check the sandbox daemon health. */
|
|
3465
3631
|
async health() {
|
|
3466
3632
|
const raw = await this.http.requestJson(
|
|
3467
3633
|
"GET",
|
|
@@ -3469,6 +3635,7 @@ var init_sandbox = __esm({
|
|
|
3469
3635
|
);
|
|
3470
3636
|
return fromSnakeKeys(raw);
|
|
3471
3637
|
}
|
|
3638
|
+
/** Get sandbox daemon info (version, uptime, process counts). */
|
|
3472
3639
|
async info() {
|
|
3473
3640
|
const raw = await this.http.requestJson(
|
|
3474
3641
|
"GET",
|
|
@@ -3481,6 +3648,10 @@ var init_sandbox = __esm({
|
|
|
3481
3648
|
});
|
|
3482
3649
|
|
|
3483
3650
|
// src/client.ts
|
|
3651
|
+
var client_exports = {};
|
|
3652
|
+
__export(client_exports, {
|
|
3653
|
+
SandboxClient: () => SandboxClient
|
|
3654
|
+
});
|
|
3484
3655
|
function sleep2(ms) {
|
|
3485
3656
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3486
3657
|
}
|
|
@@ -3517,7 +3688,13 @@ var init_client = __esm({
|
|
|
3517
3688
|
projectId;
|
|
3518
3689
|
namespace;
|
|
3519
3690
|
local;
|
|
3520
|
-
|
|
3691
|
+
/** @internal Pass `true` to suppress the deprecation warning when used by `Sandbox.create()` / `Sandbox.connect()`. */
|
|
3692
|
+
constructor(options, _internal = false) {
|
|
3693
|
+
if (!_internal) {
|
|
3694
|
+
console.warn(
|
|
3695
|
+
"[tensorlake] SandboxClient is deprecated; use Sandbox.create() / Sandbox.connect() instead."
|
|
3696
|
+
);
|
|
3697
|
+
}
|
|
3521
3698
|
this.apiUrl = options?.apiUrl ?? API_URL;
|
|
3522
3699
|
this.apiKey = options?.apiKey ?? API_KEY;
|
|
3523
3700
|
this.organizationId = options?.organizationId;
|
|
@@ -3557,6 +3734,7 @@ var init_client = __esm({
|
|
|
3557
3734
|
return lifecyclePath(subpath, this.local, this.namespace);
|
|
3558
3735
|
}
|
|
3559
3736
|
// --- Sandbox CRUD ---
|
|
3737
|
+
/** Create a new sandbox. Returns immediately; the sandbox may still be starting. Use `createAndConnect()` for a blocking, ready-to-use handle. */
|
|
3560
3738
|
async create(options) {
|
|
3561
3739
|
const body = {
|
|
3562
3740
|
resources: {
|
|
@@ -3583,8 +3761,10 @@ var init_client = __esm({
|
|
|
3583
3761
|
this.path("sandboxes"),
|
|
3584
3762
|
{ body }
|
|
3585
3763
|
);
|
|
3586
|
-
|
|
3764
|
+
const result = fromSnakeKeys(raw, "sandboxId");
|
|
3765
|
+
return Object.assign(result, { traceId: raw.traceId });
|
|
3587
3766
|
}
|
|
3767
|
+
/** Get current state and metadata for a sandbox by ID. */
|
|
3588
3768
|
async get(sandboxId) {
|
|
3589
3769
|
const raw = await this.http.requestJson(
|
|
3590
3770
|
"GET",
|
|
@@ -3592,6 +3772,7 @@ var init_client = __esm({
|
|
|
3592
3772
|
);
|
|
3593
3773
|
return fromSnakeKeys(raw, "sandboxId");
|
|
3594
3774
|
}
|
|
3775
|
+
/** List all sandboxes in the namespace. */
|
|
3595
3776
|
async list() {
|
|
3596
3777
|
const raw = await this.http.requestJson(
|
|
3597
3778
|
"GET",
|
|
@@ -3601,6 +3782,7 @@ var init_client = __esm({
|
|
|
3601
3782
|
(s) => fromSnakeKeys(s, "sandboxId")
|
|
3602
3783
|
);
|
|
3603
3784
|
}
|
|
3785
|
+
/** Update sandbox properties such as name, exposed ports, and proxy auth settings. */
|
|
3604
3786
|
async update(sandboxId, options) {
|
|
3605
3787
|
const body = {};
|
|
3606
3788
|
if (options.name != null) body.name = options.name;
|
|
@@ -3620,6 +3802,7 @@ var init_client = __esm({
|
|
|
3620
3802
|
);
|
|
3621
3803
|
return fromSnakeKeys(raw, "sandboxId");
|
|
3622
3804
|
}
|
|
3805
|
+
/** Get the current proxy port settings for a sandbox. */
|
|
3623
3806
|
async getPortAccess(sandboxId) {
|
|
3624
3807
|
const info = await this.get(sandboxId);
|
|
3625
3808
|
return {
|
|
@@ -3628,6 +3811,7 @@ var init_client = __esm({
|
|
|
3628
3811
|
sandboxUrl: info.sandboxUrl
|
|
3629
3812
|
};
|
|
3630
3813
|
}
|
|
3814
|
+
/** Add one or more user ports to the sandbox proxy allowlist. */
|
|
3631
3815
|
async exposePorts(sandboxId, ports, options) {
|
|
3632
3816
|
const requestedPorts = normalizeUserPorts(ports);
|
|
3633
3817
|
const current = await this.getPortAccess(sandboxId);
|
|
@@ -3640,6 +3824,7 @@ var init_client = __esm({
|
|
|
3640
3824
|
exposedPorts: desiredPorts
|
|
3641
3825
|
});
|
|
3642
3826
|
}
|
|
3827
|
+
/** Remove one or more user ports from the sandbox proxy allowlist. */
|
|
3643
3828
|
async unexposePorts(sandboxId, ports) {
|
|
3644
3829
|
const requestedPorts = normalizeUserPorts(ports);
|
|
3645
3830
|
const current = await this.getPortAccess(sandboxId);
|
|
@@ -3650,32 +3835,98 @@ var init_client = __esm({
|
|
|
3650
3835
|
exposedPorts: desiredPorts
|
|
3651
3836
|
});
|
|
3652
3837
|
}
|
|
3838
|
+
/** Terminate and delete a sandbox. */
|
|
3653
3839
|
async delete(sandboxId) {
|
|
3654
3840
|
await this.http.requestJson(
|
|
3655
3841
|
"DELETE",
|
|
3656
3842
|
this.path(`sandboxes/${sandboxId}`)
|
|
3657
3843
|
);
|
|
3658
3844
|
}
|
|
3659
|
-
|
|
3845
|
+
/**
|
|
3846
|
+
* Suspend a named sandbox, preserving its state for later resume.
|
|
3847
|
+
*
|
|
3848
|
+
* Only sandboxes created with a `name` can be suspended; ephemeral sandboxes
|
|
3849
|
+
* cannot. By default blocks until the sandbox is fully `Suspended`. Pass
|
|
3850
|
+
* `{ wait: false }` to return immediately after the request is sent
|
|
3851
|
+
* (fire-and-return); the server processes the suspend asynchronously.
|
|
3852
|
+
*
|
|
3853
|
+
* @param sandboxId - ID or name of the sandbox.
|
|
3854
|
+
* @param options.wait - If `true` (default), poll until `Suspended`. Pass `false` to fire-and-return.
|
|
3855
|
+
* @param options.timeout - Max seconds to wait when `wait=true` (default 300).
|
|
3856
|
+
* @param options.pollInterval - Seconds between status polls when `wait=true` (default 1).
|
|
3857
|
+
* @throws {SandboxError} If `wait=true` and the sandbox does not reach `Suspended` within `timeout`.
|
|
3858
|
+
*/
|
|
3859
|
+
async suspend(sandboxId, options) {
|
|
3660
3860
|
await this.http.requestResponse(
|
|
3661
3861
|
"POST",
|
|
3662
3862
|
this.path(`sandboxes/${sandboxId}/suspend`)
|
|
3663
3863
|
);
|
|
3864
|
+
if (options?.wait === false) return;
|
|
3865
|
+
const timeout = options?.timeout ?? 300;
|
|
3866
|
+
const pollInterval = options?.pollInterval ?? 1;
|
|
3867
|
+
const deadline = Date.now() + timeout * 1e3;
|
|
3868
|
+
while (Date.now() < deadline) {
|
|
3869
|
+
const info = await this.get(sandboxId);
|
|
3870
|
+
if (info.status === "suspended" /* SUSPENDED */) return;
|
|
3871
|
+
if (info.status === "terminated" /* TERMINATED */) {
|
|
3872
|
+
throw new SandboxError(`Sandbox ${sandboxId} terminated while waiting for suspend`);
|
|
3873
|
+
}
|
|
3874
|
+
await sleep2(pollInterval * 1e3);
|
|
3875
|
+
}
|
|
3876
|
+
throw new SandboxError(`Sandbox ${sandboxId} did not suspend within ${timeout}s`);
|
|
3664
3877
|
}
|
|
3665
|
-
|
|
3878
|
+
/**
|
|
3879
|
+
* Resume a suspended sandbox and bring it back to `Running`.
|
|
3880
|
+
*
|
|
3881
|
+
* By default blocks until the sandbox is `Running` and routable. Pass
|
|
3882
|
+
* `{ wait: false }` to return immediately after the request is sent
|
|
3883
|
+
* (fire-and-return); the server processes the resume asynchronously.
|
|
3884
|
+
*
|
|
3885
|
+
* @param sandboxId - ID or name of the sandbox.
|
|
3886
|
+
* @param options.wait - If `true` (default), poll until `Running`. Pass `false` to fire-and-return.
|
|
3887
|
+
* @param options.timeout - Max seconds to wait when `wait=true` (default 300).
|
|
3888
|
+
* @param options.pollInterval - Seconds between status polls when `wait=true` (default 1).
|
|
3889
|
+
* @throws {SandboxError} If `wait=true` and the sandbox does not reach `Running` within `timeout`.
|
|
3890
|
+
*/
|
|
3891
|
+
async resume(sandboxId, options) {
|
|
3666
3892
|
await this.http.requestResponse(
|
|
3667
3893
|
"POST",
|
|
3668
3894
|
this.path(`sandboxes/${sandboxId}/resume`)
|
|
3669
3895
|
);
|
|
3896
|
+
if (options?.wait === false) return;
|
|
3897
|
+
const timeout = options?.timeout ?? 300;
|
|
3898
|
+
const pollInterval = options?.pollInterval ?? 1;
|
|
3899
|
+
const deadline = Date.now() + timeout * 1e3;
|
|
3900
|
+
while (Date.now() < deadline) {
|
|
3901
|
+
const info = await this.get(sandboxId);
|
|
3902
|
+
if (info.status === "running" /* RUNNING */) return;
|
|
3903
|
+
if (info.status === "terminated" /* TERMINATED */) {
|
|
3904
|
+
throw new SandboxError(`Sandbox ${sandboxId} terminated while waiting for resume`);
|
|
3905
|
+
}
|
|
3906
|
+
await sleep2(pollInterval * 1e3);
|
|
3907
|
+
}
|
|
3908
|
+
throw new SandboxError(`Sandbox ${sandboxId} did not resume within ${timeout}s`);
|
|
3670
3909
|
}
|
|
3910
|
+
/** Claim a warm sandbox from a pool, creating one if no warm containers are available. */
|
|
3671
3911
|
async claim(poolId) {
|
|
3672
3912
|
const raw = await this.http.requestJson(
|
|
3673
3913
|
"POST",
|
|
3674
3914
|
this.path(`sandbox-pools/${poolId}/sandboxes`)
|
|
3675
3915
|
);
|
|
3676
|
-
|
|
3916
|
+
const result = fromSnakeKeys(raw, "sandboxId");
|
|
3917
|
+
return Object.assign(result, { traceId: raw.traceId });
|
|
3677
3918
|
}
|
|
3678
3919
|
// --- Snapshots ---
|
|
3920
|
+
/**
|
|
3921
|
+
* Request a snapshot of a running sandbox's filesystem.
|
|
3922
|
+
*
|
|
3923
|
+
* This call **returns immediately** with a `snapshotId` and `in_progress`
|
|
3924
|
+
* status — the snapshot is created asynchronously. Poll `getSnapshot()` until
|
|
3925
|
+
* `completed` or `failed`, or use `snapshotAndWait()` to block automatically.
|
|
3926
|
+
*
|
|
3927
|
+
* @param options.contentMode - `"filesystem_only"` for cold-boot snapshots (e.g. image builds).
|
|
3928
|
+
* Omit to use the server default (full VM snapshot).
|
|
3929
|
+
*/
|
|
3679
3930
|
async snapshot(sandboxId, options) {
|
|
3680
3931
|
const requestOptions = options?.contentMode != null ? { body: { snapshot_content_mode: options.contentMode } } : void 0;
|
|
3681
3932
|
const raw = await this.http.requestJson(
|
|
@@ -3685,6 +3936,7 @@ var init_client = __esm({
|
|
|
3685
3936
|
);
|
|
3686
3937
|
return fromSnakeKeys(raw, "snapshotId");
|
|
3687
3938
|
}
|
|
3939
|
+
/** Get current status and metadata for a snapshot by ID. */
|
|
3688
3940
|
async getSnapshot(snapshotId) {
|
|
3689
3941
|
const raw = await this.http.requestJson(
|
|
3690
3942
|
"GET",
|
|
@@ -3692,6 +3944,7 @@ var init_client = __esm({
|
|
|
3692
3944
|
);
|
|
3693
3945
|
return fromSnakeKeys(raw, "snapshotId");
|
|
3694
3946
|
}
|
|
3947
|
+
/** List all snapshots in the namespace. */
|
|
3695
3948
|
async listSnapshots() {
|
|
3696
3949
|
const raw = await this.http.requestJson(
|
|
3697
3950
|
"GET",
|
|
@@ -3701,12 +3954,26 @@ var init_client = __esm({
|
|
|
3701
3954
|
(s) => fromSnakeKeys(s, "snapshotId")
|
|
3702
3955
|
);
|
|
3703
3956
|
}
|
|
3957
|
+
/** Delete a snapshot by ID. */
|
|
3704
3958
|
async deleteSnapshot(snapshotId) {
|
|
3705
3959
|
await this.http.requestJson(
|
|
3706
3960
|
"DELETE",
|
|
3707
3961
|
this.path(`snapshots/${snapshotId}`)
|
|
3708
3962
|
);
|
|
3709
3963
|
}
|
|
3964
|
+
/**
|
|
3965
|
+
* Create a snapshot and block until it is committed.
|
|
3966
|
+
*
|
|
3967
|
+
* Combines `snapshot()` with polling `getSnapshot()` until `completed`.
|
|
3968
|
+
* Prefer `sandbox.checkpoint()` on a `Sandbox` handle for the same behavior
|
|
3969
|
+
* without managing the client separately.
|
|
3970
|
+
*
|
|
3971
|
+
* @param sandboxId - ID of the running sandbox to snapshot.
|
|
3972
|
+
* @param options.timeout - Max seconds to wait (default 300).
|
|
3973
|
+
* @param options.pollInterval - Seconds between status polls (default 1).
|
|
3974
|
+
* @param options.contentMode - Content mode passed through to `snapshot()`.
|
|
3975
|
+
* @throws {SandboxError} If the snapshot fails or `timeout` elapses.
|
|
3976
|
+
*/
|
|
3710
3977
|
async snapshotAndWait(sandboxId, options) {
|
|
3711
3978
|
const timeout = options?.timeout ?? 300;
|
|
3712
3979
|
const pollInterval = options?.pollInterval ?? 1;
|
|
@@ -3729,6 +3996,7 @@ var init_client = __esm({
|
|
|
3729
3996
|
);
|
|
3730
3997
|
}
|
|
3731
3998
|
// --- Pools ---
|
|
3999
|
+
/** Create a new sandbox pool with warm pre-booted containers. */
|
|
3732
4000
|
async createPool(options) {
|
|
3733
4001
|
const body = {
|
|
3734
4002
|
image: options.image,
|
|
@@ -3750,6 +4018,7 @@ var init_client = __esm({
|
|
|
3750
4018
|
);
|
|
3751
4019
|
return fromSnakeKeys(raw, "poolId");
|
|
3752
4020
|
}
|
|
4021
|
+
/** Get current state and metadata for a sandbox pool by ID. */
|
|
3753
4022
|
async getPool(poolId) {
|
|
3754
4023
|
const raw = await this.http.requestJson(
|
|
3755
4024
|
"GET",
|
|
@@ -3757,6 +4026,7 @@ var init_client = __esm({
|
|
|
3757
4026
|
);
|
|
3758
4027
|
return fromSnakeKeys(raw, "poolId");
|
|
3759
4028
|
}
|
|
4029
|
+
/** List all sandbox pools in the namespace. */
|
|
3760
4030
|
async listPools() {
|
|
3761
4031
|
const raw = await this.http.requestJson(
|
|
3762
4032
|
"GET",
|
|
@@ -3766,6 +4036,7 @@ var init_client = __esm({
|
|
|
3766
4036
|
(p) => fromSnakeKeys(p, "poolId")
|
|
3767
4037
|
);
|
|
3768
4038
|
}
|
|
4039
|
+
/** Replace the configuration of an existing sandbox pool. */
|
|
3769
4040
|
async updatePool(poolId, options) {
|
|
3770
4041
|
const body = {
|
|
3771
4042
|
image: options.image,
|
|
@@ -3787,6 +4058,7 @@ var init_client = __esm({
|
|
|
3787
4058
|
);
|
|
3788
4059
|
return fromSnakeKeys(raw, "poolId");
|
|
3789
4060
|
}
|
|
4061
|
+
/** Delete a sandbox pool. Fails if the pool has active containers. */
|
|
3790
4062
|
async deletePool(poolId) {
|
|
3791
4063
|
await this.http.requestJson(
|
|
3792
4064
|
"DELETE",
|
|
@@ -3794,6 +4066,7 @@ var init_client = __esm({
|
|
|
3794
4066
|
);
|
|
3795
4067
|
}
|
|
3796
4068
|
// --- Connect ---
|
|
4069
|
+
/** Return a `Sandbox` handle for an existing running sandbox without verifying it exists. */
|
|
3797
4070
|
connect(identifier, proxyUrl, routingHint) {
|
|
3798
4071
|
const resolvedProxy = proxyUrl ?? resolveProxyUrl(this.apiUrl);
|
|
3799
4072
|
return new Sandbox({
|
|
@@ -3805,6 +4078,15 @@ var init_client = __esm({
|
|
|
3805
4078
|
routingHint
|
|
3806
4079
|
});
|
|
3807
4080
|
}
|
|
4081
|
+
/**
|
|
4082
|
+
* Create a sandbox, wait for it to reach `Running`, and return a connected handle.
|
|
4083
|
+
*
|
|
4084
|
+
* Blocks until the sandbox is ready or `startupTimeout` elapses. The returned
|
|
4085
|
+
* `Sandbox` auto-terminates when `terminate()` is called.
|
|
4086
|
+
*
|
|
4087
|
+
* @param options.startupTimeout - Max seconds to wait for `Running` status (default 60).
|
|
4088
|
+
* @throws {SandboxError} If the sandbox terminates during startup or the timeout elapses.
|
|
4089
|
+
*/
|
|
3808
4090
|
async createAndConnect(options) {
|
|
3809
4091
|
const startupTimeout = options?.startupTimeout ?? 60;
|
|
3810
4092
|
let result;
|
|
@@ -3816,6 +4098,7 @@ var init_client = __esm({
|
|
|
3816
4098
|
if (result.status === "running" /* RUNNING */) {
|
|
3817
4099
|
const sandbox = this.connect(result.sandboxId, options?.proxyUrl, result.routingHint);
|
|
3818
4100
|
sandbox._setOwner(this);
|
|
4101
|
+
sandbox.traceId = result.traceId;
|
|
3819
4102
|
return sandbox;
|
|
3820
4103
|
}
|
|
3821
4104
|
const deadline = Date.now() + startupTimeout * 1e3;
|
|
@@ -3824,6 +4107,7 @@ var init_client = __esm({
|
|
|
3824
4107
|
if (info.status === "running" /* RUNNING */) {
|
|
3825
4108
|
const sandbox = this.connect(result.sandboxId, options?.proxyUrl, info.routingHint);
|
|
3826
4109
|
sandbox._setOwner(this);
|
|
4110
|
+
sandbox.traceId = result.traceId;
|
|
3827
4111
|
return sandbox;
|
|
3828
4112
|
}
|
|
3829
4113
|
if (info.status === "terminated" /* TERMINATED */) {
|