tensorlake 0.5.135 → 0.5.136
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/applications/index.cjs +12 -12
- package/dist/applications/index.cjs.map +1 -1
- package/dist/applications/index.js +12 -12
- package/dist/applications/index.js.map +1 -1
- package/dist/function-agent/main.cjs +1 -1
- package/dist/function-agent/main.js +1 -1
- package/dist/function-executor/main.cjs +2 -2
- package/dist/function-executor/main.js +2 -2
- package/dist/index.cjs +426 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +259 -9
- package/dist/index.d.ts +259 -9
- package/dist/index.js +420 -128
- package/dist/index.js.map +1 -1
- package/dist/sandbox-image.cjs +12 -12
- package/dist/sandbox-image.cjs.map +1 -1
- package/dist/sandbox-image.js +12 -12
- package/dist/sandbox-image.js.map +1 -1
- package/package.json +7 -7
- package/runtime/function-executor/manifest.json +5 -5
- package/runtime/function-executor/package/dist/function-executor/main.js +2 -2
- package/runtime/function-executor/package/npm-shrinkwrap.json +2 -2
- package/runtime/function-executor/package/package.json +1 -1
- package/runtime/typescript-function-runner/manifest.json +5 -5
- package/runtime/typescript-function-runner/package/dist/function-agent/main.js +1 -1
- package/runtime/typescript-function-runner/package/npm-shrinkwrap.json +20 -20
- package/runtime/typescript-function-runner/package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ var init_defaults = __esm({
|
|
|
46
46
|
"src/defaults.ts"() {
|
|
47
47
|
"use strict";
|
|
48
48
|
init_esm_shims();
|
|
49
|
-
SDK_VERSION = "0.5.
|
|
49
|
+
SDK_VERSION = "0.5.136";
|
|
50
50
|
API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
|
|
51
51
|
API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
|
|
52
52
|
NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
|
|
@@ -79,7 +79,7 @@ function formatErrorDetails(errorDetails) {
|
|
|
79
79
|
}
|
|
80
80
|
return String(errorDetails);
|
|
81
81
|
}
|
|
82
|
-
var SandboxException, SandboxError, SandboxConnectionError, SandboxNotFoundError, PoolNotFoundError, PoolInUseError, RemoteAPIError, RequestNotFinishedError, RequestFailedError, RequestExecutionError;
|
|
82
|
+
var SandboxException, SandboxError, SandboxPending, SandboxConnectionError, SandboxNotFoundError, PoolNotFoundError, PoolInUseError, RemoteAPIError, RequestNotFinishedError, RequestFailedError, RequestExecutionError;
|
|
83
83
|
var init_errors = __esm({
|
|
84
84
|
"src/errors.ts"() {
|
|
85
85
|
"use strict";
|
|
@@ -91,9 +91,27 @@ var init_errors = __esm({
|
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
93
|
SandboxError = class extends SandboxException {
|
|
94
|
-
|
|
94
|
+
reason;
|
|
95
|
+
sandboxId;
|
|
96
|
+
constructor(message, options) {
|
|
95
97
|
super(message);
|
|
96
98
|
this.name = "SandboxError";
|
|
99
|
+
if (options?.reason !== void 0) this.reason = options.reason;
|
|
100
|
+
if (options?.sandboxId !== void 0) this.sandboxId = options.sandboxId;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
SandboxPending = class extends SandboxError {
|
|
104
|
+
pendingReason;
|
|
105
|
+
timeout;
|
|
106
|
+
constructor(sandboxId, options) {
|
|
107
|
+
let message = `Sandbox ${sandboxId} is still pending`;
|
|
108
|
+
if (options?.timeout !== void 0) message += ` after ${options.timeout}s`;
|
|
109
|
+
if (options?.pendingReason) message += ` (${options.pendingReason})`;
|
|
110
|
+
message += `; it keeps its place in the queue. Wait again with ready() or Sandbox.connect({ sandboxId: '${sandboxId}' }), or delete it to cancel.`;
|
|
111
|
+
super(message, { reason: options?.pendingReason, sandboxId });
|
|
112
|
+
this.name = "SandboxPending";
|
|
113
|
+
this.pendingReason = options?.pendingReason;
|
|
114
|
+
this.timeout = options?.timeout;
|
|
97
115
|
}
|
|
98
116
|
};
|
|
99
117
|
SandboxConnectionError = class extends SandboxError {
|
|
@@ -104,11 +122,9 @@ var init_errors = __esm({
|
|
|
104
122
|
}
|
|
105
123
|
};
|
|
106
124
|
SandboxNotFoundError = class extends SandboxError {
|
|
107
|
-
sandboxId;
|
|
108
125
|
constructor(sandboxId) {
|
|
109
|
-
super(`Sandbox not found: ${sandboxId}
|
|
126
|
+
super(`Sandbox not found: ${sandboxId}`, { sandboxId });
|
|
110
127
|
this.name = "SandboxNotFoundError";
|
|
111
|
-
this.sandboxId = sandboxId;
|
|
112
128
|
}
|
|
113
129
|
};
|
|
114
130
|
PoolNotFoundError = class extends SandboxError {
|
|
@@ -132,9 +148,6 @@ var init_errors = __esm({
|
|
|
132
148
|
statusCode;
|
|
133
149
|
/** Original response body, retained for compatibility and diagnostics. */
|
|
134
150
|
responseMessage;
|
|
135
|
-
sandboxId;
|
|
136
|
-
/** Server reason, including unknown future reasons. */
|
|
137
|
-
reason;
|
|
138
151
|
errorDetails;
|
|
139
152
|
constructor(statusCode, message) {
|
|
140
153
|
let failure;
|
|
@@ -159,9 +172,10 @@ var init_errors = __esm({
|
|
|
159
172
|
if (detail) displayMessage += `: ${detail}`;
|
|
160
173
|
if (!reason && !detail) displayMessage = message;
|
|
161
174
|
}
|
|
162
|
-
super(`API error (status ${statusCode}): ${displayMessage}
|
|
163
|
-
|
|
164
|
-
|
|
175
|
+
super(`API error (status ${statusCode}): ${displayMessage}`, {
|
|
176
|
+
reason,
|
|
177
|
+
sandboxId
|
|
178
|
+
});
|
|
165
179
|
this.errorDetails = errorDetails;
|
|
166
180
|
this.name = "RemoteAPIError";
|
|
167
181
|
this.statusCode = statusCode;
|
|
@@ -457,7 +471,7 @@ var init_native_worker_client = __esm({
|
|
|
457
471
|
}
|
|
458
472
|
};
|
|
459
473
|
runtimeKey = /* @__PURE__ */ Symbol.for(
|
|
460
|
-
`tensorlake.native.worker.${false ? "source" : "0.5.
|
|
474
|
+
`tensorlake.native.worker.${false ? "source" : "0.5.136"}.v1`
|
|
461
475
|
);
|
|
462
476
|
runtimes = globalThis;
|
|
463
477
|
}
|
|
@@ -609,6 +623,9 @@ var init_native_sandbox = __esm({
|
|
|
609
623
|
});
|
|
610
624
|
|
|
611
625
|
// src/models.ts
|
|
626
|
+
function isSandboxPending(status) {
|
|
627
|
+
return String(status) === "pending" /* PENDING */;
|
|
628
|
+
}
|
|
612
629
|
function camelToSnake(str) {
|
|
613
630
|
return str.replace(CAMEL_TO_SNAKE_RE, (ch) => "_" + ch.toLowerCase());
|
|
614
631
|
}
|
|
@@ -665,7 +682,7 @@ function fromSnakeKeys(obj, idField) {
|
|
|
665
682
|
}
|
|
666
683
|
return obj;
|
|
667
684
|
}
|
|
668
|
-
var SandboxStatus, SnapshotStatus, ProcessStatus, StdinMode, OutputMode, ContainerState, CAMEL_TO_SNAKE_RE;
|
|
685
|
+
var SandboxStatus, SandboxPendingReason, TERMINATION_REASON_NO_CAPACITY, TERMINATION_REASON_CANCELLED, SnapshotStatus, ProcessStatus, StdinMode, OutputMode, ContainerState, CAMEL_TO_SNAKE_RE;
|
|
669
686
|
var init_models = __esm({
|
|
670
687
|
"src/models.ts"() {
|
|
671
688
|
"use strict";
|
|
@@ -681,6 +698,19 @@ var init_models = __esm({
|
|
|
681
698
|
SandboxStatus2["FAILED"] = "failed";
|
|
682
699
|
return SandboxStatus2;
|
|
683
700
|
})(SandboxStatus || {});
|
|
701
|
+
SandboxPendingReason = /* @__PURE__ */ ((SandboxPendingReason2) => {
|
|
702
|
+
SandboxPendingReason2["SCHEDULING"] = "scheduling";
|
|
703
|
+
SandboxPendingReason2["WAITING_FOR_CONTAINER"] = "waiting_for_container";
|
|
704
|
+
SandboxPendingReason2["NO_EXECUTORS_AVAILABLE"] = "no_executors_available";
|
|
705
|
+
SandboxPendingReason2["NO_RESOURCES_AVAILABLE"] = "no_resources_available";
|
|
706
|
+
SandboxPendingReason2["POOL_AT_CAPACITY"] = "pool_at_capacity";
|
|
707
|
+
SandboxPendingReason2["MAX_CAPACITY_REACHED"] = "max_capacity_reached";
|
|
708
|
+
SandboxPendingReason2["NO_EXECUTOR_FOR_SNAPSHOT_LOCATION"] = "no_executor_for_snapshot_location";
|
|
709
|
+
SandboxPendingReason2["UNPLACEABLE"] = "unplaceable";
|
|
710
|
+
return SandboxPendingReason2;
|
|
711
|
+
})(SandboxPendingReason || {});
|
|
712
|
+
TERMINATION_REASON_NO_CAPACITY = "no_capacity";
|
|
713
|
+
TERMINATION_REASON_CANCELLED = "cancelled";
|
|
684
714
|
SnapshotStatus = /* @__PURE__ */ ((SnapshotStatus2) => {
|
|
685
715
|
SnapshotStatus2["IN_PROGRESS"] = "in_progress";
|
|
686
716
|
SnapshotStatus2["LOCAL_READY"] = "local_ready";
|
|
@@ -714,6 +744,64 @@ var init_models = __esm({
|
|
|
714
744
|
}
|
|
715
745
|
});
|
|
716
746
|
|
|
747
|
+
// src/pending-sandbox.ts
|
|
748
|
+
var PendingSandbox;
|
|
749
|
+
var init_pending_sandbox = __esm({
|
|
750
|
+
"src/pending-sandbox.ts"() {
|
|
751
|
+
"use strict";
|
|
752
|
+
init_esm_shims();
|
|
753
|
+
PendingSandbox = class {
|
|
754
|
+
/** @internal */
|
|
755
|
+
constructor(record, binding) {
|
|
756
|
+
this.binding = binding;
|
|
757
|
+
this.sandboxId = record.sandboxId;
|
|
758
|
+
this.name = record.name;
|
|
759
|
+
this.state = record.state;
|
|
760
|
+
this.pendingReason = record.pendingReason;
|
|
761
|
+
this.routingHint = record.routingHint;
|
|
762
|
+
this.ingressEndpoint = record.ingressEndpoint;
|
|
763
|
+
this.sandboxUrl = record.sandboxUrl;
|
|
764
|
+
this.reason = record.reason;
|
|
765
|
+
this.terminationReason = record.terminationReason;
|
|
766
|
+
this.errorDetails = record.errorDetails;
|
|
767
|
+
this.traceId = binding.traceId;
|
|
768
|
+
}
|
|
769
|
+
sandboxId;
|
|
770
|
+
name;
|
|
771
|
+
state;
|
|
772
|
+
pendingReason;
|
|
773
|
+
routingHint;
|
|
774
|
+
ingressEndpoint;
|
|
775
|
+
sandboxUrl;
|
|
776
|
+
reason;
|
|
777
|
+
terminationReason;
|
|
778
|
+
errorDetails;
|
|
779
|
+
/** W3C trace id of the create request. */
|
|
780
|
+
traceId;
|
|
781
|
+
/** Fetch the sandbox's current state with one `GET`. */
|
|
782
|
+
async status() {
|
|
783
|
+
return this.binding.client.get(this.sandboxId);
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Wait for the sandbox to be running and return a connected `Sandbox`.
|
|
787
|
+
*
|
|
788
|
+
* Polls `GET /sandboxes/{id}` every `pollInterval` seconds (default 2).
|
|
789
|
+
* Call it again after a `SandboxPending` to keep waiting.
|
|
790
|
+
*
|
|
791
|
+
* @throws {SandboxPending} `timeout` elapsed while the sandbox was still
|
|
792
|
+
* pending. It keeps its place in the queue; the error carries
|
|
793
|
+
* `sandboxId` and `pendingReason`.
|
|
794
|
+
* @throws {SandboxError} The sandbox settled somewhere else: `terminated`
|
|
795
|
+
* or `failed` (`reason` is the server's, such as `no_capacity` or
|
|
796
|
+
* `cancelled`), or `suspended`.
|
|
797
|
+
*/
|
|
798
|
+
async ready(options) {
|
|
799
|
+
return this.binding.client._ready(this.sandboxId, this.binding, options);
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
|
|
717
805
|
// src/tunnel.ts
|
|
718
806
|
import * as net from "net";
|
|
719
807
|
import WebSocket from "ws";
|
|
@@ -3635,17 +3723,10 @@ var init_sandbox = __esm({
|
|
|
3635
3723
|
this.ownsSandbox = true;
|
|
3636
3724
|
this.lifecycleClient = client;
|
|
3637
3725
|
}
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
* Covers both fresh sandbox creation and restore-from-snapshot (set
|
|
3643
|
-
* `snapshotId`). Blocks until the sandbox is `Running`.
|
|
3644
|
-
*
|
|
3645
|
-
* When `name` is already claimed, the server rejects the create with
|
|
3646
|
-
* HTTP 409 (`RemoteAPIError`). To attach to the existing sandbox
|
|
3647
|
-
* instead, use {@link Sandbox.getOrCreate}.
|
|
3648
|
-
*/
|
|
3726
|
+
/** @internal Used by PendingSandbox.ready for a non-owning handle. */
|
|
3727
|
+
_setLifecycleClient(client) {
|
|
3728
|
+
this.lifecycleClient = client;
|
|
3729
|
+
}
|
|
3649
3730
|
static async create(options) {
|
|
3650
3731
|
const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
3651
3732
|
const client = new SandboxClient2(
|
|
@@ -3653,6 +3734,19 @@ var init_sandbox = __esm({
|
|
|
3653
3734
|
/* _internal */
|
|
3654
3735
|
true
|
|
3655
3736
|
);
|
|
3737
|
+
if (options?.wait === false) {
|
|
3738
|
+
if (options.poolId != null) {
|
|
3739
|
+
throw new SandboxError(
|
|
3740
|
+
"wait: false cannot be combined with poolId: a pool claim is answered synchronously"
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
const requestTimeout = options.requestTimeout ?? options.startupTimeout ?? void 0;
|
|
3744
|
+
return client.requestPending(options, {
|
|
3745
|
+
proxyUrl: options.proxyUrl,
|
|
3746
|
+
requestTimeout,
|
|
3747
|
+
ownsSandbox: true
|
|
3748
|
+
});
|
|
3749
|
+
}
|
|
3656
3750
|
return client.createAndConnect(options);
|
|
3657
3751
|
}
|
|
3658
3752
|
/**
|
|
@@ -3943,6 +4037,7 @@ var init_sandbox = __esm({
|
|
|
3943
4037
|
*/
|
|
3944
4038
|
async refreshRoutingWhenRunning(deadline, pollInterval, timeout) {
|
|
3945
4039
|
const client = this.requireLifecycleClient("refresh proxy routing");
|
|
4040
|
+
let last;
|
|
3946
4041
|
while (Date.now() < deadline) {
|
|
3947
4042
|
const info = await client.get(this.lifecycleIdentifier);
|
|
3948
4043
|
if (info.status === "running" /* RUNNING */ && (info.sandboxUrl != null || this.proxy.hasExplicitProxyUrl())) {
|
|
@@ -3951,13 +4046,22 @@ var init_sandbox = __esm({
|
|
|
3951
4046
|
}
|
|
3952
4047
|
if (info.status === "terminated" /* TERMINATED */) {
|
|
3953
4048
|
throw new SandboxError(
|
|
3954
|
-
`Sandbox ${this.lifecycleIdentifier} terminated while refreshing proxy routing
|
|
4049
|
+
`Sandbox ${this.lifecycleIdentifier} terminated while refreshing proxy routing`,
|
|
4050
|
+
{ reason: info.terminationReason, sandboxId: info.sandboxId }
|
|
3955
4051
|
);
|
|
3956
4052
|
}
|
|
4053
|
+
last = info;
|
|
3957
4054
|
await sleep(Math.min(pollInterval * 1e3, Math.max(0, deadline - Date.now())));
|
|
3958
4055
|
}
|
|
4056
|
+
if (last?.status === "pending" /* PENDING */) {
|
|
4057
|
+
throw new SandboxPending(last.sandboxId, {
|
|
4058
|
+
pendingReason: last.pendingReason,
|
|
4059
|
+
timeout
|
|
4060
|
+
});
|
|
4061
|
+
}
|
|
3959
4062
|
throw new SandboxError(
|
|
3960
|
-
`Sandbox ${this.lifecycleIdentifier} did not provide refreshed proxy routing within ${timeout}s
|
|
4063
|
+
`Sandbox ${this.lifecycleIdentifier} did not provide refreshed proxy routing within ${timeout}s`,
|
|
4064
|
+
{ sandboxId: this.lifecycleIdentifier }
|
|
3961
4065
|
);
|
|
3962
4066
|
}
|
|
3963
4067
|
/** Live-copy this running sandbox. */
|
|
@@ -4452,6 +4556,7 @@ var init_sandbox = __esm({
|
|
|
4452
4556
|
// src/client.ts
|
|
4453
4557
|
var client_exports = {};
|
|
4454
4558
|
__export(client_exports, {
|
|
4559
|
+
DEFAULT_WAIT_POLL_INTERVAL_SEC: () => DEFAULT_WAIT_POLL_INTERVAL_SEC,
|
|
4455
4560
|
SandboxClient: () => SandboxClient
|
|
4456
4561
|
});
|
|
4457
4562
|
function requireReadOnlySnapshotPin(fileSystemId, mountPath, readOnly, snapshotId) {
|
|
@@ -4490,6 +4595,12 @@ function gpuRequest(gpu, gpus, gpuModel) {
|
|
|
4490
4595
|
}
|
|
4491
4596
|
return [{ count: gpus, model: gpuModel }];
|
|
4492
4597
|
}
|
|
4598
|
+
function startupFailure(sandboxId, status, options) {
|
|
4599
|
+
return new SandboxError(formatStartupFailureMessage(sandboxId, status, options), {
|
|
4600
|
+
reason: options.terminationReason,
|
|
4601
|
+
sandboxId
|
|
4602
|
+
});
|
|
4603
|
+
}
|
|
4493
4604
|
function resolveRequestTimeoutMs(options) {
|
|
4494
4605
|
if (options?.requestTimeout != null) {
|
|
4495
4606
|
return secondsToMillis3(options.requestTimeout);
|
|
@@ -4550,7 +4661,7 @@ function validateUserPort(port) {
|
|
|
4550
4661
|
function dedupeAndSortPorts(ports) {
|
|
4551
4662
|
return [...new Set(ports)].sort((a, b) => a - b);
|
|
4552
4663
|
}
|
|
4553
|
-
var GPU_MODELS, SandboxClient, RESERVED_SANDBOX_MANAGEMENT_PORT;
|
|
4664
|
+
var DEFAULT_WAIT_POLL_INTERVAL_SEC, GPU_MODELS, SandboxClient, RESERVED_SANDBOX_MANAGEMENT_PORT;
|
|
4554
4665
|
var init_client = __esm({
|
|
4555
4666
|
"src/client.ts"() {
|
|
4556
4667
|
"use strict";
|
|
@@ -4560,9 +4671,11 @@ var init_client = __esm({
|
|
|
4560
4671
|
init_native_worker_client();
|
|
4561
4672
|
init_native_sandbox();
|
|
4562
4673
|
init_models();
|
|
4674
|
+
init_pending_sandbox();
|
|
4563
4675
|
init_sandbox();
|
|
4564
4676
|
init_sdk_timings();
|
|
4565
4677
|
init_url();
|
|
4678
|
+
DEFAULT_WAIT_POLL_INTERVAL_SEC = 2;
|
|
4566
4679
|
GPU_MODELS = /* @__PURE__ */ new Set([
|
|
4567
4680
|
"A100-40GB",
|
|
4568
4681
|
"A100-80GB",
|
|
@@ -4665,9 +4778,155 @@ var init_client = __esm({
|
|
|
4665
4778
|
const { json } = await callNative(fn, context);
|
|
4666
4779
|
return fromSnakeKeys(JSON.parse(json), idField);
|
|
4667
4780
|
}
|
|
4668
|
-
// --- Sandbox CRUD ---
|
|
4669
|
-
/** Create a new sandbox. Returns immediately; the sandbox may still be starting. Use `createAndConnect()` for a blocking, ready-to-use handle. */
|
|
4670
4781
|
async create(options) {
|
|
4782
|
+
if (options?.wait === false) {
|
|
4783
|
+
return this.requestPending(options, { ownsSandbox: false });
|
|
4784
|
+
}
|
|
4785
|
+
const body = _SandboxClient.buildCreateRequestBody(options);
|
|
4786
|
+
return this.tracedJson(
|
|
4787
|
+
() => this.native.createSandbox(JSON.stringify(body)),
|
|
4788
|
+
"sandboxId"
|
|
4789
|
+
);
|
|
4790
|
+
}
|
|
4791
|
+
/**
|
|
4792
|
+
* @internal Send the create with `wait: false` and return the pending
|
|
4793
|
+
* handle, bound to this client so `ready()` / `status()` work.
|
|
4794
|
+
*/
|
|
4795
|
+
async requestPending(options, binding) {
|
|
4796
|
+
const body = _SandboxClient.buildCreateRequestBody({
|
|
4797
|
+
...options,
|
|
4798
|
+
wait: false
|
|
4799
|
+
});
|
|
4800
|
+
const record = await this.tracedJson(
|
|
4801
|
+
() => this.native.createSandboxNoWait(JSON.stringify(body))
|
|
4802
|
+
);
|
|
4803
|
+
return new PendingSandbox(record, {
|
|
4804
|
+
client: this,
|
|
4805
|
+
proxyUrl: binding.proxyUrl,
|
|
4806
|
+
requestTimeout: binding.requestTimeout,
|
|
4807
|
+
requestedName: options?.name ?? null,
|
|
4808
|
+
ownsSandbox: binding.ownsSandbox,
|
|
4809
|
+
traceId: record.traceId
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
/** @internal Implementation of `PendingSandbox.ready`. */
|
|
4813
|
+
async _ready(sandboxId, binding, options) {
|
|
4814
|
+
const budget = options?.timeout ?? this.requestTimeoutMs / 1e3;
|
|
4815
|
+
const observed = await this.waitForSandbox(
|
|
4816
|
+
sandboxId,
|
|
4817
|
+
budget,
|
|
4818
|
+
options?.pollInterval ?? DEFAULT_WAIT_POLL_INTERVAL_SEC
|
|
4819
|
+
);
|
|
4820
|
+
return this.settleWait(observed, {
|
|
4821
|
+
budget,
|
|
4822
|
+
proxyUrl: binding.proxyUrl,
|
|
4823
|
+
requestTimeout: binding.requestTimeout,
|
|
4824
|
+
cancelOnTimeout: options?.cancelOnTimeout ?? false,
|
|
4825
|
+
requestedName: binding.requestedName,
|
|
4826
|
+
ownsSandbox: binding.ownsSandbox,
|
|
4827
|
+
traceId: binding.traceId
|
|
4828
|
+
});
|
|
4829
|
+
}
|
|
4830
|
+
/**
|
|
4831
|
+
* Poll `get` every `pollInterval` seconds until the sandbox leaves
|
|
4832
|
+
* `pending` or `timeout` elapses, resolving with the last observation.
|
|
4833
|
+
* Never rejects for a timeout and never deletes.
|
|
4834
|
+
*/
|
|
4835
|
+
async waitForSandbox(sandboxId, timeout, pollInterval) {
|
|
4836
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
4837
|
+
throw new SandboxError("timeout must be a non-negative number of seconds");
|
|
4838
|
+
}
|
|
4839
|
+
if (!Number.isFinite(pollInterval) || pollInterval <= 0) {
|
|
4840
|
+
throw new SandboxError("pollInterval must be a positive number of seconds");
|
|
4841
|
+
}
|
|
4842
|
+
return this.tracedJson(
|
|
4843
|
+
() => this.native.waitForSandbox(sandboxId, timeout, pollInterval),
|
|
4844
|
+
"sandboxId",
|
|
4845
|
+
{ sandboxId, notFoundKind: "sandbox" }
|
|
4846
|
+
);
|
|
4847
|
+
}
|
|
4848
|
+
/** Turn the last observed sandbox state into a handle or an error. */
|
|
4849
|
+
async settleWait(observed, options) {
|
|
4850
|
+
const { status, sandboxId } = observed;
|
|
4851
|
+
if (isSandboxPending(status)) {
|
|
4852
|
+
if (options.cancelOnTimeout) {
|
|
4853
|
+
try {
|
|
4854
|
+
await this.delete(sandboxId);
|
|
4855
|
+
} catch {
|
|
4856
|
+
}
|
|
4857
|
+
throw new SandboxError(
|
|
4858
|
+
`Sandbox ${sandboxId} did not start within ${options.budget}s`,
|
|
4859
|
+
{ reason: observed.pendingReason, sandboxId }
|
|
4860
|
+
);
|
|
4861
|
+
}
|
|
4862
|
+
throw new SandboxPending(sandboxId, {
|
|
4863
|
+
pendingReason: observed.pendingReason,
|
|
4864
|
+
timeout: options.budget
|
|
4865
|
+
});
|
|
4866
|
+
}
|
|
4867
|
+
if (status === "running" /* RUNNING */) {
|
|
4868
|
+
const explicitProxyUrl = options.proxyUrl ?? explicitProxyUrlOverride() ?? void 0;
|
|
4869
|
+
const selectedProxyUrl = await this.native.selectSandboxProxyUrl(
|
|
4870
|
+
sandboxId,
|
|
4871
|
+
observed.sandboxUrl ?? null,
|
|
4872
|
+
observed.ingressEndpoint ?? null,
|
|
4873
|
+
explicitProxyUrl ?? null
|
|
4874
|
+
);
|
|
4875
|
+
const sandbox = this.connect(
|
|
4876
|
+
sandboxId,
|
|
4877
|
+
selectedProxyUrl,
|
|
4878
|
+
observed.routingHint,
|
|
4879
|
+
options.requestTimeout,
|
|
4880
|
+
explicitProxyUrl
|
|
4881
|
+
);
|
|
4882
|
+
if (options.ownsSandbox) sandbox._setOwner(this);
|
|
4883
|
+
else sandbox._setLifecycleClient(this);
|
|
4884
|
+
sandbox.traceId = options.traceId ?? observed.traceId;
|
|
4885
|
+
sandbox._setLifecycleIdentifier(sandboxId);
|
|
4886
|
+
sandbox._setName(observed.name ?? options.requestedName ?? null);
|
|
4887
|
+
return sandbox;
|
|
4888
|
+
}
|
|
4889
|
+
if (status === "terminated" /* TERMINATED */ || status === "failed" /* FAILED */) {
|
|
4890
|
+
throw startupFailure(sandboxId, status, {
|
|
4891
|
+
errorDetails: observed.errorDetails,
|
|
4892
|
+
terminationReason: observed.terminationReason
|
|
4893
|
+
});
|
|
4894
|
+
}
|
|
4895
|
+
throw new SandboxError(
|
|
4896
|
+
`Sandbox ${sandboxId} is ${status}, not running; ` + (status === "suspended" /* SUSPENDED */ ? "resume it to run it again" : "wait for it to settle"),
|
|
4897
|
+
{ reason: String(status), sandboxId }
|
|
4898
|
+
);
|
|
4899
|
+
}
|
|
4900
|
+
/**
|
|
4901
|
+
* Routing for a lazy `connect` handle. A sandbox that is still pending is
|
|
4902
|
+
* waited on here rather than failing: readiness is a property of the
|
|
4903
|
+
* sandbox, not of the create call that requested it.
|
|
4904
|
+
*/
|
|
4905
|
+
async resolveRoutingInfo(identifier, requestTimeout) {
|
|
4906
|
+
const info = await this.get(identifier);
|
|
4907
|
+
if (info.status !== "pending" /* PENDING */) return info;
|
|
4908
|
+
const budget = requestTimeout ?? this.requestTimeoutMs / 1e3;
|
|
4909
|
+
const observed = await this.waitForSandbox(
|
|
4910
|
+
info.sandboxId,
|
|
4911
|
+
budget,
|
|
4912
|
+
DEFAULT_WAIT_POLL_INTERVAL_SEC
|
|
4913
|
+
);
|
|
4914
|
+
if (isSandboxPending(observed.status)) {
|
|
4915
|
+
throw new SandboxPending(observed.sandboxId, {
|
|
4916
|
+
pendingReason: observed.pendingReason,
|
|
4917
|
+
timeout: budget
|
|
4918
|
+
});
|
|
4919
|
+
}
|
|
4920
|
+
if (observed.status === "terminated" /* TERMINATED */ || observed.status === "failed" /* FAILED */) {
|
|
4921
|
+
throw startupFailure(observed.sandboxId, observed.status, {
|
|
4922
|
+
errorDetails: observed.errorDetails,
|
|
4923
|
+
terminationReason: observed.terminationReason
|
|
4924
|
+
});
|
|
4925
|
+
}
|
|
4926
|
+
return observed;
|
|
4927
|
+
}
|
|
4928
|
+
/** @internal Build the create wire body; shared by `create` and `createAndConnect`. */
|
|
4929
|
+
static buildCreateRequestBody(options) {
|
|
4671
4930
|
const gpuResources = gpuRequest(
|
|
4672
4931
|
options?.gpu,
|
|
4673
4932
|
options?.gpus,
|
|
@@ -4697,10 +4956,14 @@ var init_client = __esm({
|
|
|
4697
4956
|
deny_out: options?.denyOut ?? []
|
|
4698
4957
|
};
|
|
4699
4958
|
}
|
|
4700
|
-
|
|
4701
|
-
()
|
|
4702
|
-
|
|
4703
|
-
|
|
4959
|
+
if (options?.maxPendingSecs != null) {
|
|
4960
|
+
if (!Number.isInteger(options.maxPendingSecs) || options.maxPendingSecs < 0) {
|
|
4961
|
+
throw new SandboxError("maxPendingSecs must be a non-negative integer");
|
|
4962
|
+
}
|
|
4963
|
+
body.max_pending_secs = options.maxPendingSecs;
|
|
4964
|
+
}
|
|
4965
|
+
if (options?.wait === false) body.wait = false;
|
|
4966
|
+
return body;
|
|
4704
4967
|
}
|
|
4705
4968
|
/** Get current state and metadata for a sandbox by ID. */
|
|
4706
4969
|
async get(sandboxId) {
|
|
@@ -5148,7 +5411,7 @@ var init_client = __esm({
|
|
|
5148
5411
|
organizationId: this.organizationId,
|
|
5149
5412
|
projectId: this.projectId,
|
|
5150
5413
|
routingHint,
|
|
5151
|
-
resolveProxyInfo: async (currentIdentifier) => this.
|
|
5414
|
+
resolveProxyInfo: async (currentIdentifier) => this.resolveRoutingInfo(currentIdentifier, requestTimeout),
|
|
5152
5415
|
requestTimeout,
|
|
5153
5416
|
nativeClient: this.native
|
|
5154
5417
|
});
|
|
@@ -5156,123 +5419,145 @@ var init_client = __esm({
|
|
|
5156
5419
|
/**
|
|
5157
5420
|
* Create a sandbox, wait for it to reach `Running`, and return a connected handle.
|
|
5158
5421
|
*
|
|
5159
|
-
*
|
|
5160
|
-
* `
|
|
5422
|
+
* This is `create({ wait: false })` followed by `PendingSandbox.ready()`
|
|
5423
|
+
* polling every `pollInterval` seconds, with `requestTimeout` as the wait
|
|
5424
|
+
* budget, in one call. The returned `Sandbox` auto-terminates when
|
|
5425
|
+
* `terminate()` is called.
|
|
5426
|
+
*
|
|
5427
|
+
* **When the wait runs out the sandbox is not deleted.** A `SandboxPending`
|
|
5428
|
+
* is thrown with the sandbox id, and the sandbox keeps its place in the
|
|
5429
|
+
* queue and starts whenever capacity arrives; `connect` with that id to
|
|
5430
|
+
* collect it, or `delete` it to give up. Pass
|
|
5431
|
+
* `cancelOnTimeout: true` for the previous behaviour (delete, then throw
|
|
5432
|
+
* `SandboxError`), or set `maxPendingSecs` to let the server fail it after
|
|
5433
|
+
* a bound. A pool claim (`poolId`) answers from the server-side wait; a
|
|
5434
|
+
* claim that is still starting is then waited on the same way.
|
|
5161
5435
|
*/
|
|
5162
5436
|
async createAndConnect(options) {
|
|
5163
5437
|
const opStart = nowMs();
|
|
5164
5438
|
const requestTimeout = options?.requestTimeout ?? options?.startupTimeout ?? this.requestTimeoutMs / 1e3;
|
|
5165
5439
|
const requestClient = this.withRequestTimeout(requestTimeout);
|
|
5440
|
+
const deadline = Date.now() + secondsToMillis3(requestTimeout);
|
|
5166
5441
|
logSdkTimingEvent("sandbox.create", "start", {
|
|
5167
5442
|
request_timeout_s: requestTimeout,
|
|
5168
5443
|
image: options?.image,
|
|
5169
5444
|
pool_id: options?.poolId
|
|
5170
5445
|
});
|
|
5446
|
+
const requestedName = options?.poolId != null ? null : options?.name ?? null;
|
|
5447
|
+
let sandboxId;
|
|
5448
|
+
let traceId;
|
|
5171
5449
|
const createStart = nowMs();
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
"sandbox.create",
|
|
5177
|
-
options?.poolId != null ? "claim_response" : "create_response",
|
|
5178
|
-
createStart,
|
|
5179
|
-
{
|
|
5450
|
+
if (options?.poolId != null) {
|
|
5451
|
+
const result = await requestClient.claim(options.poolId, {
|
|
5452
|
+
fileSystems: options.fileSystems
|
|
5453
|
+
});
|
|
5454
|
+
logSdkTiming("sandbox.create", "claim_response", createStart, {
|
|
5180
5455
|
sandbox_id: result.sandboxId,
|
|
5181
5456
|
status: result.status,
|
|
5182
5457
|
server_trace_id: result.traceId
|
|
5183
|
-
}
|
|
5184
|
-
);
|
|
5185
|
-
const requestedName = options?.poolId != null ? null : options?.name ?? null;
|
|
5186
|
-
const finishConnect = async (sandboxId, routingHint, name, ingressEndpoint, sandboxUrl) => {
|
|
5187
|
-
const explicitProxyUrl = options?.proxyUrl ?? explicitProxyUrlOverride() ?? void 0;
|
|
5188
|
-
const selectedProxyUrl = await this.native.selectSandboxProxyUrl(
|
|
5189
|
-
sandboxId,
|
|
5190
|
-
sandboxUrl ?? null,
|
|
5191
|
-
ingressEndpoint ?? null,
|
|
5192
|
-
explicitProxyUrl ?? null
|
|
5193
|
-
);
|
|
5194
|
-
const sandbox = requestClient.connect(
|
|
5195
|
-
sandboxId,
|
|
5196
|
-
selectedProxyUrl,
|
|
5197
|
-
routingHint,
|
|
5198
|
-
requestTimeout,
|
|
5199
|
-
explicitProxyUrl
|
|
5200
|
-
);
|
|
5201
|
-
sandbox._setOwner(requestClient);
|
|
5202
|
-
sandbox.traceId = result.traceId;
|
|
5203
|
-
sandbox._setLifecycleIdentifier(sandboxId);
|
|
5204
|
-
sandbox._setName(name ?? requestedName);
|
|
5205
|
-
logSdkTiming("sandbox.create", "complete", opStart, {
|
|
5206
|
-
sandbox_id: sandboxId,
|
|
5207
|
-
status: "running" /* RUNNING */,
|
|
5208
|
-
server_trace_id: result.traceId,
|
|
5209
|
-
routing_hint: routingHint,
|
|
5210
|
-
ingress_endpoint: ingressEndpoint,
|
|
5211
|
-
sandbox_url: sandboxUrl
|
|
5212
5458
|
});
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5459
|
+
if (result.status === "running" /* RUNNING */) {
|
|
5460
|
+
const explicitProxyUrl = options?.proxyUrl ?? explicitProxyUrlOverride() ?? void 0;
|
|
5461
|
+
const selectedProxyUrl = await this.native.selectSandboxProxyUrl(
|
|
5462
|
+
result.sandboxId,
|
|
5463
|
+
result.sandboxUrl ?? null,
|
|
5464
|
+
result.ingressEndpoint ?? null,
|
|
5465
|
+
explicitProxyUrl ?? null
|
|
5466
|
+
);
|
|
5467
|
+
const sandbox2 = requestClient.connect(
|
|
5468
|
+
result.sandboxId,
|
|
5469
|
+
selectedProxyUrl,
|
|
5470
|
+
result.routingHint,
|
|
5471
|
+
requestTimeout,
|
|
5472
|
+
explicitProxyUrl
|
|
5473
|
+
);
|
|
5474
|
+
sandbox2._setOwner(requestClient);
|
|
5475
|
+
sandbox2.traceId = result.traceId;
|
|
5476
|
+
sandbox2._setLifecycleIdentifier(result.sandboxId);
|
|
5477
|
+
sandbox2._setName(result.name ?? requestedName);
|
|
5478
|
+
logSdkTiming("sandbox.create", "complete", opStart, {
|
|
5479
|
+
sandbox_id: result.sandboxId,
|
|
5480
|
+
status: "running" /* RUNNING */,
|
|
5481
|
+
server_trace_id: result.traceId
|
|
5482
|
+
});
|
|
5483
|
+
return sandbox2;
|
|
5484
|
+
}
|
|
5485
|
+
if (result.status === "suspended" /* SUSPENDED */ || result.status === "terminated" /* TERMINATED */ || result.status === "failed" /* FAILED */) {
|
|
5486
|
+
throw startupFailure(result.sandboxId, result.status, {
|
|
5227
5487
|
errorDetails: result.errorDetails,
|
|
5228
5488
|
terminationReason: result.terminationReason ?? result.reason
|
|
5229
|
-
})
|
|
5230
|
-
);
|
|
5231
|
-
}
|
|
5232
|
-
if (result.status === "timeout" /* TIMEOUT */) {
|
|
5233
|
-
try {
|
|
5234
|
-
await requestClient.delete(result.sandboxId);
|
|
5235
|
-
} catch {
|
|
5489
|
+
});
|
|
5236
5490
|
}
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
while (Date.now() < deadline) {
|
|
5243
|
-
const pollStart = nowMs();
|
|
5244
|
-
const info = await requestClient.get(result.sandboxId);
|
|
5245
|
-
logSdkTiming("sandbox.create", "poll_response", pollStart, {
|
|
5246
|
-
sandbox_id: result.sandboxId,
|
|
5247
|
-
status: info.status,
|
|
5248
|
-
server_trace_id: info.traceId
|
|
5491
|
+
sandboxId = result.sandboxId;
|
|
5492
|
+
traceId = result.traceId;
|
|
5493
|
+
} else {
|
|
5494
|
+
const pending = await requestClient.requestPending(options, {
|
|
5495
|
+
ownsSandbox: true
|
|
5249
5496
|
});
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5497
|
+
logSdkTiming("sandbox.create", "create_response", createStart, {
|
|
5498
|
+
sandbox_id: pending.sandboxId,
|
|
5499
|
+
status: pending.state,
|
|
5500
|
+
server_trace_id: pending.traceId
|
|
5501
|
+
});
|
|
5502
|
+
sandboxId = pending.sandboxId;
|
|
5503
|
+
traceId = pending.traceId;
|
|
5504
|
+
if (pending.state === "running" /* RUNNING */) {
|
|
5505
|
+
const explicitProxyUrl = options?.proxyUrl ?? explicitProxyUrlOverride() ?? void 0;
|
|
5506
|
+
const selectedProxyUrl = await this.native.selectSandboxProxyUrl(
|
|
5507
|
+
sandboxId,
|
|
5508
|
+
pending.sandboxUrl ?? null,
|
|
5509
|
+
pending.ingressEndpoint ?? null,
|
|
5510
|
+
explicitProxyUrl ?? null
|
|
5257
5511
|
);
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
})
|
|
5512
|
+
const sandbox2 = requestClient.connect(
|
|
5513
|
+
sandboxId,
|
|
5514
|
+
selectedProxyUrl,
|
|
5515
|
+
pending.routingHint,
|
|
5516
|
+
requestTimeout,
|
|
5517
|
+
explicitProxyUrl
|
|
5265
5518
|
);
|
|
5519
|
+
sandbox2._setOwner(requestClient);
|
|
5520
|
+
sandbox2.traceId = traceId;
|
|
5521
|
+
sandbox2._setLifecycleIdentifier(sandboxId);
|
|
5522
|
+
sandbox2._setName(pending.name ?? requestedName);
|
|
5523
|
+
logSdkTiming("sandbox.create", "complete", opStart, {
|
|
5524
|
+
sandbox_id: sandboxId,
|
|
5525
|
+
status: "running" /* RUNNING */,
|
|
5526
|
+
server_trace_id: traceId
|
|
5527
|
+
});
|
|
5528
|
+
return sandbox2;
|
|
5529
|
+
}
|
|
5530
|
+
if (pending.state === "terminated" /* TERMINATED */ || pending.state === "failed" /* FAILED */) {
|
|
5531
|
+
throw startupFailure(sandboxId, pending.state, {
|
|
5532
|
+
errorDetails: pending.errorDetails,
|
|
5533
|
+
terminationReason: pending.terminationReason ?? pending.reason
|
|
5534
|
+
});
|
|
5266
5535
|
}
|
|
5267
|
-
await sleep2(500);
|
|
5268
|
-
}
|
|
5269
|
-
try {
|
|
5270
|
-
await requestClient.delete(result.sandboxId);
|
|
5271
|
-
} catch {
|
|
5272
5536
|
}
|
|
5273
|
-
|
|
5274
|
-
|
|
5537
|
+
const remaining = Math.max(0, (deadline - Date.now()) / 1e3);
|
|
5538
|
+
const observed = await requestClient.waitForSandbox(
|
|
5539
|
+
sandboxId,
|
|
5540
|
+
remaining,
|
|
5541
|
+
options?.pollInterval ?? DEFAULT_WAIT_POLL_INTERVAL_SEC
|
|
5275
5542
|
);
|
|
5543
|
+
const sandbox = await requestClient.settleWait(observed, {
|
|
5544
|
+
budget: requestTimeout,
|
|
5545
|
+
proxyUrl: options?.proxyUrl,
|
|
5546
|
+
requestTimeout,
|
|
5547
|
+
cancelOnTimeout: options?.cancelOnTimeout ?? false,
|
|
5548
|
+
requestedName,
|
|
5549
|
+
ownsSandbox: true,
|
|
5550
|
+
traceId
|
|
5551
|
+
});
|
|
5552
|
+
logSdkTiming("sandbox.create", "complete", opStart, {
|
|
5553
|
+
sandbox_id: sandboxId,
|
|
5554
|
+
status: "running" /* RUNNING */,
|
|
5555
|
+
server_trace_id: traceId,
|
|
5556
|
+
routing_hint: observed.routingHint,
|
|
5557
|
+
ingress_endpoint: observed.ingressEndpoint,
|
|
5558
|
+
sandbox_url: observed.sandboxUrl
|
|
5559
|
+
});
|
|
5560
|
+
return sandbox;
|
|
5276
5561
|
}
|
|
5277
5562
|
};
|
|
5278
5563
|
RESERVED_SANDBOX_MANAGEMENT_PORT = 9501;
|
|
@@ -6632,6 +6917,7 @@ var init_sandbox_image = __esm({
|
|
|
6632
6917
|
init_esm_shims();
|
|
6633
6918
|
init_client();
|
|
6634
6919
|
init_sandbox();
|
|
6920
|
+
init_pending_sandbox();
|
|
6635
6921
|
init_sandbox();
|
|
6636
6922
|
init_desktop();
|
|
6637
6923
|
init_tunnel();
|
|
@@ -9647,6 +9933,7 @@ export {
|
|
|
9647
9933
|
ImageBuildOperationType,
|
|
9648
9934
|
MountError,
|
|
9649
9935
|
OutputMode,
|
|
9936
|
+
PendingSandbox,
|
|
9650
9937
|
PoolInUseError,
|
|
9651
9938
|
PoolNotFoundError,
|
|
9652
9939
|
ProcessStatus,
|
|
@@ -9665,9 +9952,13 @@ export {
|
|
|
9665
9952
|
SandboxError,
|
|
9666
9953
|
SandboxException,
|
|
9667
9954
|
SandboxNotFoundError,
|
|
9955
|
+
SandboxPending,
|
|
9956
|
+
SandboxPendingReason,
|
|
9668
9957
|
SandboxStatus,
|
|
9669
9958
|
SnapshotStatus,
|
|
9670
9959
|
StdinMode,
|
|
9960
|
+
TERMINATION_REASON_CANCELLED,
|
|
9961
|
+
TERMINATION_REASON_NO_CAPACITY,
|
|
9671
9962
|
TcpTunnel,
|
|
9672
9963
|
createFileSystem,
|
|
9673
9964
|
createSandboxImage,
|
|
@@ -9676,6 +9967,7 @@ export {
|
|
|
9676
9967
|
dockerfileContent,
|
|
9677
9968
|
findSandboxImageByName,
|
|
9678
9969
|
importSandboxImage,
|
|
9970
|
+
isSandboxPending,
|
|
9679
9971
|
listFileSystems,
|
|
9680
9972
|
listSandboxImages,
|
|
9681
9973
|
registerApplication,
|