withruntime 0.11.0 → 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/BLAXEL.md +7 -8
- package/DAYTONA.md +7 -8
- package/E2B.md +16 -2
- package/README.md +3 -3
- package/README.src.md +3 -3
- package/VERCEL.md +3 -2
- package/compatibility-lock.json +55 -0
- package/dist/api-defaults.d.ts +1 -1
- package/dist/api-defaults.js +1 -1
- package/dist/blaxel/lookup.d.ts +2 -1
- package/dist/blaxel/lookup.js +2 -1
- package/dist/blaxel/sandbox.d.ts +7 -5
- package/dist/blaxel/sandbox.js +15 -10
- package/dist/cli.js +39 -15
- package/dist/client.d.ts +5 -1
- package/dist/client.js +19 -3
- package/dist/compat/files.js +5 -1
- package/dist/compat/lease.d.ts +1 -0
- package/dist/compat/lease.js +14 -8
- package/dist/credentials.d.ts +9 -0
- package/dist/credentials.js +26 -4
- package/dist/daytona/daytona.js +29 -12
- package/dist/daytona/sandbox.d.ts +8 -3
- package/dist/daytona/sandbox.js +23 -4
- package/dist/e2b/sandbox.d.ts +7 -3
- package/dist/e2b/sandbox.js +21 -7
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +6 -0
- package/dist/identity.js +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/modal/index.js +6 -2
- package/dist/network-cli.js +7 -7
- package/dist/products/browser.d.ts +2 -1
- package/dist/products/browser.js +9 -19
- package/dist/products/desktop.d.ts +2 -1
- package/dist/products/desktop.js +5 -30
- package/dist/products/jobs.d.ts +7 -5
- package/dist/products/jobs.js +7 -3
- package/dist/products/mcp.d.ts +5 -1
- package/dist/products/mcp.js +29 -8
- package/dist/products/network-products.d.ts +1 -1
- package/dist/products/network-products.js +1 -1
- package/dist/products/observability.d.ts +1 -1
- package/dist/products/private-network.d.ts +1 -1
- package/dist/products/secrets.d.ts +2 -2
- package/dist/runloop/index.js +6 -2
- package/dist/sandbox.d.ts +27 -19
- package/dist/sandbox.js +121 -54
- package/dist/tar.d.ts +2 -0
- package/dist/tar.js +74 -16
- package/dist/transport.d.ts +33 -7
- package/dist/transport.js +171 -36
- package/dist/types.d.ts +54 -9
- package/dist/vercel/filesystem.js +3 -1
- package/dist/vercel/sandbox.d.ts +17 -10
- package/dist/vercel/sandbox.js +26 -13
- package/dist/wait.d.ts +12 -0
- package/dist/wait.js +47 -0
- package/package.json +1 -1
package/BLAXEL.md
CHANGED
|
@@ -48,15 +48,14 @@ name, or through `getByExternalId`, use the same Runtime key.
|
|
|
48
48
|
resumes on the next call. On Runtime it pauses after 60 seconds without a
|
|
49
49
|
call (Runtime's shortest idle pause; Blaxel's is about 15 seconds), keeping
|
|
50
50
|
its memory, files and processes, and wakes by itself on the next command,
|
|
51
|
-
file call or preview visit.
|
|
52
|
-
|
|
53
|
-
does run out the sandbox pauses rather than ends.
|
|
51
|
+
file call or preview visit. It has no time limit, so a sandbox in use is
|
|
52
|
+
never paused on a clock.
|
|
54
53
|
- **How long it is kept:** Blaxel keeps a sandbox until it is deleted or its
|
|
55
54
|
TTL ends. A paused Runtime sandbox is kept 365 days when no TTL, expiry or
|
|
56
55
|
lifecycle is given. With one, it is never deleted before Blaxel would delete
|
|
57
56
|
it, and may be kept longer:
|
|
58
|
-
- a `ttl`, `expires`, `ttl-max-age` or `date` within the hour is a
|
|
59
|
-
ends the sandbox at that time, or later if the sandbox paused and woke;
|
|
57
|
+
- a `ttl`, `expires`, `ttl-max-age` or `date` within the hour is a time limit
|
|
58
|
+
that ends the sandbox at that time, or later if the sandbox paused and woke;
|
|
60
59
|
- any other deadline, and any `ttl-idle`, keeps a paused sandbox that many
|
|
61
60
|
days, rounded up, counted from each pause; with several, the shortest wins;
|
|
62
61
|
- at most 365 days.
|
|
@@ -161,9 +160,9 @@ Some differences are not refusals:
|
|
|
161
160
|
The old idle pause comes back once no `keepAlive` process runs, when a client
|
|
162
161
|
sees one end (a waited exec, `wait` or `get`), stops or kills one, or calls
|
|
163
162
|
`SandboxInstance.get`. With no such call, the sandbox pauses when it has been
|
|
164
|
-
idle for that `timeout`.
|
|
165
|
-
is paused with the sandbox when the
|
|
166
|
-
carries on at the next call.
|
|
163
|
+
idle for that `timeout`. On a sandbox with a time limit, a `keepAlive`
|
|
164
|
+
process past it is paused with the sandbox when the limit ends with no call
|
|
165
|
+
to renew it, and carries on at the next call.
|
|
167
166
|
- **A name is not refused while its process runs:** a second process may take a
|
|
168
167
|
running process's name, and `get(name)` answers the newest.
|
|
169
168
|
- **`process.list()` leaves each process's output empty** (Blaxel includes a
|
package/DAYTONA.md
CHANGED
|
@@ -38,14 +38,13 @@ package talks only to Runtime.
|
|
|
38
38
|
kept for Runtime's retention: 30 days on credit, 7 on the trial, or
|
|
39
39
|
`autoDeleteInterval` minutes rounded up to whole days. `delete()` ends it.
|
|
40
40
|
An `ephemeral` sandbox (or `autoDeleteInterval: 0`) ends on `stop()`.
|
|
41
|
-
- **Auto-stop:**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
the deadline.
|
|
41
|
+
- **Auto-stop:** `autoStopInterval` minutes (default 15; `0` never) is the
|
|
42
|
+
sandbox's idle pause: it pauses after that long with nothing happening in
|
|
43
|
+
it, counted by the sandbox itself, so a long command is never paused for
|
|
44
|
+
want of calls. It has no time limit. `ttlMinutes` gives it one, and with
|
|
45
|
+
it Daytona's own rule: the sandbox pauses after `autoStopInterval` minutes
|
|
46
|
+
without a call through the adapter, each call moving the limit on, and ends
|
|
47
|
+
at the deadline.
|
|
49
48
|
- **Funding:** left to Runtime, as `withruntime`'s own `create()` does: the free
|
|
50
49
|
trial while the account has trial time, then prepaid credit. Pass
|
|
51
50
|
`withruntime: { create: { funding: "trial" } }` to `new Daytona(...)` or to
|
package/E2B.md
CHANGED
|
@@ -41,6 +41,20 @@ machine. An E2B key (`e2b_...`) is never sent anywhere. If one is passed as
|
|
|
41
41
|
- **Timeout:** E2B's default of 300 seconds. When it ends, the sandbox is
|
|
42
42
|
stopped, as E2B kills it. `lifecycle: { onTimeout: "pause" }` pauses it
|
|
43
43
|
instead.
|
|
44
|
+
- **Idle pause:** Runtime's default, which E2B does not have. After 60
|
|
45
|
+
seconds with nothing happening in it (no request, running command, open
|
|
46
|
+
connection, traffic or CPU use) the sandbox pauses with its memory kept, and
|
|
47
|
+
the next command or file call wakes it. While it is paused, `isRunning()`
|
|
48
|
+
is `false` and `getInfo()` says `paused`, so code that reads either as
|
|
49
|
+
"the sandbox is gone" should not. Pass
|
|
50
|
+
`runtime: { create: { idlePauseSeconds: 0 } }` (Python:
|
|
51
|
+
`runtime_create={"idle_pause_seconds": 0}`) to keep it running, as on E2B.
|
|
52
|
+
- **Connections:** one client per key, holding at most 48 connections to the
|
|
53
|
+
API at once, since one address may hold 64. Each command being run holds
|
|
54
|
+
one while its output is read, and 8 are kept for other calls, so past 40
|
|
55
|
+
commands at once from one process the rest wait their turn. Pass your own
|
|
56
|
+
client with `runtime: { client: new Runtime({ maxConnections }) }` (Python:
|
|
57
|
+
`client=Runtime(max_connections=...)`).
|
|
44
58
|
- **Funding:** left to Runtime, as `withruntime`'s own `create()` does. The
|
|
45
59
|
free trial is used while the account has trial time, then prepaid credit.
|
|
46
60
|
Pass `runtime: { create: { funding: "trial" } }` to use only the trial.
|
|
@@ -54,7 +68,7 @@ machine. An E2B key (`e2b_...`) is never sent anywhere. If one is passed as
|
|
|
54
68
|
| E2B | On Runtime |
|
|
55
69
|
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
56
70
|
| `Sandbox.create()`, `Sandbox.create(template, opts)` | `sandboxes.create`. `base` and `code-interpreter-v1` are Runtime's stock image. Any other name must be a ready Runtime image with that name. A UUID is an image or a snapshot. |
|
|
57
|
-
| `timeoutMs` (Python `timeout`, seconds) | `timeoutSeconds`, rounded up. Under 60 s becomes 60 s, with a warning. Up to 24 hours, as on E2B: a Runtime
|
|
71
|
+
| `timeoutMs` (Python `timeout`, seconds) | Left out, the sandbox has no time limit: it runs while it works and pauses itself when idle. Given, it is `timeoutSeconds`, rounded up. Under 60 s becomes 60 s, with a warning. Up to 24 hours, as on E2B: a Runtime time limit reaches at most an hour ahead, so while this process runs the adapter extends it every five minutes, never past the end asked for. If the process ends first, the sandbox ends at its last limit, at most an hour later. Over 24 hours throws `InvalidArgumentError`. |
|
|
58
72
|
| `metadata` | labels (at most 32). |
|
|
59
73
|
| `envs` | Given to every command and code run through this object. |
|
|
60
74
|
| `allowInternetAccess: false` | `network: { internet: false }`. |
|
|
@@ -73,7 +87,7 @@ machine. An E2B key (`e2b_...`) is never sent anywhere. If one is passed as
|
|
|
73
87
|
| Relative paths | Resolved against the home directory, `/workspace` on Runtime. |
|
|
74
88
|
| `/home/user` (E2B's home) | The first time a path, `cwd` or command names it, it becomes a link to `/workspace`, unless something is already there. |
|
|
75
89
|
| `sandbox.kill()`, `Sandbox.kill(id)` | `stop`, without waiting. `false` when the sandbox was not found or had already ended. |
|
|
76
|
-
| `sandbox.setTimeout(ms)`, `Sandbox.setTimeout(id, ms)` | `extend`: the end moves to now + ms, up to 24 hours (past an hour it is carried on as for `timeoutMs`). An earlier end is refused: Runtime cannot end a lease early.
|
|
90
|
+
| `sandbox.setTimeout(ms)`, `Sandbox.setTimeout(id, ms)` | `extend`: the end moves to now + ms, up to 24 hours (past an hour it is carried on as for `timeoutMs`). An earlier end is refused: Runtime cannot end a lease early. A sandbox with no time limit has no end to move, and nothing changes. |
|
|
77
91
|
| `Sandbox.connect(id, { timeoutMs })`, `sandbox.connect()` | `get`. A paused sandbox is woken. A running one's end moves later, never earlier, up to 24 hours. An ended one throws `SandboxNotFoundError`. |
|
|
78
92
|
| `sandbox.pause()`, `betaPause`, `Sandbox.pause(id)` | `pause`, keeping memory and files. `false` when it was already paused. |
|
|
79
93
|
| `getInfo`, `isRunning` | `get`. `templateId` is `base` or the image or snapshot id. `envdVersion` is `runtime`. |
|
package/README.md
CHANGED
|
@@ -31,8 +31,8 @@ Node 22 call `await sbx.stop()`). With no arguments you get the free
|
|
|
31
31
|
trial while it lasts (100 free hours, up to eight sandboxes running at once), 2 vCPU, 4 GiB of
|
|
32
32
|
memory and a 4 GiB disk. The current default image includes NumPy, pandas and
|
|
33
33
|
matplotlib; see the [sandbox environment](https://withruntime.com/docs/sandbox-environment).
|
|
34
|
-
|
|
35
|
-
`
|
|
34
|
+
The trial's hours are spent first, then prepaid credit, with nothing to
|
|
35
|
+
choose; `funding` is accepted and ignored.
|
|
36
36
|
|
|
37
37
|
The sandbox object does the rest:
|
|
38
38
|
|
|
@@ -45,7 +45,7 @@ The sandbox object does the rest:
|
|
|
45
45
|
directories with `upload` and `download`;
|
|
46
46
|
- `pause`, `wake`, `extend`, `fork` and `snapshot` (a paused sandbox also wakes
|
|
47
47
|
by itself on the next call), `update` for its name, environment, automatic
|
|
48
|
-
wake, idle pause and persistence, `keepAlive` to
|
|
48
|
+
wake, idle pause and persistence, `keepAlive` to move a time limit on while your
|
|
49
49
|
process runs, `switchImage` to move it to a new image keeping /workspace,
|
|
50
50
|
and `delete` to remove it for good;
|
|
51
51
|
- `interpreter`, `network`, `previews`, `desktop`, `mounts` (your S3, R2 or
|
package/README.src.md
CHANGED
|
@@ -33,8 +33,8 @@ Node 22 call `await sbx.stop()`). With no arguments you get the free
|
|
|
33
33
|
trial while it lasts ({{trial-hours}} free hours, up to {{trial-sandboxes}} sandboxes running at once), 2 vCPU, 4 GiB of
|
|
34
34
|
memory and a 4 GiB disk. The current default image includes NumPy, pandas and
|
|
35
35
|
matplotlib; see the [sandbox environment](https://withruntime.com/docs/sandbox-environment).
|
|
36
|
-
|
|
37
|
-
`
|
|
36
|
+
The trial's hours are spent first, then prepaid credit, with nothing to
|
|
37
|
+
choose; `funding` is accepted and ignored.
|
|
38
38
|
|
|
39
39
|
The sandbox object does the rest:
|
|
40
40
|
|
|
@@ -47,7 +47,7 @@ The sandbox object does the rest:
|
|
|
47
47
|
directories with `upload` and `download`;
|
|
48
48
|
- `pause`, `wake`, `extend`, `fork` and `snapshot` (a paused sandbox also wakes
|
|
49
49
|
by itself on the next call), `update` for its name, environment, automatic
|
|
50
|
-
wake, idle pause and persistence, `keepAlive` to
|
|
50
|
+
wake, idle pause and persistence, `keepAlive` to move a time limit on while your
|
|
51
51
|
process runs, `switchImage` to move it to a new image keeping /workspace,
|
|
52
52
|
and `delete` to remove it for good;
|
|
53
53
|
- `interpreter`, `network`, `previews`, `desktop`, `mounts` (your S3, R2 or
|
package/VERCEL.md
CHANGED
|
@@ -33,8 +33,9 @@ are ignored.
|
|
|
33
33
|
|
|
34
34
|
- **Machine:** Vercel's default, 2 vCPUs with 2048 MiB each.
|
|
35
35
|
`resources: { vcpus }` sets another, with 2048 MiB per vCPU.
|
|
36
|
-
- **Timeout:**
|
|
37
|
-
|
|
36
|
+
- **Timeout:** none unless you pass one: the sandbox runs while it works and
|
|
37
|
+
pauses itself when idle. A `timeout` is kept as a Runtime time limit, which
|
|
38
|
+
runs 60 seconds to an hour. A longer `timeout` (Python `execution_time_limit`) starts with an
|
|
38
39
|
hour's lease, and the sandbox object renews it toward the timeout while it
|
|
39
40
|
lives, never past it; once the program ends, the sandbox pauses within an
|
|
40
41
|
hour. `extendTimeout` moves the end later, as often as needed.
|
package/compatibility-lock.json
CHANGED
|
@@ -229,6 +229,34 @@
|
|
|
229
229
|
"artifacts": {
|
|
230
230
|
"prime_sandboxes-0.4.1-py3-none-any.whl": "sha256-1a1bb96afacc66d690815be82c0b7af180ea141421b7d180b4a0adbada4f38f0",
|
|
231
231
|
"prime_sandboxes-0.4.1.tar.gz": "sha256-53f7577dc9070e3b8e30db360f9e3cce3bcc35f8765b26f24f64dbc3c7763b06"
|
|
232
|
+
},
|
|
233
|
+
"latestReview": {
|
|
234
|
+
"version": "0.4.2",
|
|
235
|
+
"artifacts": {
|
|
236
|
+
"prime_sandboxes-0.4.2-py3-none-any.whl": "sha256-ed59f001c7575339d6c903166c5468f783eda0997586ec6476fd8b35f65746f9",
|
|
237
|
+
"prime_sandboxes-0.4.2.tar.gz": "sha256-4990a724cac0a662fde6e12e7eccfee092a78679cc568653b8ef52008dfa28e4"
|
|
238
|
+
},
|
|
239
|
+
"reviewedAt": "2026-10-02",
|
|
240
|
+
"disposition": "held-for-sdk-qualification",
|
|
241
|
+
"evidence": {
|
|
242
|
+
"sourceUrls": [
|
|
243
|
+
"https://pypi.org/pypi/prime-sandboxes/0.4.2/json",
|
|
244
|
+
"https://files.pythonhosted.org/packages/3f/4d/a379cdf82d6f06c970bd4f0333c2360c08aba65c809d7492f49aece84c66/prime_sandboxes-0.4.2.tar.gz",
|
|
245
|
+
"https://files.pythonhosted.org/packages/da/b5/6a9fe6ae1342872c1c0cc45072cc0c58a5fa2783c4c45770e585f2535c8f/prime_sandboxes-0.4.2-py3-none-any.whl",
|
|
246
|
+
"https://github.com/PrimeIntellect-ai/prime/tree/main/packages/prime-sandboxes"
|
|
247
|
+
],
|
|
248
|
+
"artifactSha256": {
|
|
249
|
+
"prime_sandboxes-0.4.2-py3-none-any.whl": "ed59f001c7575339d6c903166c5468f783eda0997586ec6476fd8b35f65746f9",
|
|
250
|
+
"prime_sandboxes-0.4.2.tar.gz": "4990a724cac0a662fde6e12e7eccfee092a78679cc568653b8ef52008dfa28e4"
|
|
251
|
+
},
|
|
252
|
+
"changes": [
|
|
253
|
+
"Source diff of the 0.4.1 and 0.4.2 sdists, downloaded and hashed on the Mac, nothing installed or run: README, __init__, models.py, sandbox.py, one test changed; tests/test_checkpoints.py added.",
|
|
254
|
+
"Adds filesystem checkpoints: SandboxCheckpoint, CheckpointLookupError and BatchCheckpointResponse models; checkpoint, get_checkpoint, get_checkpoints (batch of up to 100 ids), wait_for_checkpoint and list_checkpoints on the sync and async clients; CreateSandboxRequest takes checkpoint_id with a validate_restore_source check.",
|
|
255
|
+
"CreateSandboxRequest.docker_image becomes Optional (None when restoring from a checkpoint) and disk_size_gb's default 5.0 becomes None.",
|
|
256
|
+
"Background job launch: the working_dir prefix is 'cd DIR || exit 1;' instead of 'cd DIR &&', and the launch cwd is / for an absolute working_dir.",
|
|
257
|
+
"No existing method was removed or renamed. Installed consumer qualification against withruntime/prime is not run; the supported pin stays 0.4.1."
|
|
258
|
+
]
|
|
259
|
+
}
|
|
232
260
|
}
|
|
233
261
|
}
|
|
234
262
|
]
|
|
@@ -252,6 +280,33 @@
|
|
|
252
280
|
"artifacts": {
|
|
253
281
|
"modal-1.6.0-py3-none-any.whl": "sha256-2f5981ba656570ad96379d29f0ddff876880708c84966024ce130e9e1794fa68",
|
|
254
282
|
"modal-1.6.0.tar.gz": "sha256-c5dd551b5e0a283f3c764476c0a4ebe5bdef1e4a69432fa27e1b1ad8ca5e0817"
|
|
283
|
+
},
|
|
284
|
+
"latestReview": {
|
|
285
|
+
"version": "1.6.1",
|
|
286
|
+
"artifacts": {
|
|
287
|
+
"modal-1.6.1-py3-none-any.whl": "sha256-f408ef88563003a83e491a6be09d4221eaa6e038fa4faa2ad8b15b25afe949a4",
|
|
288
|
+
"modal-1.6.1.tar.gz": "sha256-ff17768f67a65595aa7882e893e6cb78e2e001b3653aa52cfe98d4051d8d9e9e"
|
|
289
|
+
},
|
|
290
|
+
"reviewedAt": "2026-10-03",
|
|
291
|
+
"disposition": "held-for-sdk-qualification",
|
|
292
|
+
"evidence": {
|
|
293
|
+
"sourceUrls": [
|
|
294
|
+
"https://pypi.org/pypi/modal/1.6.1/json",
|
|
295
|
+
"https://files.pythonhosted.org/packages/65/ba/2b36899ea5633bf101e6ba6f7e95a4da3e4b1f57f52bd0ba8f4cfd12e808/modal-1.6.1.tar.gz",
|
|
296
|
+
"https://files.pythonhosted.org/packages/d2/3c/6b7d9a15dab9af2833ce674bbc72b5654d4099d5b088f1cc1eda3f8249ca/modal-1.6.1-py3-none-any.whl"
|
|
297
|
+
],
|
|
298
|
+
"artifactSha256": {
|
|
299
|
+
"modal-1.6.1-py3-none-any.whl": "f408ef88563003a83e491a6be09d4221eaa6e038fa4faa2ad8b15b25afe949a4",
|
|
300
|
+
"modal-1.6.1.tar.gz": "ff17768f67a65595aa7882e893e6cb78e2e001b3653aa52cfe98d4051d8d9e9e"
|
|
301
|
+
},
|
|
302
|
+
"changes": [
|
|
303
|
+
"Source diff of the 1.6.0 and 1.6.1 sdists, downloaded and hashed on the Mac, nothing installed or run; the 1.6.0 hashes match the pin. No file added or removed; 37 files changed, most in sandbox.py, the CLI and the generated protos.",
|
|
304
|
+
"Sandbox v2 calls send a per-sandbox token (x-modal-sandbox-token, from the create response) beside the auth token through a new _v2_metadata helper, including command router access.",
|
|
305
|
+
"Experimental sidecars take include_oidc_identity_token and proxy, refused for GPU sandboxes. Server sessions retry start with an idempotency key for up to 25 minutes; the CLI gains endpoint commands; stats types gain container_total_count; agent detection reads tool variables before AGENT and AI_AGENT.",
|
|
306
|
+
"Requirements: protobuf below 8.0 instead of 7.0, synchronicity ~=0.12.6 instead of ~=0.12.5. Some iterator return types become AsyncGenerator.",
|
|
307
|
+
"No public Sandbox, ContainerProcess, Image, App or file method used by withruntime/modal was removed or renamed; that drop-in does not import modal. Installed consumer qualification is not run; the supported pin stays 1.6.0."
|
|
308
|
+
]
|
|
309
|
+
}
|
|
255
310
|
}
|
|
256
311
|
}
|
|
257
312
|
]
|
package/dist/api-defaults.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export declare const WAIT_FOR_TIMEOUT_SECONDS = 60;
|
|
3
3
|
/** A streamed exec's command limit when none is given: the API's longest. */
|
|
4
4
|
export declare const STREAMED_EXEC_TIMEOUT_MS = 86400000;
|
|
5
|
-
/** The
|
|
5
|
+
/** The time keepAlive keeps ahead of a time limit, and so the most it extends by. */
|
|
6
6
|
export declare const KEEP_ALIVE_MARGIN_SECONDS = 600;
|
|
7
7
|
/** A webhook watch runs until stopped. */
|
|
8
8
|
export declare const WEBHOOK_WATCH_TIMEOUT_MS = 0;
|
package/dist/api-defaults.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export const WAIT_FOR_TIMEOUT_SECONDS = 60;
|
|
8
8
|
/** A streamed exec's command limit when none is given: the API's longest. */
|
|
9
9
|
export const STREAMED_EXEC_TIMEOUT_MS = 86_400_000;
|
|
10
|
-
/** The
|
|
10
|
+
/** The time keepAlive keeps ahead of a time limit, and so the most it extends by. */
|
|
11
11
|
export const KEEP_ALIVE_MARGIN_SECONDS = 600;
|
|
12
12
|
/** A webhook watch runs until stopped. */
|
|
13
13
|
export const WEBHOOK_WATCH_TIMEOUT_MS = 0;
|
package/dist/blaxel/lookup.d.ts
CHANGED
|
@@ -23,7 +23,8 @@ export declare const STANDBY: {
|
|
|
23
23
|
idlePauseSeconds: number;
|
|
24
24
|
autoWake: true;
|
|
25
25
|
};
|
|
26
|
-
/** Runtime's longest
|
|
26
|
+
/** Runtime's longest time limit. A sandbox made before 0300 has it, and the
|
|
27
|
+
* adapter renews it while the sandbox is used; one made since has none. */
|
|
27
28
|
export declare const LEASE_SECONDS = 3600;
|
|
28
29
|
/** The live sandbox with this name (or Runtime id): one call. A 404 when
|
|
29
30
|
* there is none, as Blaxel answers. */
|
package/dist/blaxel/lookup.js
CHANGED
|
@@ -30,7 +30,8 @@ export const STANDBY = {
|
|
|
30
30
|
idlePauseSeconds: 60,
|
|
31
31
|
autoWake: true,
|
|
32
32
|
};
|
|
33
|
-
/** Runtime's longest
|
|
33
|
+
/** Runtime's longest time limit. A sandbox made before 0300 has it, and the
|
|
34
|
+
* adapter renews it while the sandbox is used; one made since has none. */
|
|
34
35
|
export const LEASE_SECONDS = 3600;
|
|
35
36
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
36
37
|
/** The live sandbox with this name (or Runtime id): one call. A 404 when
|
package/dist/blaxel/sandbox.d.ts
CHANGED
|
@@ -58,16 +58,18 @@ type Resolved = {
|
|
|
58
58
|
};
|
|
59
59
|
/** A duration as Blaxel writes it ("30m", "24h", "7d", "1w", "1h30m"). */
|
|
60
60
|
export declare function durationMs(value: string): number;
|
|
61
|
-
/** The
|
|
62
|
-
* lifecycle: never deleted before Blaxel would delete it. A fixed
|
|
63
|
-
* within the hour is a
|
|
64
|
-
*
|
|
61
|
+
/** The time limit and the paused retention that honour Blaxel's TTL, expiry
|
|
62
|
+
* and lifecycle: never deleted before Blaxel would delete it. A fixed
|
|
63
|
+
* deadline within the hour is a time limit that ends the sandbox; past that
|
|
64
|
+
* there is none, so it runs while it works and pauses when idle (0300), and
|
|
65
|
+
* a paused sandbox is kept that many days, rounded up; none keeps it 365
|
|
66
|
+
* days. */
|
|
65
67
|
export declare function lifetimeOf(asked: {
|
|
66
68
|
ttl?: string | null;
|
|
67
69
|
expires?: Date;
|
|
68
70
|
lifecycle?: SandboxLifecycle | null;
|
|
69
71
|
}): {
|
|
70
|
-
timeoutSeconds
|
|
72
|
+
timeoutSeconds?: number;
|
|
71
73
|
onLeaseEnd: "pause" | "stop";
|
|
72
74
|
days: number;
|
|
73
75
|
};
|
package/dist/blaxel/sandbox.js
CHANGED
|
@@ -71,10 +71,12 @@ export function durationMs(value) {
|
|
|
71
71
|
total += Number(count) * unit[letter];
|
|
72
72
|
return total;
|
|
73
73
|
}
|
|
74
|
-
/** The
|
|
75
|
-
* lifecycle: never deleted before Blaxel would delete it. A fixed
|
|
76
|
-
* within the hour is a
|
|
77
|
-
*
|
|
74
|
+
/** The time limit and the paused retention that honour Blaxel's TTL, expiry
|
|
75
|
+
* and lifecycle: never deleted before Blaxel would delete it. A fixed
|
|
76
|
+
* deadline within the hour is a time limit that ends the sandbox; past that
|
|
77
|
+
* there is none, so it runs while it works and pauses when idle (0300), and
|
|
78
|
+
* a paused sandbox is kept that many days, rounded up; none keeps it 365
|
|
79
|
+
* days. */
|
|
78
80
|
export function lifetimeOf(asked) {
|
|
79
81
|
const now = Date.now();
|
|
80
82
|
const fixed = [];
|
|
@@ -110,7 +112,7 @@ export function lifetimeOf(asked) {
|
|
|
110
112
|
: KEEP_DAYS;
|
|
111
113
|
return soonest <= LEASE_SECONDS * 1000
|
|
112
114
|
? { timeoutSeconds: Math.max(60, Math.ceil(soonest / 1000)), onLeaseEnd: "stop", days }
|
|
113
|
-
: {
|
|
115
|
+
: { onLeaseEnd: "pause", days };
|
|
114
116
|
}
|
|
115
117
|
/** Blaxel's network settings as Runtime's rules: allowed and forbidden
|
|
116
118
|
* domains, from the network itself or from its proxy (Blaxel's current
|
|
@@ -402,9 +404,10 @@ export class SandboxInstance {
|
|
|
402
404
|
}
|
|
403
405
|
// ---- the live sandbox ---------------------------------------------------
|
|
404
406
|
/** The sandbox, ready for a call. A paused one wakes by itself on the call
|
|
405
|
-
* (autoWake); one made without autoWake is woken here. A
|
|
406
|
-
*
|
|
407
|
-
*
|
|
407
|
+
* (autoWake); one made without autoWake is woken here. A time limit
|
|
408
|
+
* nearing its end (an hour, on a sandbox made before 0300) is renewed in
|
|
409
|
+
* the background, so a sandbox in use is not paused by it; one with no
|
|
410
|
+
* time limit renews itself. */
|
|
408
411
|
async #live() {
|
|
409
412
|
if (this.#deleted)
|
|
410
413
|
throw responseError(404, `Sandbox ${this.name} was deleted.`);
|
|
@@ -414,6 +417,8 @@ export class SandboxInstance {
|
|
|
414
417
|
await this.#wake();
|
|
415
418
|
else if (state === "running" &&
|
|
416
419
|
rt.info.onLeaseEnd === "pause" &&
|
|
420
|
+
// One with no time limit renews itself (0300).
|
|
421
|
+
rt.info.endsAt !== null &&
|
|
417
422
|
!this.#renewing &&
|
|
418
423
|
Date.parse(rt.info.expiresAt) - Date.now() < RENEW_BELOW_MS)
|
|
419
424
|
this.#renewing = rt
|
|
@@ -461,7 +466,7 @@ export class SandboxInstance {
|
|
|
461
466
|
labels: { ...labels, [IDLE_PAUSE]: labels[IDLE_PAUSE] ?? String(current ?? 0) },
|
|
462
467
|
}))
|
|
463
468
|
: undefined,
|
|
464
|
-
rt.info.onLeaseEnd === "pause" && need >= 1
|
|
469
|
+
rt.info.onLeaseEnd === "pause" && rt.info.endsAt !== null && need >= 1
|
|
465
470
|
? rt.extend(Math.ceil(need)).catch(() => undefined)
|
|
466
471
|
: undefined,
|
|
467
472
|
]);
|
|
@@ -545,7 +550,7 @@ export class SandboxInstance {
|
|
|
545
550
|
vcpu: Math.min(MAX_VCPU, Math.max(1, Math.round(memory / MEMORY_PER_VCPU))),
|
|
546
551
|
memoryMiB: memory,
|
|
547
552
|
...STANDBY,
|
|
548
|
-
timeoutSeconds: lifetime.timeoutSeconds,
|
|
553
|
+
...(lifetime.timeoutSeconds === undefined ? {} : { timeoutSeconds: lifetime.timeoutSeconds }),
|
|
549
554
|
onLeaseEnd: lifetime.onLeaseEnd,
|
|
550
555
|
...(config.name ? { name: config.name } : {}),
|
|
551
556
|
labels,
|
package/dist/cli.js
CHANGED
|
@@ -140,10 +140,10 @@ const SANDBOX_HELP = `runtime sandbox <command>
|
|
|
140
140
|
resize <id> [--vcpu 2] [--memory 4096] --restart
|
|
141
141
|
Change its size by a restart: the whole disk stays,
|
|
142
142
|
programs stop (snapshot it first to keep memory)
|
|
143
|
-
extend <id> <seconds>
|
|
143
|
+
extend <id> <seconds> Move a time limit on (one with none needs nothing)
|
|
144
144
|
update <id> [--name n] [--label k=v]... [--env K=V]... [--unset-env K]... [--idle-pause <seconds>] [--auto-wake on|off]
|
|
145
145
|
[--persistent on|off] [--max-total-cost <usd>|none]
|
|
146
|
-
Change its settings; persistent keeps it running
|
|
146
|
+
Change its settings; persistent keeps it running until stopped
|
|
147
147
|
snapshot <id> [--name n] [--retention days] Keep its whole machine; prints the snapshot id
|
|
148
148
|
mount <id> <s3|r2|gcs>://<bucket>[/prefix] <path> [--secret NAME] [--region r]
|
|
149
149
|
[--endpoint https://...] [--account-id id] [--read-only]
|
|
@@ -517,8 +517,18 @@ function describe(info) {
|
|
|
517
517
|
],
|
|
518
518
|
["funding", info.funding],
|
|
519
519
|
["region", info.region],
|
|
520
|
-
|
|
521
|
-
|
|
520
|
+
// A sandbox with no time limit runs while it works (0300): endsAt is
|
|
521
|
+
// null. An older server sends no endsAt; its expiresAt was the end.
|
|
522
|
+
["time limit", info.timeoutSeconds ? `${info.timeoutSeconds} s` : "none"],
|
|
523
|
+
[
|
|
524
|
+
"ends",
|
|
525
|
+
info.endsAt === null
|
|
526
|
+
? info.state === "running"
|
|
527
|
+
? "when idle, stopped or out of credit"
|
|
528
|
+
: "-"
|
|
529
|
+
: (info.endsAt ?? info.expiresAt ?? "-"),
|
|
530
|
+
],
|
|
531
|
+
["at its end", info.onLeaseEnd ?? "-"],
|
|
522
532
|
// Why a sandbox is no longer running (troubleshooting.md, "A sandbox
|
|
523
533
|
// stopped on its own"); `get` left both out until 30 September 2026.
|
|
524
534
|
...(info.pausedAt ? [["paused at", info.pausedAt]] : []),
|
|
@@ -1071,10 +1081,18 @@ export function usageCsv(u) {
|
|
|
1071
1081
|
.join(","));
|
|
1072
1082
|
return [head.join(","), ...rows].join("\n");
|
|
1073
1083
|
}
|
|
1084
|
+
/** Milliseconds as hours, to a tenth: "8,731.2". */
|
|
1085
|
+
const hours = (ms) => (ms / 3_600_000).toLocaleString("en-US", { maximumFractionDigits: 1 });
|
|
1074
1086
|
/** The free trial's time left, as `runtime usage` and `runtime limits` say it. */
|
|
1075
1087
|
function trialLeft(trial) {
|
|
1076
|
-
|
|
1077
|
-
|
|
1088
|
+
return `${hours(trial.availableMs)} of ${hours(trial.totalMs)} hours left`;
|
|
1089
|
+
}
|
|
1090
|
+
/** A pilot's sandbox hours left, as `runtime usage` says them. */
|
|
1091
|
+
function pilotLeft(pilot) {
|
|
1092
|
+
const left = `${hours(pilot.leftMs)} of ${pilot.hours.toLocaleString("en-US")} left`;
|
|
1093
|
+
return pilot.leftMs > 0
|
|
1094
|
+
? `${left}; new pilot sandboxes until ${pilot.endsAt.slice(0, 16).replace("T", " ")} UTC`
|
|
1095
|
+
: "This pilot's sandbox hours are used.";
|
|
1078
1096
|
}
|
|
1079
1097
|
function usageSummary(u) {
|
|
1080
1098
|
const micros = (value) => typeof value === "string" || typeof value === "number" || typeof value === "bigint"
|
|
@@ -1088,15 +1106,17 @@ function usageSummary(u) {
|
|
|
1088
1106
|
// its own line, so "spent" reads as what was used.
|
|
1089
1107
|
["used", dollars(micros(u.spent) - takenBack)],
|
|
1090
1108
|
...(takenBack > 0n ? [["returned by refunds and disputes", dollars(takenBack)]] : []),
|
|
1091
|
-
//
|
|
1092
|
-
//
|
|
1093
|
-
//
|
|
1094
|
-
["
|
|
1109
|
+
// What running sandboxes and the hour ahead of stored snapshots, images
|
|
1110
|
+
// and volumes are about to use, so an account with nothing running can
|
|
1111
|
+
// still show some. Said without "held": no guide teaches holds.
|
|
1112
|
+
["set aside for running sandboxes and this hour's storage", dollars(micros(u.held))],
|
|
1095
1113
|
];
|
|
1096
1114
|
if (micros(u.expired) > 0n)
|
|
1097
1115
|
rows.push(["expired or taken back", dollars(micros(u.expired))]);
|
|
1098
1116
|
if (u.trial)
|
|
1099
1117
|
rows.push(["free trial", trialLeft(u.trial)]);
|
|
1118
|
+
if (u.pilot)
|
|
1119
|
+
rows.push(["pilot sandbox hours", pilotLeft(u.pilot)]);
|
|
1100
1120
|
if (u.outbound) {
|
|
1101
1121
|
const gib = (bytes) => `${(bytes / 1_073_741_824).toLocaleString("en-US", { maximumFractionDigits: 1 })} GiB`;
|
|
1102
1122
|
const left = Math.max(0, u.outbound.allowanceBytes - u.outbound.freeBytes);
|
|
@@ -1474,11 +1494,13 @@ async function sandbox(argv, env, out) {
|
|
|
1474
1494
|
s.state,
|
|
1475
1495
|
`${s.info.vcpu}/${s.info.memoryMiB}`,
|
|
1476
1496
|
s.info.funding,
|
|
1477
|
-
s
|
|
1497
|
+
// When it stops or pauses by itself (0381): its time limit's end, or
|
|
1498
|
+
// "-" when it never will. An older server sends no endsAt.
|
|
1499
|
+
(s.info.endsAt === undefined ? s.info.expiresAt : s.info.endsAt) ?? "-",
|
|
1478
1500
|
]);
|
|
1479
1501
|
print([
|
|
1480
1502
|
rows.length
|
|
1481
|
-
? table([["ID", "NAME", "STATE", "CPU/MIB", "FUNDING", "
|
|
1503
|
+
? table([["ID", "NAME", "STATE", "CPU/MIB", "FUNDING", "ENDS"], ...rows])
|
|
1482
1504
|
: stopped
|
|
1483
1505
|
? "No live sandboxes."
|
|
1484
1506
|
: "No sandboxes. Create one: runtime sandbox create",
|
|
@@ -1704,7 +1726,9 @@ async function sandbox(argv, env, out) {
|
|
|
1704
1726
|
const sbx = await get(rest[0]);
|
|
1705
1727
|
const seconds = Number(need(rest[1], "seconds, e.g. runtime sandbox extend <id> 600"));
|
|
1706
1728
|
await sbx.extend(seconds);
|
|
1707
|
-
print(
|
|
1729
|
+
print(sbx.info.endsAt === null
|
|
1730
|
+
? `${sbx.id} has no time limit: it runs while it works, so nothing was extended`
|
|
1731
|
+
: `${sbx.id} now ends at ${sbx.info.endsAt ?? sbx.info.expiresAt}`, sbx.info);
|
|
1708
1732
|
return 0;
|
|
1709
1733
|
}
|
|
1710
1734
|
case "exec": {
|
|
@@ -2783,8 +2807,8 @@ read = readSecret) {
|
|
|
2783
2807
|
}
|
|
2784
2808
|
const JOB_HELP = `runtime job <command>
|
|
2785
2809
|
|
|
2786
|
-
A job runs a command in a fresh sandbox, once or on a schedule. Each run
|
|
2787
|
-
|
|
2810
|
+
A job runs a command in a fresh sandbox, once or on a schedule. Each run spends
|
|
2811
|
+
the free trial's hours first, then credit at the sandbox rates.
|
|
2788
2812
|
|
|
2789
2813
|
create <name> (--cron "<min hour day month weekday>" [--timezone Europe/Berlin] | --at <time|now>)
|
|
2790
2814
|
[--vcpu 2] [--memory 4096] [--disk 4096] [--cpu shared|reserved] [--cpu-floor <thousandths>]
|
package/dist/client.d.ts
CHANGED
|
@@ -16,7 +16,11 @@ export type RuntimeOptions = {
|
|
|
16
16
|
timeoutMs?: number;
|
|
17
17
|
/** Retries of transport failures, 429, 502, 503 and 504. Default 4. */
|
|
18
18
|
maxRetries?: number;
|
|
19
|
-
/**
|
|
19
|
+
/** Connections held at once, calls and streams (a command's output, a
|
|
20
|
+
* download) together; more wait their turn, first come first served, and
|
|
21
|
+
* reuse them. Default 48: one address may hold 64 connections to the API
|
|
22
|
+
* before it has used a valid key. 8 are kept for calls whatever the
|
|
23
|
+
* streams hold. */
|
|
20
24
|
maxConnections?: number;
|
|
21
25
|
/** How long `sandboxes.create` keeps retrying, with the same key and input,
|
|
22
26
|
* when the trial's slots, the account's quota or the region is full
|
package/dist/client.js
CHANGED
|
@@ -4,7 +4,7 @@ import { clientFactories, clientProductAliases } from "./products/index.js";
|
|
|
4
4
|
import { usageExport as makeUsageExport } from "./products/observability.js";
|
|
5
5
|
import { Sandbox, deleteSandbox, sandboxPage } from "./sandbox.js";
|
|
6
6
|
import { Snapshots } from "./snapshots.js";
|
|
7
|
-
import { Transport, missingKey } from "./transport.js";
|
|
7
|
+
import { DEFAULT_BASE_URL, Transport, missingKey } from "./transport.js";
|
|
8
8
|
/** The key `runtime login` saved for this machine and this API origin, found
|
|
9
9
|
* on first use. A constructor override must never receive another API's key. */
|
|
10
10
|
const savedKey = async (apiOrigin) => {
|
|
@@ -30,10 +30,14 @@ export class Runtime {
|
|
|
30
30
|
/** Date-range settlements, paged with exact charges and the server's CSV. */
|
|
31
31
|
usageExport;
|
|
32
32
|
constructor(options = {}) {
|
|
33
|
+
// The saved key is found by the origin as given, as `runtime login` saved
|
|
34
|
+
// it; the calls go where that origin is reachable from here, which in a
|
|
35
|
+
// sandbox is runtime.internal (transport.ts, `reachable`).
|
|
36
|
+
const origin = options.baseUrl || env("RUNTIME_API_URL") || DEFAULT_BASE_URL;
|
|
33
37
|
this.transport = new Transport({
|
|
34
38
|
// A key given, then RUNTIME_API_KEY, then (in Node and Bun) the key
|
|
35
39
|
// `runtime login` saved for this machine, read on the first call.
|
|
36
|
-
apiKey: options.apiKey ?? env("RUNTIME_API_KEY") ?? (() => savedKey(
|
|
40
|
+
apiKey: options.apiKey ?? env("RUNTIME_API_KEY") ?? (() => savedKey(origin)),
|
|
37
41
|
baseUrl: options.baseUrl ?? env("RUNTIME_API_URL"),
|
|
38
42
|
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
39
43
|
...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
|
@@ -97,6 +101,9 @@ export class Sandboxes {
|
|
|
97
101
|
* free, up to `waitForCapacityMs` (the client's, two minutes by default). */
|
|
98
102
|
async create(input = {}, options = {}) {
|
|
99
103
|
const { wait, ...body } = input;
|
|
104
|
+
const began = performance.now();
|
|
105
|
+
// Time spent waiting for capacity is the room's, not the deadline's.
|
|
106
|
+
let waited = 0;
|
|
100
107
|
const info = await this.t.json({
|
|
101
108
|
method: "POST",
|
|
102
109
|
path: "/v1/sandboxes",
|
|
@@ -104,13 +111,22 @@ export class Sandboxes {
|
|
|
104
111
|
wait: wait === false ? 0 : 60,
|
|
105
112
|
...options,
|
|
106
113
|
waitForCapacityMs: options.waitForCapacityMs ?? this.t.waitForCapacityMs,
|
|
114
|
+
onCapacityWait: (refusal, waitMs) => {
|
|
115
|
+
waited += waitMs;
|
|
116
|
+
options.onCapacityWait?.(refusal, waitMs);
|
|
117
|
+
},
|
|
107
118
|
});
|
|
108
119
|
const sandbox = new Sandbox(this.t, info);
|
|
109
120
|
if (wait !== false && info.state !== "running") {
|
|
121
|
+
// One deadline for the whole create: the wait for running gets what the
|
|
122
|
+
// create left of it (1 ms when nothing is left, so it ends as a timeout).
|
|
123
|
+
const { timeoutMs } = options;
|
|
110
124
|
await sandbox.waitFor("running", {
|
|
111
125
|
timeoutSeconds: WAIT_FOR_TIMEOUT_SECONDS,
|
|
112
126
|
signal: options.signal,
|
|
113
|
-
timeoutMs:
|
|
127
|
+
timeoutMs: timeoutMs
|
|
128
|
+
? Math.max(1, Math.ceil(timeoutMs - (performance.now() - began - waited)))
|
|
129
|
+
: timeoutMs,
|
|
114
130
|
idempotencyKey: options.idempotencyKey,
|
|
115
131
|
});
|
|
116
132
|
if (sandbox.state !== "running")
|
package/dist/compat/files.js
CHANGED
|
@@ -63,10 +63,14 @@ export class GuestFiles {
|
|
|
63
63
|
if (!overwrite) {
|
|
64
64
|
// cp -n alone reports success when it skips a raced destination. Stage
|
|
65
65
|
// privately, then publish without replacement and verify it moved.
|
|
66
|
+
// mv -n that skips succeeds before coreutils 9.2 and fails from it on
|
|
67
|
+
// (the guest's 9.4 says "not replacing"), so a skip is told by the
|
|
68
|
+
// staged copy still being there beside a destination; with none there,
|
|
69
|
+
// mv's own error stands.
|
|
66
70
|
await checked(sandbox, [
|
|
67
71
|
"bash",
|
|
68
72
|
"-c",
|
|
69
|
-
'set -e; parent=$(dirname -- "$2"); stage="$parent/.runtime-copy-$4"; mkdir -m 700 -- "$stage"; trap \'rm -rf -- "$stage"\' EXIT; if [ "$3" = true ]; then cp -R
|
|
73
|
+
'set -e; parent=$(dirname -- "$2"); stage="$parent/.runtime-copy-$4"; mkdir -m 700 -- "$stage"; trap \'rm -rf -- "$stage"\' EXIT; if [ "$3" = true ]; then cp -R -- "$1" "$stage/item"; else cp -- "$1" "$stage/item"; fi; mv -n -T -- "$stage/item" "$2" 2>"$stage/mv.err" || :; if [ -e "$stage/item" ] || [ -L "$stage/item" ]; then if [ -e "$2" ] || [ -L "$2" ]; then printf "Destination exists: %s\\n" "$2" >&2; exit 73; fi; cat -- "$stage/mv.err" >&2; exit 1; fi',
|
|
70
74
|
"bash",
|
|
71
75
|
this.path(from),
|
|
72
76
|
this.path(to),
|