tensorlake 0.5.5 → 0.5.7
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 +120 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -22
- package/dist/index.d.ts +34 -22
- package/dist/index.js +120 -35
- package/dist/index.js.map +1 -1
- package/dist/{sandbox-image-BmhjX2bC.d.cts → sandbox-image-BMDaNpZ2.d.cts} +1 -1
- package/dist/{sandbox-image-BmhjX2bC.d.ts → sandbox-image-BMDaNpZ2.d.ts} +1 -1
- package/dist/sandbox-image.cjs +120 -35
- 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 +120 -35
- package/dist/sandbox-image.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TI
|
|
|
13
13
|
var init_defaults = __esm({
|
|
14
14
|
"src/defaults.ts"() {
|
|
15
15
|
"use strict";
|
|
16
|
-
SDK_VERSION = "0.
|
|
16
|
+
SDK_VERSION = "0.5.7";
|
|
17
17
|
API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
|
|
18
18
|
API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
|
|
19
19
|
NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
|
|
@@ -218,6 +218,9 @@ var init_http = __esm({
|
|
|
218
218
|
if (options.hostHeader) {
|
|
219
219
|
this.headers["Host"] = options.hostHeader;
|
|
220
220
|
}
|
|
221
|
+
if (options.sandboxIdHeader) {
|
|
222
|
+
this.headers["X-Tensorlake-Sandbox-Id"] = options.sandboxIdHeader;
|
|
223
|
+
}
|
|
221
224
|
if (options.routingHint) {
|
|
222
225
|
this.headers["X-Tensorlake-Route-Hint"] = options.routingHint;
|
|
223
226
|
}
|
|
@@ -2929,21 +2932,36 @@ function resolveProxyTarget(proxyUrl, sandboxId) {
|
|
|
2929
2932
|
if (host === "localhost" || host === "127.0.0.1") {
|
|
2930
2933
|
return {
|
|
2931
2934
|
baseUrl: trimTrailingSlashes(proxyUrl),
|
|
2932
|
-
hostHeader: `${sandboxId}.local
|
|
2935
|
+
hostHeader: `${sandboxId}.local`,
|
|
2936
|
+
sandboxIdHeader: void 0
|
|
2933
2937
|
};
|
|
2934
2938
|
}
|
|
2935
2939
|
const port = parsed.port ? `:${parsed.port}` : "";
|
|
2936
2940
|
return {
|
|
2937
|
-
baseUrl: `${parsed.protocol}//${
|
|
2938
|
-
hostHeader: void 0
|
|
2941
|
+
baseUrl: `${parsed.protocol}//${host}${port}`,
|
|
2942
|
+
hostHeader: void 0,
|
|
2943
|
+
sandboxIdHeader: sandboxId
|
|
2939
2944
|
};
|
|
2940
2945
|
} catch {
|
|
2941
2946
|
return {
|
|
2942
2947
|
baseUrl: `${trimTrailingSlashes(proxyUrl)}/${sandboxId}`,
|
|
2943
|
-
hostHeader: void 0
|
|
2948
|
+
hostHeader: void 0,
|
|
2949
|
+
sandboxIdHeader: void 0
|
|
2944
2950
|
};
|
|
2945
2951
|
}
|
|
2946
2952
|
}
|
|
2953
|
+
function resolveSandboxLifecycleUrl(apiUrl) {
|
|
2954
|
+
if (isLocalhost(apiUrl)) return apiUrl;
|
|
2955
|
+
try {
|
|
2956
|
+
const parsed = new URL(apiUrl);
|
|
2957
|
+
if (parsed.hostname.startsWith("api.")) {
|
|
2958
|
+
parsed.hostname = "sandbox." + parsed.hostname.slice(4);
|
|
2959
|
+
return parsed.toString().replace(/\/$/, "");
|
|
2960
|
+
}
|
|
2961
|
+
} catch {
|
|
2962
|
+
}
|
|
2963
|
+
return apiUrl;
|
|
2964
|
+
}
|
|
2947
2965
|
function lifecyclePath(path2, isLocal, namespace) {
|
|
2948
2966
|
if (isLocal) {
|
|
2949
2967
|
return `/v1/namespaces/${namespace}/${path2}`;
|
|
@@ -3170,7 +3188,7 @@ var init_sandbox = __esm({
|
|
|
3170
3188
|
this.sandboxId = options.sandboxId;
|
|
3171
3189
|
this.lifecycleIdentifier = options.sandboxId;
|
|
3172
3190
|
const proxyUrl = options.proxyUrl ?? SANDBOX_PROXY_URL;
|
|
3173
|
-
const { baseUrl, hostHeader } = resolveProxyTarget(proxyUrl, options.sandboxId);
|
|
3191
|
+
const { baseUrl, hostHeader, sandboxIdHeader } = resolveProxyTarget(proxyUrl, options.sandboxId);
|
|
3174
3192
|
this.baseUrl = baseUrl;
|
|
3175
3193
|
this.wsHeaders = {};
|
|
3176
3194
|
if (options.apiKey) {
|
|
@@ -3185,12 +3203,16 @@ var init_sandbox = __esm({
|
|
|
3185
3203
|
if (hostHeader) {
|
|
3186
3204
|
this.wsHeaders.Host = hostHeader;
|
|
3187
3205
|
}
|
|
3206
|
+
if (sandboxIdHeader) {
|
|
3207
|
+
this.wsHeaders["X-Tensorlake-Sandbox-Id"] = sandboxIdHeader;
|
|
3208
|
+
}
|
|
3188
3209
|
this.http = new HttpClient({
|
|
3189
3210
|
baseUrl,
|
|
3190
3211
|
apiKey: options.apiKey,
|
|
3191
3212
|
organizationId: options.organizationId,
|
|
3192
3213
|
projectId: options.projectId,
|
|
3193
3214
|
hostHeader,
|
|
3215
|
+
sandboxIdHeader,
|
|
3194
3216
|
routingHint: options.routingHint
|
|
3195
3217
|
});
|
|
3196
3218
|
}
|
|
@@ -3231,8 +3253,8 @@ var init_sandbox = __esm({
|
|
|
3231
3253
|
/**
|
|
3232
3254
|
* Attach to an existing sandbox and return a connected handle.
|
|
3233
3255
|
*
|
|
3234
|
-
*
|
|
3235
|
-
*
|
|
3256
|
+
* Returns immediately without contacting the server. Call `sandbox.info()`
|
|
3257
|
+
* to fetch the current state on demand. Does **not** auto-resume a suspended
|
|
3236
3258
|
* sandbox — call `sandbox.resume()` explicitly.
|
|
3237
3259
|
*/
|
|
3238
3260
|
static async connect(options) {
|
|
@@ -3242,15 +3264,12 @@ var init_sandbox = __esm({
|
|
|
3242
3264
|
/* _internal */
|
|
3243
3265
|
true
|
|
3244
3266
|
);
|
|
3245
|
-
const info = await client.get(options.sandboxId);
|
|
3246
3267
|
const sandbox = client.connect(
|
|
3247
|
-
|
|
3268
|
+
options.sandboxId,
|
|
3248
3269
|
options.proxyUrl,
|
|
3249
|
-
options.routingHint
|
|
3270
|
+
options.routingHint
|
|
3250
3271
|
);
|
|
3251
3272
|
sandbox.lifecycleClient = client;
|
|
3252
|
-
sandbox._setLifecycleIdentifier(info.sandboxId);
|
|
3253
|
-
sandbox._setName(info.name ?? null);
|
|
3254
3273
|
return sandbox;
|
|
3255
3274
|
}
|
|
3256
3275
|
// --- Static snapshot management ---
|
|
@@ -3274,6 +3293,26 @@ var init_sandbox = __esm({
|
|
|
3274
3293
|
);
|
|
3275
3294
|
await client.deleteSnapshot(snapshotId);
|
|
3276
3295
|
}
|
|
3296
|
+
/** List all sandboxes. No sandbox handle needed. */
|
|
3297
|
+
static async list(options) {
|
|
3298
|
+
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3299
|
+
const client = new SandboxClient2(
|
|
3300
|
+
options,
|
|
3301
|
+
/* _internal */
|
|
3302
|
+
true
|
|
3303
|
+
);
|
|
3304
|
+
return client.list();
|
|
3305
|
+
}
|
|
3306
|
+
/** List all snapshots in the project. No sandbox handle needed. */
|
|
3307
|
+
static async listSnapshots(options) {
|
|
3308
|
+
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3309
|
+
const client = new SandboxClient2(
|
|
3310
|
+
options,
|
|
3311
|
+
/* _internal */
|
|
3312
|
+
true
|
|
3313
|
+
);
|
|
3314
|
+
return client.listSnapshots();
|
|
3315
|
+
}
|
|
3277
3316
|
// --- Instance lifecycle methods ---
|
|
3278
3317
|
requireLifecycleClient(operation) {
|
|
3279
3318
|
if (!this.lifecycleClient) {
|
|
@@ -3283,6 +3322,14 @@ var init_sandbox = __esm({
|
|
|
3283
3322
|
}
|
|
3284
3323
|
return this.lifecycleClient;
|
|
3285
3324
|
}
|
|
3325
|
+
/** Fetch the current sandbox information from the server on demand. */
|
|
3326
|
+
async info() {
|
|
3327
|
+
const client = this.requireLifecycleClient("info");
|
|
3328
|
+
const info = await client.get(this.lifecycleIdentifier);
|
|
3329
|
+
this._setLifecycleIdentifier(info.sandboxId);
|
|
3330
|
+
this._setName(info.name ?? null);
|
|
3331
|
+
return info;
|
|
3332
|
+
}
|
|
3286
3333
|
/**
|
|
3287
3334
|
* Fetch the current sandbox status from the server.
|
|
3288
3335
|
*
|
|
@@ -3390,6 +3437,7 @@ var init_sandbox = __esm({
|
|
|
3390
3437
|
"/api/v1/processes/run",
|
|
3391
3438
|
{ json: body }
|
|
3392
3439
|
);
|
|
3440
|
+
const traceId = sseStream.traceId;
|
|
3393
3441
|
const stdoutLines = [];
|
|
3394
3442
|
const stderrLines = [];
|
|
3395
3443
|
let exitCode = -1;
|
|
@@ -3408,11 +3456,10 @@ var init_sandbox = __esm({
|
|
|
3408
3456
|
}
|
|
3409
3457
|
}
|
|
3410
3458
|
}
|
|
3411
|
-
return
|
|
3412
|
-
exitCode,
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
};
|
|
3459
|
+
return Object.assign(
|
|
3460
|
+
{ exitCode, stdout: stdoutLines.join("\n"), stderr: stderrLines.join("\n") },
|
|
3461
|
+
{ traceId }
|
|
3462
|
+
);
|
|
3416
3463
|
}
|
|
3417
3464
|
// --- Process management ---
|
|
3418
3465
|
/**
|
|
@@ -3442,7 +3489,7 @@ var init_sandbox = __esm({
|
|
|
3442
3489
|
"/api/v1/processes",
|
|
3443
3490
|
{ body: payload }
|
|
3444
3491
|
);
|
|
3445
|
-
return fromSnakeKeys(raw);
|
|
3492
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3446
3493
|
}
|
|
3447
3494
|
/** List all processes (running and exited) tracked by the sandbox daemon. */
|
|
3448
3495
|
async listProcesses() {
|
|
@@ -3459,7 +3506,7 @@ var init_sandbox = __esm({
|
|
|
3459
3506
|
"GET",
|
|
3460
3507
|
`/api/v1/processes/${pid}`
|
|
3461
3508
|
);
|
|
3462
|
-
return fromSnakeKeys(raw);
|
|
3509
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3463
3510
|
}
|
|
3464
3511
|
/** Send SIGKILL to a process. */
|
|
3465
3512
|
async killProcess(pid) {
|
|
@@ -3472,7 +3519,7 @@ var init_sandbox = __esm({
|
|
|
3472
3519
|
`/api/v1/processes/${pid}/signal`,
|
|
3473
3520
|
{ body: { signal } }
|
|
3474
3521
|
);
|
|
3475
|
-
return fromSnakeKeys(raw);
|
|
3522
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3476
3523
|
}
|
|
3477
3524
|
// --- Process I/O ---
|
|
3478
3525
|
/** Write bytes to a process's stdin. The process must have been started with `stdinMode: StdinMode.PIPE`. */
|
|
@@ -3492,7 +3539,7 @@ var init_sandbox = __esm({
|
|
|
3492
3539
|
"GET",
|
|
3493
3540
|
`/api/v1/processes/${pid}/stdout`
|
|
3494
3541
|
);
|
|
3495
|
-
return fromSnakeKeys(raw);
|
|
3542
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3496
3543
|
}
|
|
3497
3544
|
/** Return all captured stderr lines produced so far by a process. */
|
|
3498
3545
|
async getStderr(pid) {
|
|
@@ -3500,7 +3547,7 @@ var init_sandbox = __esm({
|
|
|
3500
3547
|
"GET",
|
|
3501
3548
|
`/api/v1/processes/${pid}/stderr`
|
|
3502
3549
|
);
|
|
3503
|
-
return fromSnakeKeys(raw);
|
|
3550
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3504
3551
|
}
|
|
3505
3552
|
/** Return all captured stdout+stderr lines produced so far by a process. */
|
|
3506
3553
|
async getOutput(pid) {
|
|
@@ -3508,7 +3555,7 @@ var init_sandbox = __esm({
|
|
|
3508
3555
|
"GET",
|
|
3509
3556
|
`/api/v1/processes/${pid}/output`
|
|
3510
3557
|
);
|
|
3511
|
-
return fromSnakeKeys(raw);
|
|
3558
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3512
3559
|
}
|
|
3513
3560
|
// --- Streaming (SSE) ---
|
|
3514
3561
|
/** Stream stdout events from a process until it exits. Yields one `OutputEvent` per line. */
|
|
@@ -3582,7 +3629,7 @@ var init_sandbox = __esm({
|
|
|
3582
3629
|
"GET",
|
|
3583
3630
|
`/api/v1/files/list?path=${encodeURIComponent(path2)}`
|
|
3584
3631
|
);
|
|
3585
|
-
return fromSnakeKeys(raw);
|
|
3632
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3586
3633
|
}
|
|
3587
3634
|
// --- PTY ---
|
|
3588
3635
|
/** Create an interactive PTY session. Returns a `sessionId` and `token` for WebSocket connection via `connectPty()`. */
|
|
@@ -3600,7 +3647,7 @@ var init_sandbox = __esm({
|
|
|
3600
3647
|
"/api/v1/pty",
|
|
3601
3648
|
{ body: payload }
|
|
3602
3649
|
);
|
|
3603
|
-
return fromSnakeKeys(raw);
|
|
3650
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3604
3651
|
}
|
|
3605
3652
|
/** Create a PTY session and connect to it immediately. Cleans up the session if the WebSocket connection fails. */
|
|
3606
3653
|
async createPty(options) {
|
|
@@ -3654,15 +3701,53 @@ var init_sandbox = __esm({
|
|
|
3654
3701
|
}
|
|
3655
3702
|
/** Connect to a sandbox VNC session for programmatic desktop control. */
|
|
3656
3703
|
async connectDesktop(options) {
|
|
3704
|
+
const port = options?.port ?? 5901;
|
|
3705
|
+
const connectTimeout = options?.connectTimeout ?? 10;
|
|
3706
|
+
const startMs = Date.now();
|
|
3707
|
+
const deadlineMs = startMs + connectTimeout * 1e3;
|
|
3708
|
+
await this.waitForPortReady(port, deadlineMs);
|
|
3709
|
+
const remainingSecs = Math.max(0.1, (deadlineMs - Date.now()) / 1e3);
|
|
3657
3710
|
return Desktop.connect({
|
|
3658
3711
|
baseUrl: this.baseUrl,
|
|
3659
3712
|
wsHeaders: this.wsHeaders,
|
|
3660
|
-
port
|
|
3713
|
+
port,
|
|
3661
3714
|
password: options?.password,
|
|
3662
3715
|
shared: options?.shared,
|
|
3663
|
-
connectTimeout:
|
|
3716
|
+
connectTimeout: remainingSecs
|
|
3664
3717
|
});
|
|
3665
3718
|
}
|
|
3719
|
+
/**
|
|
3720
|
+
* Poll the in-sandbox daemon until `127.0.0.1:port` accepts a TCP connection.
|
|
3721
|
+
* Uses `bash`'s `/dev/tcp` builtin via `processes/run` — no extra deps in
|
|
3722
|
+
* the sandbox image. `bash` is present on every image we ship.
|
|
3723
|
+
*/
|
|
3724
|
+
async waitForPortReady(port, deadlineMs) {
|
|
3725
|
+
const probeIntervalMs = 250;
|
|
3726
|
+
const probeProcessTimeoutSecs = 2;
|
|
3727
|
+
let lastError;
|
|
3728
|
+
while (Date.now() < deadlineMs) {
|
|
3729
|
+
try {
|
|
3730
|
+
const result = await this.run("/bin/bash", {
|
|
3731
|
+
args: ["-c", `exec 3<>/dev/tcp/127.0.0.1/${port}`],
|
|
3732
|
+
timeout: probeProcessTimeoutSecs
|
|
3733
|
+
});
|
|
3734
|
+
if (result.exitCode === 0) {
|
|
3735
|
+
return;
|
|
3736
|
+
}
|
|
3737
|
+
} catch (error) {
|
|
3738
|
+
lastError = error;
|
|
3739
|
+
}
|
|
3740
|
+
const remainingMs = deadlineMs - Date.now();
|
|
3741
|
+
if (remainingMs <= 0) break;
|
|
3742
|
+
await new Promise(
|
|
3743
|
+
(resolve) => setTimeout(resolve, Math.min(probeIntervalMs, remainingMs))
|
|
3744
|
+
);
|
|
3745
|
+
}
|
|
3746
|
+
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
3747
|
+
throw new SandboxError(
|
|
3748
|
+
`port ${port} did not become reachable inside sandbox within the connect timeout${detail}`
|
|
3749
|
+
);
|
|
3750
|
+
}
|
|
3666
3751
|
ptyWsUrl(sessionId, token) {
|
|
3667
3752
|
let wsBase;
|
|
3668
3753
|
if (this.baseUrl.startsWith("https://")) {
|
|
@@ -3681,15 +3766,15 @@ var init_sandbox = __esm({
|
|
|
3681
3766
|
"GET",
|
|
3682
3767
|
"/api/v1/health"
|
|
3683
3768
|
);
|
|
3684
|
-
return fromSnakeKeys(raw);
|
|
3769
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3685
3770
|
}
|
|
3686
3771
|
/** Get sandbox daemon info (version, uptime, process counts). */
|
|
3687
|
-
async
|
|
3772
|
+
async daemonInfo() {
|
|
3688
3773
|
const raw = await this.http.requestJson(
|
|
3689
3774
|
"GET",
|
|
3690
3775
|
"/api/v1/info"
|
|
3691
3776
|
);
|
|
3692
|
-
return fromSnakeKeys(raw);
|
|
3777
|
+
return Object.assign(fromSnakeKeys(raw), { traceId: raw.traceId });
|
|
3693
3778
|
}
|
|
3694
3779
|
};
|
|
3695
3780
|
}
|
|
@@ -3782,7 +3867,7 @@ var init_client = __esm({
|
|
|
3782
3867
|
this.namespace = options?.namespace ?? NAMESPACE;
|
|
3783
3868
|
this.local = isLocalhost(this.apiUrl);
|
|
3784
3869
|
this.http = new HttpClient({
|
|
3785
|
-
baseUrl: this.apiUrl,
|
|
3870
|
+
baseUrl: resolveSandboxLifecycleUrl(this.apiUrl),
|
|
3786
3871
|
apiKey: this.apiKey,
|
|
3787
3872
|
organizationId: this.organizationId,
|
|
3788
3873
|
projectId: this.projectId,
|
|
@@ -3850,7 +3935,7 @@ var init_client = __esm({
|
|
|
3850
3935
|
"GET",
|
|
3851
3936
|
this.path(`sandboxes/${sandboxId}`)
|
|
3852
3937
|
);
|
|
3853
|
-
return fromSnakeKeys(raw, "sandboxId");
|
|
3938
|
+
return Object.assign(fromSnakeKeys(raw, "sandboxId"), { traceId: raw.traceId });
|
|
3854
3939
|
}
|
|
3855
3940
|
/** List all sandboxes in the namespace. */
|
|
3856
3941
|
async list() {
|
|
@@ -3881,7 +3966,7 @@ var init_client = __esm({
|
|
|
3881
3966
|
this.path(`sandboxes/${sandboxId}`),
|
|
3882
3967
|
{ body }
|
|
3883
3968
|
);
|
|
3884
|
-
return fromSnakeKeys(raw, "sandboxId");
|
|
3969
|
+
return Object.assign(fromSnakeKeys(raw, "sandboxId"), { traceId: raw.traceId });
|
|
3885
3970
|
}
|
|
3886
3971
|
/** Get the current proxy port settings for a sandbox. */
|
|
3887
3972
|
async getPortAccess(sandboxId) {
|
|
@@ -4023,7 +4108,7 @@ var init_client = __esm({
|
|
|
4023
4108
|
"GET",
|
|
4024
4109
|
this.path(`snapshots/${snapshotId}`)
|
|
4025
4110
|
);
|
|
4026
|
-
return fromSnakeKeys(raw, "snapshotId");
|
|
4111
|
+
return Object.assign(fromSnakeKeys(raw, "snapshotId"), { traceId: raw.traceId });
|
|
4027
4112
|
}
|
|
4028
4113
|
/** List all snapshots in the namespace. */
|
|
4029
4114
|
async listSnapshots() {
|