withruntime 0.14.0 → 0.16.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 +97 -32
- package/COMPATIBILITY.md +120 -5
- package/DAYTONA.md +34 -3
- package/E2B.md +34 -5
- package/README.md +33 -0
- package/README.src.md +33 -0
- package/VERCEL.md +52 -5
- package/compatibility-lock.json +71 -111
- package/dist/blaxel/client.d.ts +11 -0
- package/dist/blaxel/client.js +28 -0
- package/dist/blaxel/errors.d.ts +65 -0
- package/dist/blaxel/errors.js +114 -0
- package/dist/blaxel/index.d.ts +10 -3
- package/dist/blaxel/index.js +23 -4
- package/dist/blaxel/preview.d.ts +29 -4
- package/dist/blaxel/preview.js +79 -5
- package/dist/blaxel/sandbox.js +1 -0
- package/dist/blaxel/session.js +4 -2
- package/dist/cli-extras.js +2 -1
- package/dist/cli-words.js +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +61 -26
- package/dist/client.d.ts +1 -1
- package/dist/daytona/client.d.ts +4 -0
- package/dist/daytona/client.js +8 -3
- package/dist/daytona/daytona.d.ts +3 -0
- package/dist/daytona/daytona.js +2 -1
- package/dist/e2b/sandbox.d.ts +6 -5
- package/dist/e2b/sandbox.js +9 -12
- package/dist/freestyle/index.d.ts +77 -5
- package/dist/freestyle/index.js +380 -48
- package/dist/identity.js +63 -22
- package/dist/index.d.ts +2 -2
- package/dist/machine.d.ts +28 -13
- package/dist/machine.js +49 -15
- package/dist/mcp.js +16 -3
- package/dist/modal/index.d.ts +15 -0
- package/dist/modal/index.js +35 -7
- package/dist/morph/index.d.ts +255 -0
- package/dist/morph/index.js +641 -0
- package/dist/network-cli.js +2 -2
- package/dist/product-names.d.ts +2 -2
- package/dist/product-names.js +2 -2
- package/dist/products/limits.d.ts +16 -2
- package/dist/products/limits.js +2 -2
- package/dist/products/mcp.d.ts +5 -0
- package/dist/products/network-products.d.ts +21 -3
- package/dist/products/network-products.js +3 -1
- package/dist/products/previews.d.ts +6 -3
- package/dist/products/previews.js +1 -1
- package/dist/snapshots.d.ts +4 -0
- package/dist/ssh.d.ts +35 -0
- package/dist/ssh.js +93 -1
- package/dist/transport.d.ts +11 -8
- package/dist/transport.js +46 -12
- package/dist/types.d.ts +24 -0
- package/dist/vercel/command.d.ts +48 -1
- package/dist/vercel/command.js +237 -6
- package/dist/vercel/sandbox-user.js +2 -1
- package/dist/vercel/sandbox.d.ts +16 -2
- package/dist/vercel/sandbox.js +45 -2
- package/package.json +6 -1
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ Usage: runtime <product> <command> [options] runtime <command> [options]
|
|
|
24
24
|
|
|
25
25
|
Start
|
|
26
26
|
sandboxes run [--keep] [create options] -- <command>
|
|
27
|
-
A fresh sandbox runs one command, then
|
|
27
|
+
A fresh sandbox runs one command, then is deleted
|
|
28
28
|
|
|
29
29
|
Account
|
|
30
30
|
login [--agent-name <name>] [--no-browser] [--wait]
|
|
@@ -88,6 +88,8 @@ Account
|
|
|
88
88
|
Connect
|
|
89
89
|
sandboxes ssh <id|name> [-- <command...>] Log in over SSH; \`runtime sandboxes ssh help\` for editors
|
|
90
90
|
sandboxes ssh config [--install] Make \`ssh <id|name>.runtime\` work (VS Code, JetBrains)
|
|
91
|
+
sandboxes code <id|name> [--editor vscode|cursor|windsurf]
|
|
92
|
+
Open it in VS Code, Cursor or Windsurf over SSH
|
|
91
93
|
sandboxes port-forward <id|name> <port|local:remote>...
|
|
92
94
|
Forward local ports to ports in a sandbox
|
|
93
95
|
|
|
@@ -122,14 +124,17 @@ const SANDBOX_HELP = `runtime sandboxes <command>
|
|
|
122
124
|
|
|
123
125
|
Every <id> below can also be the sandbox's name.
|
|
124
126
|
|
|
125
|
-
run [--keep] [create options] -- <command> A fresh sandbox runs one command, then
|
|
127
|
+
run [--keep] [create options] -- <command> A fresh sandbox runs one command, then is deleted
|
|
126
128
|
ssh <id|name> [-- <command...>] | ssh config [--install] Log in over SSH, also from VS Code and JetBrains
|
|
129
|
+
code <id|name> [--editor vscode|cursor|windsurf] [--path /workspace] [--print]
|
|
130
|
+
Open it in your editor over SSH, in one step
|
|
127
131
|
port-forward <id|name> <port|local:remote>... Forward local ports to ports in it
|
|
128
132
|
create [--name n] [--label k=v]... [--env K=V]... [--vcpu 2] [--memory 4096] [--disk 4096]
|
|
129
133
|
[--cpu shared|reserved] [--cpu-floor <thousandths>] [--max-cost <usd>] [--max-total-cost <usd>]
|
|
130
134
|
[--timeout <60-86400>] [--on-timeout pause|stop|delete] [--no-wait]
|
|
131
135
|
[--no-internet] [--allow <host>]... [--deny <host>]... [--connect <host:port>]...
|
|
132
136
|
[--image <name:tag|imageId> | --snapshot <snapshotId>] [--volume <volumeId>:/data[:snapshot]]...
|
|
137
|
+
[--spread-from <id>]...
|
|
133
138
|
[--idle-pause <seconds>] [--no-auto-wake] [--persistent] [--get-or-create]
|
|
134
139
|
Create one; prints its id
|
|
135
140
|
ls [--all] [--label k=v]... [--state running] List (live ones unless --all)
|
|
@@ -156,12 +161,14 @@ const SANDBOX_HELP = `runtime sandboxes <command>
|
|
|
156
161
|
switch-image <id> <image> --keep-workspace Move it to another image, keeping /workspace (your home),
|
|
157
162
|
volumes, env and previews; processes restart, the rest of
|
|
158
163
|
its disk is lost (snapshot it first to keep everything)
|
|
159
|
-
resize <id> [--vcpu 2] [--memory 4096] --restart
|
|
160
|
-
Change its size by a restart: the whole disk stays
|
|
161
|
-
programs stop (snapshot it first
|
|
164
|
+
resize <id> [--vcpu 2] [--memory 4096] [--disk 20480] --restart
|
|
165
|
+
Change its size by a restart: the whole disk stays and
|
|
166
|
+
--disk only grows it; programs stop (snapshot it first
|
|
167
|
+
to keep memory)
|
|
162
168
|
extend <id> <seconds> Move a time limit on (one with none needs nothing)
|
|
163
169
|
update <id> [--name n] [--label k=v]... [--env K=V]... [--unset-env K]... [--idle-pause <seconds>] [--auto-wake on|off]
|
|
164
170
|
[--persistent on|off] [--max-total-cost <usd>|none]
|
|
171
|
+
[--timeout <60-86400 from now>|0] [--on-timeout pause|stop|delete]
|
|
165
172
|
Change its settings; persistent keeps it running until stopped
|
|
166
173
|
snapshot <id> [--name n] [--retention days|credit] Keep its whole machine; prints the snapshot id
|
|
167
174
|
mount <id> <s3|r2|gcs>://<bucket>[/prefix] <path> [--secret NAME] [--region r]
|
|
@@ -179,8 +186,9 @@ const SANDBOX_HELP = `runtime sandboxes <command>
|
|
|
179
186
|
Print file changes as they happen, until Ctrl-C
|
|
180
187
|
mcp catalog MCP servers a sandbox can run (licence, settings, hosts)
|
|
181
188
|
mcp <id> start <server>... [--secret SERVER.SETTING=SECRET]... [--env SERVER.NAME=value]...
|
|
182
|
-
[--option SERVER.NAME=value]... [--port 8765] [--replace]
|
|
189
|
+
[--option SERVER.NAME=value]... [--port 8765] [--replace] [--public]
|
|
183
190
|
Start them; prints each URL and the header to send
|
|
191
|
+
(--public: URLs that never expire, paid only)
|
|
184
192
|
mcp <id> [status] | mcp <id> stop Their state and fresh URLs; stop them
|
|
185
193
|
preview <id> <port> [--public] [--ttl <s>] Share a port at an HTTPS address (--public: paid only)
|
|
186
194
|
preview rotate <id> <port> Refuse every token given out for a private port so
|
|
@@ -254,7 +262,7 @@ commandAfter) {
|
|
|
254
262
|
if (arg.startsWith("--") || (arg.startsWith("-") && arg.length === 2 && !/^-\d/.test(arg))) {
|
|
255
263
|
const [typed, inline] = arg.replace(/^-+/, "").split(/=(.*)/s, 2);
|
|
256
264
|
// A plural of an option is the option once per comma: --hosts a,b is
|
|
257
|
-
// --host a --host b (13 October 2026:
|
|
265
|
+
// --host a --host b (13 October 2026: a user's first try at a secret).
|
|
258
266
|
const plural = !known.has(typed) &&
|
|
259
267
|
typed.endsWith("s") &&
|
|
260
268
|
LISTS.has(typed.slice(0, -1)) &&
|
|
@@ -428,6 +436,7 @@ const SANDBOX_MOVED = ["run", "ssh", "port-forward", "forward"];
|
|
|
428
436
|
const SANDBOX_VERBS = [
|
|
429
437
|
"run",
|
|
430
438
|
"ssh",
|
|
439
|
+
"code",
|
|
431
440
|
"port-forward",
|
|
432
441
|
"create",
|
|
433
442
|
"ls",
|
|
@@ -585,12 +594,12 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
|
|
|
585
594
|
out.error(`Warning: ${named(words.warning)}`);
|
|
586
595
|
const [first, ...remaining] = words.argv;
|
|
587
596
|
// Sandbox is one product of several, so its commands live under it
|
|
588
|
-
// (
|
|
597
|
+
// (23 September 2026): `runtime sandboxes run`, `sandbox ssh` and
|
|
589
598
|
// `sandbox port-forward`. The old top-level forms were removed, not aliased.
|
|
590
599
|
if (first && SANDBOX_MOVED.includes(first))
|
|
591
600
|
throw usage(`\`${me} ${first}\` is now \`${me} sandboxes ${first === "forward" ? "port-forward" : first}\`.`);
|
|
592
601
|
const nested = (first === "sandbox" || first === "sandboxes" || first === "sbx") &&
|
|
593
|
-
SANDBOX_MOVED.includes(remaining[0] ?? "");
|
|
602
|
+
[...SANDBOX_MOVED, "code"].includes(remaining[0] ?? "");
|
|
594
603
|
const command = nested ? remaining[0] : first;
|
|
595
604
|
const rest = nested ? remaining.slice(1) : remaining;
|
|
596
605
|
// `runtime sandboxes create --help` is how an agent asks what a command takes:
|
|
@@ -627,7 +636,7 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
|
|
|
627
636
|
: `Runtime Cloud ${VERSION}. ${start}
|
|
628
637
|
|
|
629
638
|
${me} sandboxes run -- python3 < invoice.py
|
|
630
|
-
Run a local invoice script, then
|
|
639
|
+
Run a local invoice script, then delete the sandbox
|
|
631
640
|
${me} sandboxes create A sandbox that stays; prints its id
|
|
632
641
|
${me} sandboxes exec <id> -- <command> Run in it
|
|
633
642
|
${me} help Everything else
|
|
@@ -649,24 +658,23 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
|
|
|
649
658
|
const onCapacityWait = waiting(out);
|
|
650
659
|
const sbx = await withVolumeRelease((options) => runtime.sandboxes.create(input, { ...options, onCapacityWait }), out);
|
|
651
660
|
let cleanup;
|
|
652
|
-
// SIGINT and normal completion share one
|
|
653
|
-
// across
|
|
661
|
+
// SIGINT and normal completion share one delete, with an absolute
|
|
662
|
+
// deadline across its retries, so cleanup cannot hang. A delete, not a
|
|
663
|
+
// stop: a stopped sandbox keeps its disk, billed, and an account without
|
|
664
|
+
// credit keeps at most 10, so ten runs that only stopped refused the
|
|
665
|
+
// eleventh (no_credit_kept_limit, 0685). --keep is how to keep one.
|
|
654
666
|
const stop = () => (cleanup ??= (async () => {
|
|
655
667
|
const signal = AbortSignal.timeout(30_000);
|
|
656
668
|
try {
|
|
657
|
-
await sbx.
|
|
658
|
-
if (sbx.state !== "stopped")
|
|
659
|
-
await sbx.waitFor("stopped", { timeoutSeconds: 25, signal });
|
|
660
|
-
if (sbx.state !== "stopped")
|
|
661
|
-
throw new Error(`Sandbox is still ${sbx.state}.`);
|
|
669
|
+
await sbx.delete({ signal });
|
|
662
670
|
return true;
|
|
663
671
|
}
|
|
664
672
|
catch (error) {
|
|
665
673
|
out.error(describeError(new RuntimeError({
|
|
666
674
|
code: "cleanup_failed",
|
|
667
675
|
status: 0,
|
|
668
|
-
message: `Could not confirm that sandbox ${sbx.id}
|
|
669
|
-
hint: `Check it and retry cleanup with: ${me} sandboxes
|
|
676
|
+
message: `Could not confirm that sandbox ${sbx.id} was deleted. ${error instanceof Error ? error.message : String(error)}`,
|
|
677
|
+
hint: `Check it and retry cleanup with: ${me} sandboxes rm ${sbx.id}`,
|
|
670
678
|
cause: error,
|
|
671
679
|
}), out.json));
|
|
672
680
|
return false;
|
|
@@ -1035,6 +1043,10 @@ export async function run(argv, env = process.env, out = defaultOut(argv)) {
|
|
|
1035
1043
|
product = "ssh";
|
|
1036
1044
|
return (await import("./ssh.js")).sshCommand(rest, env, out, () => client(env), me);
|
|
1037
1045
|
}
|
|
1046
|
+
if (nested && command === "code") {
|
|
1047
|
+
product = "ssh";
|
|
1048
|
+
return (await import("./ssh.js")).editorCommand(rest, env, out, () => client(env), me);
|
|
1049
|
+
}
|
|
1038
1050
|
if (command === "port-forward" || command === "forward") {
|
|
1039
1051
|
product = "ssh";
|
|
1040
1052
|
return (await import("./ssh.js")).portForwardCommand(rest, out, () => client(env), me);
|
|
@@ -1707,13 +1719,14 @@ async function sandbox(argv, env, out) {
|
|
|
1707
1719
|
return 0;
|
|
1708
1720
|
}
|
|
1709
1721
|
case "resize": {
|
|
1710
|
-
const args = parse(rest, ["restart"], ["vcpu", "memory"]);
|
|
1722
|
+
const args = parse(rest, ["restart"], ["vcpu", "memory", "disk"]);
|
|
1711
1723
|
const sbx = await use(need(args.positional[0], `a sandbox, e.g. ${me} sandboxes resize <id> --memory 4096 --restart`));
|
|
1712
1724
|
const size = {
|
|
1713
1725
|
...(integer(args, "vcpu") !== undefined ? { vcpu: integer(args, "vcpu") } : {}),
|
|
1714
1726
|
...(integer(args, "memory") !== undefined ? { memoryMiB: integer(args, "memory") } : {}),
|
|
1727
|
+
...(integer(args, "disk") !== undefined ? { diskMiB: integer(args, "disk") } : {}),
|
|
1715
1728
|
};
|
|
1716
|
-
if (size.vcpu === undefined && size.memoryMiB === undefined)
|
|
1729
|
+
if (size.vcpu === undefined && size.memoryMiB === undefined && size.diskMiB === undefined)
|
|
1717
1730
|
throw usage(`Name a new size, e.g. ${me} sandboxes resize ${sbx.id} --memory 4096 --restart`);
|
|
1718
1731
|
if (!args.flags.has("restart"))
|
|
1719
1732
|
throw usage(`A resize restarts it: its whole disk stays and its programs stop. Add --restart to say so, or snapshot it first (${me} sandboxes snapshot ${sbx.id}) to keep its memory too.`);
|
|
@@ -1852,6 +1865,8 @@ async function sandbox(argv, env, out) {
|
|
|
1852
1865
|
"auto-wake",
|
|
1853
1866
|
"persistent",
|
|
1854
1867
|
"max-total-cost",
|
|
1868
|
+
"timeout",
|
|
1869
|
+
"on-timeout",
|
|
1855
1870
|
]);
|
|
1856
1871
|
const sbx = await get(args.positional[0]);
|
|
1857
1872
|
const onOff = (name) => {
|
|
@@ -1862,6 +1877,9 @@ async function sandbox(argv, env, out) {
|
|
|
1862
1877
|
throw usage(`--${name} takes on or off.`);
|
|
1863
1878
|
return value === "on";
|
|
1864
1879
|
};
|
|
1880
|
+
const onTimeout = flag(args, "on-timeout")
|
|
1881
|
+
? oneOf(args, "on-timeout", ["pause", "stop", "delete"])
|
|
1882
|
+
: undefined;
|
|
1865
1883
|
const cost = flag(args, "max-total-cost");
|
|
1866
1884
|
if (cost !== undefined && cost !== "none" && !/^\d+(\.\d{1,6})?$/.test(cost))
|
|
1867
1885
|
throw usage("--max-total-cost takes dollars, such as 25 or 2.50, or none.");
|
|
@@ -1883,9 +1901,13 @@ async function sandbox(argv, env, out) {
|
|
|
1883
1901
|
: {
|
|
1884
1902
|
maxTotalCostMicros: cost === "none" ? null : usdMicros(args, "max-total-cost"),
|
|
1885
1903
|
}),
|
|
1904
|
+
...(integer(args, "timeout") !== undefined
|
|
1905
|
+
? { timeoutSeconds: integer(args, "timeout") }
|
|
1906
|
+
: {}),
|
|
1907
|
+
...(onTimeout === undefined ? {} : { onTimeout }),
|
|
1886
1908
|
};
|
|
1887
1909
|
if (!Object.keys(settings).length)
|
|
1888
|
-
throw usage("Say what to change: --name, --label, --env, --unset-env, --idle-pause, --auto-wake, --persistent
|
|
1910
|
+
throw usage("Say what to change: --name, --label, --env, --unset-env, --idle-pause, --auto-wake, --persistent, --max-total-cost, --timeout or --on-timeout.");
|
|
1889
1911
|
await sbx.update(settings);
|
|
1890
1912
|
print(describe(sbx.info), sbx.info);
|
|
1891
1913
|
return 0;
|
|
@@ -2191,7 +2213,7 @@ function attachment(spec) {
|
|
|
2191
2213
|
* A terminal: one line, not shown. */
|
|
2192
2214
|
/** A pasted secret as the header it becomes: no line breaks (a token copied
|
|
2193
2215
|
* from a terminal arrives wrapped), no bracketed-paste markers, no space at
|
|
2194
|
-
* either end. 13 October 2026:
|
|
2216
|
+
* either end. 13 October 2026: a user's pasted Claude token was refused as
|
|
2195
2217
|
* "not visible ASCII". A header cannot hold a line break, so none is lost. */
|
|
2196
2218
|
export function cleanSecret(raw) {
|
|
2197
2219
|
return raw
|
|
@@ -2603,8 +2625,8 @@ Making, listing and revoking keys with a key needs one an owner or admin made.
|
|
|
2603
2625
|
Every key is also at https://withruntime.com/account/keys.
|
|
2604
2626
|
`;
|
|
2605
2627
|
/* `runtime keys`: a key made from the terminal, by this machine's key with no
|
|
2606
|
-
browser (
|
|
2607
|
-
(
|
|
2628
|
+
browser (14 October 2026), or approved in the browser
|
|
2629
|
+
(23 September 2026; ARCHITECTURE.md section 10, "Keys from the
|
|
2608
2630
|
terminal"). Only the options the keys page offers. */
|
|
2609
2631
|
/* `runtime account`: the accounts this machine is connected to, and which one
|
|
2610
2632
|
every command uses (ARCHITECTURE.md section 3.9). Each is its own saved
|
|
@@ -2787,7 +2809,7 @@ async function keys(argv, env, out) {
|
|
|
2787
2809
|
dailyLimitMicros: limit === undefined ? null : dailyLimitMicros(limit),
|
|
2788
2810
|
};
|
|
2789
2811
|
/* A key on this machine makes the new one itself, with no browser: an
|
|
2790
|
-
agent with no person, a swarm's coordinator (
|
|
2812
|
+
agent with no person, a swarm's coordinator (14 October 2026). */
|
|
2791
2813
|
const saved = has(args, "browser")
|
|
2792
2814
|
? null
|
|
2793
2815
|
: env.RUNTIME_API_KEY || (await connectionStore(env).read())?.key || null;
|
|
@@ -3701,6 +3723,7 @@ const CREATE_VALUES = [
|
|
|
3701
3723
|
"connect",
|
|
3702
3724
|
"image",
|
|
3703
3725
|
"snapshot",
|
|
3726
|
+
"spread-from",
|
|
3704
3727
|
"volume",
|
|
3705
3728
|
"env",
|
|
3706
3729
|
];
|
|
@@ -3728,6 +3751,18 @@ function createInput(args) {
|
|
|
3728
3751
|
return {
|
|
3729
3752
|
...(flag(args, "image") ? { image: flag(args, "image") } : {}),
|
|
3730
3753
|
...(flag(args, "snapshot") ? { snapshot: flag(args, "snapshot") } : {}),
|
|
3754
|
+
...(args.flags.has("spread-from")
|
|
3755
|
+
? {
|
|
3756
|
+
spreadFrom: args.flags
|
|
3757
|
+
.get("spread-from")
|
|
3758
|
+
.flatMap((value) => value.split(","))
|
|
3759
|
+
.map((id) => {
|
|
3760
|
+
if (!id.trim())
|
|
3761
|
+
throw usage("--spread-from needs a non-empty value.");
|
|
3762
|
+
return id.trim();
|
|
3763
|
+
}),
|
|
3764
|
+
}
|
|
3765
|
+
: {}),
|
|
3731
3766
|
...(args.flags.has("volume") ? { volumes: args.flags.get("volume").map(attachment) } : {}),
|
|
3732
3767
|
...(has(args, "no-internet") || rules.length
|
|
3733
3768
|
? {
|
package/dist/client.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Sandbox } from "./sandbox.js";
|
|
|
6
6
|
import { Snapshots } from "./snapshots.js";
|
|
7
7
|
import { Transport, type RequestOptions } from "./transport.js";
|
|
8
8
|
import type { CreateSandbox, DeletedSandbox, FeedbackKind, SandboxInfo, Usage } from "./types.js";
|
|
9
|
-
export type { CreateOptions } from "./machine.js";
|
|
9
|
+
export type { CreateOptions, LifecycleOptions } from "./machine.js";
|
|
10
10
|
export type RuntimeOptions = {
|
|
11
11
|
/** Default: the RUNTIME_API_KEY environment variable. */
|
|
12
12
|
apiKey?: string;
|
package/dist/daytona/client.d.ts
CHANGED
|
@@ -40,5 +40,9 @@ export interface DaytonaConfig {
|
|
|
40
40
|
export declare function pickKey(explicit?: string): string | undefined;
|
|
41
41
|
/** The Runtime client for this configuration. */
|
|
42
42
|
export declare function clientFor(config?: DaytonaConfig): Runtime;
|
|
43
|
+
/** Runtime runs in one US region: a Daytona target (the client's, or a
|
|
44
|
+
* create's own since @daytona/sdk 0.224) other than "us" is refused, and
|
|
45
|
+
* none or "" means that region. */
|
|
46
|
+
export declare function refuseTarget(target: string | undefined): void;
|
|
43
47
|
/** Test hook: forget the cached clients. */
|
|
44
48
|
export declare function resetClients(): void;
|
package/dist/daytona/client.js
CHANGED
|
@@ -21,9 +21,7 @@ const clients = new Map();
|
|
|
21
21
|
export function clientFor(config = {}) {
|
|
22
22
|
if (config.jwtToken !== undefined || (config.organizationId !== undefined && !config.apiKey))
|
|
23
23
|
throw new NotSupportedError("Daytona JWT sign-in (jwtToken, organizationId)", "Use a Runtime key: set RUNTIME_API_KEY, or run `npx withruntime login` once.");
|
|
24
|
-
|
|
25
|
-
if (target !== undefined && target !== "" && target !== "us")
|
|
26
|
-
throw new NotSupportedError(`The Daytona target "${target}"`, 'Runtime runs in one US region; remove target or use "us".');
|
|
24
|
+
refuseTarget(config.target ?? env("DAYTONA_TARGET"));
|
|
27
25
|
if (config.withruntime?.client)
|
|
28
26
|
return config.withruntime.client;
|
|
29
27
|
const key = pickKey(config.apiKey);
|
|
@@ -34,6 +32,13 @@ export function clientFor(config = {}) {
|
|
|
34
32
|
}
|
|
35
33
|
return client;
|
|
36
34
|
}
|
|
35
|
+
/** Runtime runs in one US region: a Daytona target (the client's, or a
|
|
36
|
+
* create's own since @daytona/sdk 0.224) other than "us" is refused, and
|
|
37
|
+
* none or "" means that region. */
|
|
38
|
+
export function refuseTarget(target) {
|
|
39
|
+
if (target !== undefined && target !== "" && target !== "us")
|
|
40
|
+
throw new NotSupportedError(`The Daytona target "${target}"`, 'Runtime runs in one US region; remove target or use "us".');
|
|
41
|
+
}
|
|
37
42
|
/** Test hook: forget the cached clients. */
|
|
38
43
|
export function resetClients() {
|
|
39
44
|
clients.clear();
|
|
@@ -62,6 +62,9 @@ export type CreateSandboxBaseParams = {
|
|
|
62
62
|
spot?: boolean;
|
|
63
63
|
linkedSandbox?: string;
|
|
64
64
|
secrets?: Record<string, string>;
|
|
65
|
+
/** The region for this create, over the client's target: "us" (Runtime's
|
|
66
|
+
* one region) or none; any other is refused. */
|
|
67
|
+
target?: string;
|
|
65
68
|
/** Runtime-only: an explicit client, or fields for this create. */
|
|
66
69
|
withruntime?: WithRuntime;
|
|
67
70
|
};
|
package/dist/daytona/daytona.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { clientFor, } from "./client.js";
|
|
1
|
+
import { clientFor, refuseTarget, } from "./client.js";
|
|
2
2
|
import { DaytonaError, DaytonaInvalidArgumentError, DaytonaNotFoundError, DaytonaQueueTimeoutError, guard, NotSupportedError, } from "./errors.js";
|
|
3
3
|
import { RuntimeError } from "../errors.js";
|
|
4
4
|
import { LEASE_MAX_SECONDS } from "../compat/lease.js";
|
|
@@ -433,6 +433,7 @@ function refuseCreate(params) {
|
|
|
433
433
|
gpuType !== "" &&
|
|
434
434
|
(!Array.isArray(gpuType) || gpuType.length > 0)))
|
|
435
435
|
throw new NotSupportedError("GPUs", "Runtime runs sandboxes on CPUs; remove gpu and gpuType from resources.");
|
|
436
|
+
refuseTarget(params.target);
|
|
436
437
|
if (params.volumes?.some((mount) => mount.subpath))
|
|
437
438
|
throw new NotSupportedError("Mounting part of a volume (subpath)", "Mount the whole volume.");
|
|
438
439
|
if (params.kvm)
|
package/dist/e2b/sandbox.d.ts
CHANGED
|
@@ -148,11 +148,12 @@ export declare class Sandbox {
|
|
|
148
148
|
* deleted. */
|
|
149
149
|
static kill(sandboxId: string, opts?: SandboxApiOpts): Promise<boolean>;
|
|
150
150
|
kill(opts?: Pick<ConnectionOpts, "requestTimeoutMs" | "signal">): Promise<boolean>;
|
|
151
|
-
/** Sets the sandbox to end `timeoutMs` from now, up to 24
|
|
152
|
-
* does
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
151
|
+
/** Sets the sandbox to end `timeoutMs` from now, sooner or later, up to 24
|
|
152
|
+
* hours, as E2B does: the server keeps the new time limit (an update's
|
|
153
|
+
* timeoutSeconds), and what the end does stays as created. Under a minute
|
|
154
|
+
* is a minute, Runtime's shortest limit. A sandbox with no time limit gets
|
|
155
|
+
* one; a persistent one (a pilot's, kept running by the server) has none to
|
|
156
|
+
* set, and nothing changes. */
|
|
156
157
|
static setTimeout(sandboxId: string, timeoutMs: number, opts?: SandboxApiOpts): Promise<void>;
|
|
157
158
|
setTimeout(timeoutMs: number, opts?: Pick<ConnectionOpts, "requestTimeoutMs" | "signal">): Promise<void>;
|
|
158
159
|
static getInfo(sandboxId: string, opts?: SandboxApiOpts): Promise<SandboxInfo>;
|
package/dist/e2b/sandbox.js
CHANGED
|
@@ -414,11 +414,12 @@ export class Sandbox {
|
|
|
414
414
|
throw error;
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
|
-
/** Sets the sandbox to end `timeoutMs` from now, up to 24
|
|
418
|
-
* does
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
417
|
+
/** Sets the sandbox to end `timeoutMs` from now, sooner or later, up to 24
|
|
418
|
+
* hours, as E2B does: the server keeps the new time limit (an update's
|
|
419
|
+
* timeoutSeconds), and what the end does stays as created. Under a minute
|
|
420
|
+
* is a minute, Runtime's shortest limit. A sandbox with no time limit gets
|
|
421
|
+
* one; a persistent one (a pilot's, kept running by the server) has none to
|
|
422
|
+
* set, and nothing changes. */
|
|
422
423
|
static async setTimeout(sandboxId, timeoutMs, opts = {}) {
|
|
423
424
|
const client = clientFor(opts);
|
|
424
425
|
const runtime = await guard("sandbox", () => client.sandboxes.get(sandboxId, request(opts)));
|
|
@@ -617,14 +618,10 @@ function secondsLater(runtime, timeoutMs) {
|
|
|
617
618
|
return (Date.now() + timeoutMs - end) / 1000;
|
|
618
619
|
}
|
|
619
620
|
async function extendTo(runtime, timeoutMs, opts) {
|
|
620
|
-
|
|
621
|
-
if (runtime.info.
|
|
621
|
+
const seconds = timeoutSeconds(timeoutMs);
|
|
622
|
+
if (runtime.info.persistent === true)
|
|
622
623
|
return;
|
|
623
|
-
|
|
624
|
-
if (later < -1)
|
|
625
|
-
throw new NotSupportedError("Ending a sandbox sooner than its time limit (a shorter setTimeout)", "Runtime cannot bring a time limit forward. Call kill() when the work is done.");
|
|
626
|
-
if (later > 1)
|
|
627
|
-
await guard("sandbox", () => runtime.extend(Math.ceil(later), request(opts)));
|
|
624
|
+
await guard("sandbox", () => runtime.update({ timeoutSeconds: seconds }, request(opts)));
|
|
628
625
|
}
|
|
629
626
|
async function pause(runtime, opts) {
|
|
630
627
|
if (snapshotMemory("mode", opts.mode, opts.keepMemory) === false)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Runtime } from "../client.js";
|
|
2
|
-
import type { Sandbox
|
|
2
|
+
import type { Sandbox } from "../sandbox.js";
|
|
3
3
|
import type { Snapshot } from "../snapshots.js";
|
|
4
4
|
import { CompatibilityError, type ClientOptions, type Refused, type RefusedAsync } from "../compat/core.js";
|
|
5
5
|
export { CompatibilityError };
|
|
@@ -341,7 +341,30 @@ export interface PtyAttachOptions {
|
|
|
341
341
|
session: PtySessionSelector;
|
|
342
342
|
linuxUser?: string;
|
|
343
343
|
}
|
|
344
|
+
export type PtyConnectionState = "connecting" | "connected" | "reconnecting" | "closed" | "exited";
|
|
345
|
+
export interface PtyReconnectOptions {
|
|
346
|
+
/** Total time to recover one dropped connection. Default: five minutes. */
|
|
347
|
+
timeoutMs?: number;
|
|
348
|
+
/** Initial backoff, with 30% jitter. Default: 400ms. */
|
|
349
|
+
initialDelayMs?: number;
|
|
350
|
+
/** Backoff ceiling before jitter. Default: 10 seconds. */
|
|
351
|
+
maxDelayMs?: number;
|
|
352
|
+
}
|
|
344
353
|
export interface PtySessionEvents {
|
|
354
|
+
/** Reattach by itself after a dropped connection (Freestyle 0.2.18). */
|
|
355
|
+
reconnect?: boolean | PtyReconnectOptions;
|
|
356
|
+
/** Longest wait for each connection's terminal. Recovery waits at most 15
|
|
357
|
+
* seconds by default; a first connection, only when this is given. */
|
|
358
|
+
connectTimeoutMs?: number;
|
|
359
|
+
onStateChange?: (state: PtyConnectionState) => void;
|
|
360
|
+
/** Freestyle's exact replay boundaries. A Runtime terminal replays the
|
|
361
|
+
* session's output from its start on each connection without marking where
|
|
362
|
+
* the replay ends, as Freestyle's older guest agents do, so these never
|
|
363
|
+
* fire: the replay begins at the "connected" state. */
|
|
364
|
+
onReplayStart?: (info: {
|
|
365
|
+
exact: boolean;
|
|
366
|
+
}) => void;
|
|
367
|
+
onReplayEnd?: () => void;
|
|
345
368
|
onData?: (data: Uint8Array) => void;
|
|
346
369
|
onExit?: (exitCode: number) => void;
|
|
347
370
|
onClose?: (info: {
|
|
@@ -353,25 +376,37 @@ export interface PtySessionEvents {
|
|
|
353
376
|
}
|
|
354
377
|
/** A session's number: FNV-1a of its process id, 31 bits, never 0. */
|
|
355
378
|
export declare function sessionNumber(processId: string): number;
|
|
379
|
+
/** A stable handle across reattachments; input is never retried or buffered.
|
|
380
|
+
* Each connection is a Runtime terminal attached to the session's process. */
|
|
356
381
|
export declare class PtySession {
|
|
357
382
|
#private;
|
|
358
|
-
private readonly terminal;
|
|
359
383
|
private readonly sandbox;
|
|
360
384
|
private readonly processId;
|
|
361
385
|
readonly sessionId: number;
|
|
362
386
|
readonly slug: string | undefined;
|
|
363
387
|
readonly created: boolean;
|
|
364
|
-
|
|
365
|
-
|
|
388
|
+
private readonly events;
|
|
389
|
+
/** Resolves once the first connection is up. */
|
|
390
|
+
readonly ready: Promise<void>;
|
|
391
|
+
constructor(sandbox: Sandbox, processId: string, sessionId: number, slug: string | undefined, created: boolean, events: PtySessionEvents, dimensions?: {
|
|
392
|
+
cols: number;
|
|
393
|
+
rows: number;
|
|
394
|
+
});
|
|
395
|
+
/** Retry now after a network change or a spent retry budget. Never opens a new shell. */
|
|
396
|
+
reconnect(): void;
|
|
397
|
+
/** Send input once. Throws while disconnected; uncertain keystrokes are never replayed. */
|
|
366
398
|
write(data: Uint8Array | string): void;
|
|
399
|
+
/** Remembers the size and applies it again after a reattachment. */
|
|
367
400
|
resize(options: {
|
|
368
401
|
cols: number;
|
|
369
402
|
rows: number;
|
|
370
403
|
}): void;
|
|
371
404
|
signal(sig: "sigint" | "sigkill"): void;
|
|
372
|
-
/**
|
|
405
|
+
/** Cancels recovery and closes the connection; the shell keeps running and
|
|
406
|
+
* attach() finds it. */
|
|
373
407
|
detach(): void;
|
|
374
408
|
get readyState(): number;
|
|
409
|
+
get state(): PtyConnectionState;
|
|
375
410
|
}
|
|
376
411
|
export declare class VmPty {
|
|
377
412
|
private readonly get;
|
|
@@ -414,6 +449,43 @@ export declare class VmLinuxUserPty {
|
|
|
414
449
|
exitCode?: undefined;
|
|
415
450
|
}>;
|
|
416
451
|
}
|
|
452
|
+
interface XtermDisposable {
|
|
453
|
+
dispose(): void;
|
|
454
|
+
}
|
|
455
|
+
interface XtermSequence {
|
|
456
|
+
prefix?: string;
|
|
457
|
+
intermediates?: string;
|
|
458
|
+
final: string;
|
|
459
|
+
}
|
|
460
|
+
/** The xterm.js surface connectXterm uses; xterm itself is not a dependency. */
|
|
461
|
+
export interface XtermTerminal {
|
|
462
|
+
cols: number;
|
|
463
|
+
rows: number;
|
|
464
|
+
write(data: string | Uint8Array, callback?: () => void): void;
|
|
465
|
+
onData(listener: (data: string) => void): XtermDisposable;
|
|
466
|
+
onResize(listener: (size: {
|
|
467
|
+
cols: number;
|
|
468
|
+
rows: number;
|
|
469
|
+
}) => void): XtermDisposable;
|
|
470
|
+
parser: {
|
|
471
|
+
registerCsiHandler(id: XtermSequence, handler: () => boolean): XtermDisposable;
|
|
472
|
+
registerDcsHandler(id: XtermSequence, handler: () => boolean): XtermDisposable;
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
export type ConnectXtermOptions = PtyOpenOptions & PtySessionEvents & {
|
|
476
|
+
pty: VmPty | VmLinuxUserPty;
|
|
477
|
+
terminal: XtermTerminal;
|
|
478
|
+
slug: string;
|
|
479
|
+
};
|
|
480
|
+
/** Freestyle 0.2.18's connectXterm: xterm.js on a named session that
|
|
481
|
+
* reattaches by itself unless `reconnect: false`. Each connection replays the
|
|
482
|
+
* session's output from its start, so the screen is reset first and the
|
|
483
|
+
* replay's terminal queries go unanswered until it has been written (150ms
|
|
484
|
+
* quiet, at most 2 seconds). dispose() detaches; the shell keeps running. */
|
|
485
|
+
export declare function connectXterm({ pty, terminal, ...options }: ConnectXtermOptions): Promise<{
|
|
486
|
+
session: PtySession;
|
|
487
|
+
dispose(): void;
|
|
488
|
+
}>;
|
|
417
489
|
export declare class VmLinuxUser {
|
|
418
490
|
private readonly vm;
|
|
419
491
|
private readonly linuxUser;
|