withruntime 0.10.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 +40 -35
- package/E2B.md +70 -57
- package/README.md +3 -3
- package/README.src.md +3 -3
- package/VERCEL.md +23 -20
- package/compatibility-lock.json +63 -84
- 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 +112 -17
- package/dist/client.d.ts +17 -1
- package/dist/client.js +46 -3
- package/dist/compat/files.js +5 -1
- package/dist/compat/lease.d.ts +37 -0
- package/dist/compat/lease.js +93 -0
- package/dist/credentials.d.ts +9 -0
- package/dist/credentials.js +26 -4
- package/dist/daytona/computer-use.d.ts +162 -0
- package/dist/daytona/computer-use.js +324 -0
- package/dist/daytona/context.d.ts +10 -0
- package/dist/daytona/context.js +24 -0
- package/dist/daytona/daytona.d.ts +20 -0
- package/dist/daytona/daytona.js +150 -26
- package/dist/daytona/filesystem.js +8 -0
- package/dist/daytona/index.d.ts +2 -26
- package/dist/daytona/index.js +2 -7
- package/dist/daytona/process.d.ts +63 -6
- package/dist/daytona/process.js +224 -23
- package/dist/daytona/sandbox.d.ts +25 -6
- package/dist/daytona/sandbox.js +60 -27
- package/dist/e2b/client.d.ts +5 -0
- package/dist/e2b/client.js +5 -1
- package/dist/e2b/commands.d.ts +15 -6
- package/dist/e2b/commands.js +83 -18
- package/dist/e2b/errors.d.ts +7 -0
- package/dist/e2b/errors.js +20 -0
- package/dist/e2b/filesystem.d.ts +2 -1
- package/dist/e2b/filesystem.js +43 -6
- package/dist/e2b/index.d.ts +2 -2
- package/dist/e2b/index.js +1 -1
- package/dist/e2b/pty.js +6 -3
- package/dist/e2b/sandbox.d.ts +20 -6
- package/dist/e2b/sandbox.js +207 -31
- package/dist/e2b/users.d.ts +30 -0
- package/dist/e2b/users.js +185 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +6 -0
- package/dist/identity.js +2 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.js +6 -1
- package/dist/modal/index.js +6 -2
- package/dist/network-cli.js +33 -5
- package/dist/products/browser.d.ts +61 -0
- package/dist/products/browser.js +27 -0
- package/dist/products/desktop.d.ts +4 -3
- package/dist/products/desktop.js +7 -32
- package/dist/products/images.d.ts +3 -1
- package/dist/products/images.js +14 -2
- package/dist/products/index.d.ts +2 -0
- package/dist/products/index.js +2 -0
- 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 +8 -1
- package/dist/products/network-products.js +4 -1
- package/dist/products/observability.d.ts +1 -1
- package/dist/products/private-network.d.ts +22 -0
- package/dist/products/private-network.js +10 -0
- package/dist/products/secrets.d.ts +2 -2
- package/dist/runloop/index.js +6 -2
- package/dist/sandbox.d.ts +44 -14
- package/dist/sandbox.js +162 -48
- 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 +59 -11
- package/dist/vercel/filesystem.js +3 -1
- package/dist/vercel/index.d.ts +1 -7
- package/dist/vercel/index.js +1 -3
- package/dist/vercel/sandbox-user.d.ts +70 -0
- package/dist/vercel/sandbox-user.js +206 -0
- package/dist/vercel/sandbox.d.ts +57 -15
- package/dist/vercel/sandbox.js +219 -47
- package/dist/wait.d.ts +12 -0
- package/dist/wait.js +47 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export type { TailscaleJoin, TailscaleJoined, TailscaleNode, TailscaleStatus, }
|
|
|
25
25
|
export type { Volume, VolumeBackup, CreateVolume, VolumeAttachment } from "./products/volumes.js";
|
|
26
26
|
export type { CreateJob, Job, JobCompute, JobDefinition, JobLogs, JobRun, JobRunState, JobSchedule, } from "./products/jobs.js";
|
|
27
27
|
export type { CheckedDomain, DnsRecord, Domain, EgressAddress, TcpPort, Tunnel as PrivateTunnel, TunnelPeer, TunnelPeerCreated, SetUpstreamProxy, UpstreamProxy, } from "./products/network-products.js";
|
|
28
|
+
export type { PrivateNetwork } from "./products/private-network.js";
|
|
28
29
|
export { verifyWebhook, WebhookVerificationError, type MetricPoint, type MetricRange, type OtelExport, type RuntimeEvent, type SandboxMetrics, type Webhook, type WebhookDelivery, type WebhookEventType, } from "./products/observability.js";
|
|
29
30
|
export { Snapshots, type Snapshot, type SnapshotOptions } from "./snapshots.js";
|
|
30
31
|
export { Transport, VERSION, apiOrigin, type RequestOptions, type Call } from "./transport.js";
|
|
@@ -34,7 +35,8 @@ export type * from "./types.js";
|
|
|
34
35
|
* does the same with an explicit client. */
|
|
35
36
|
export declare class Sandbox extends SandboxClass {
|
|
36
37
|
/** Creates a sandbox (every field optional) and waits until it is running.
|
|
37
|
-
*
|
|
38
|
+
* With no `timeoutSeconds` it runs while it works and pauses when idle.
|
|
39
|
+
* `keepAlive: true` (or its options) carries one with a time limit past it
|
|
38
40
|
* until you stop it; see `sandbox.keepAlive()`. */
|
|
39
41
|
static create(input?: CreateSandbox & {
|
|
40
42
|
wait?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,8 @@ export * from "./errors.js";
|
|
|
14
14
|
* does the same with an explicit client. */
|
|
15
15
|
export class Sandbox extends SandboxClass {
|
|
16
16
|
/** Creates a sandbox (every field optional) and waits until it is running.
|
|
17
|
-
*
|
|
17
|
+
* With no `timeoutSeconds` it runs while it works and pauses when idle.
|
|
18
|
+
* `keepAlive: true` (or its options) carries one with a time limit past it
|
|
18
19
|
* until you stop it; see `sandbox.keepAlive()`. */
|
|
19
20
|
static async create(input = {}, options = {}) {
|
|
20
21
|
const { client, ...rest } = options;
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/** Bridges an MCP client that speaks stdio to Runtime's hosted MCP endpoint.
|
|
2
2
|
* Newline-delimited JSON-RPC in, the same out; every message is forwarded as
|
|
3
3
|
* it is, so the server's tools, schemas and `instructions` reach the client
|
|
4
|
-
* unchanged, and nothing here keeps a second catalogue.
|
|
4
|
+
* unchanged, and nothing here keeps a second catalogue. The one change: the
|
|
5
|
+
* initialize answer's serverInfo.version is this package's. Starting it costs a
|
|
5
6
|
* process and one TLS connection (undici loads only behind a proxy).
|
|
6
7
|
*
|
|
7
8
|
* With no key on this machine it does not fail: it serves one tool,
|
package/dist/mcp.js
CHANGED
|
@@ -14,7 +14,8 @@ const connectTool = {
|
|
|
14
14
|
/** Bridges an MCP client that speaks stdio to Runtime's hosted MCP endpoint.
|
|
15
15
|
* Newline-delimited JSON-RPC in, the same out; every message is forwarded as
|
|
16
16
|
* it is, so the server's tools, schemas and `instructions` reach the client
|
|
17
|
-
* unchanged, and nothing here keeps a second catalogue.
|
|
17
|
+
* unchanged, and nothing here keeps a second catalogue. The one change: the
|
|
18
|
+
* initialize answer's serverInfo.version is this package's. Starting it costs a
|
|
18
19
|
* process and one TLS connection (undici loads only behind a proxy).
|
|
19
20
|
*
|
|
20
21
|
* With no key on this machine it does not fail: it serves one tool,
|
|
@@ -79,6 +80,10 @@ export async function serveMcp(env = process.env, options = {}) {
|
|
|
79
80
|
const result = reply.result;
|
|
80
81
|
if (result?.protocolVersion)
|
|
81
82
|
protocolVersion = result.protocolVersion;
|
|
83
|
+
// The client runs this package: it reports the package's version, as
|
|
84
|
+
// before connecting, not the hosted API's contract version (0.2.0).
|
|
85
|
+
if (result?.serverInfo)
|
|
86
|
+
result.serverInfo.version = VERSION;
|
|
82
87
|
}
|
|
83
88
|
return { status: response.status, messages, text };
|
|
84
89
|
}
|
package/dist/modal/index.js
CHANGED
|
@@ -164,8 +164,12 @@ export class SandboxService {
|
|
|
164
164
|
vcpu: params.cpu,
|
|
165
165
|
memoryMiB: params.memoryMiB,
|
|
166
166
|
region: placement,
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
// A timeout is the customer's limit, and the sandbox never pauses
|
|
168
|
+
// for idleness before it. None is no time limit (0300): it runs while
|
|
169
|
+
// it works and pauses when idle.
|
|
170
|
+
...(params.timeoutMs === undefined
|
|
171
|
+
? {}
|
|
172
|
+
: { timeoutSeconds: Math.ceil(params.timeoutMs / 1000), idlePauseSeconds: 0 }),
|
|
169
173
|
onLeaseEnd: "stop",
|
|
170
174
|
network: {
|
|
171
175
|
internet: !params.blockNetwork,
|
package/dist/network-cli.js
CHANGED
|
@@ -25,7 +25,7 @@ export const NETWORK_HELP = {
|
|
|
25
25
|
ls Your domains
|
|
26
26
|
get <hostname> One domain and its DNS records
|
|
27
27
|
rm <hostname> Stop serving it
|
|
28
|
-
|
|
28
|
+
Needs a kept top-up. The first visit gets the certificate, in a few seconds.
|
|
29
29
|
`,
|
|
30
30
|
port: `runtime port <command>
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ export const NETWORK_HELP = {
|
|
|
34
34
|
Prints address:port for your client
|
|
35
35
|
ls [--sandbox <id>] Your open ports
|
|
36
36
|
close <portId> Close one, its open connections too
|
|
37
|
-
|
|
37
|
+
Needs a kept top-up. TCP, carried as it is: use your service's own password and TLS.
|
|
38
38
|
`,
|
|
39
39
|
address: `runtime address <command>
|
|
40
40
|
|
|
@@ -42,7 +42,7 @@ export const NETWORK_HELP = {
|
|
|
42
42
|
account sends from it, for allow-lists
|
|
43
43
|
ls Your addresses
|
|
44
44
|
release <addressId> Give it back; sandboxes use the shared addresses again
|
|
45
|
-
|
|
45
|
+
Needs credit on the account.
|
|
46
46
|
`,
|
|
47
47
|
tunnel: `runtime tunnel <command>
|
|
48
48
|
|
|
@@ -56,7 +56,7 @@ export const NETWORK_HELP = {
|
|
|
56
56
|
peer rotate <peerId> [--out runtime.conf]
|
|
57
57
|
A new key; the old one stops working within seconds
|
|
58
58
|
peer rm <peerId> Remove it; its tunnel ends within seconds
|
|
59
|
-
--route: your own ranges behind the peer that sandboxes may reach.
|
|
59
|
+
--route: your own ranges behind the peer that sandboxes may reach. Needs a kept top-up.
|
|
60
60
|
`,
|
|
61
61
|
network: `runtime network <command>
|
|
62
62
|
|
|
@@ -69,7 +69,13 @@ export const NETWORK_HELP = {
|
|
|
69
69
|
upstream-proxy get The proxy in use
|
|
70
70
|
upstream-proxy remove Connections leave directly again
|
|
71
71
|
A proxy that refuses or cannot be reached fails the connection; nothing goes
|
|
72
|
-
around it.
|
|
72
|
+
around it. Needs a kept top-up.
|
|
73
|
+
|
|
74
|
+
private on Your sandboxes reach each other by name, over TCP:
|
|
75
|
+
<name>.sandbox.internal:<port> or <id>.sandbox.internal:<port>
|
|
76
|
+
private off They stop; open connections between them are cut
|
|
77
|
+
private status On or off
|
|
78
|
+
Only your own sandboxes answer. Needs a kept top-up; free.
|
|
73
79
|
`,
|
|
74
80
|
};
|
|
75
81
|
function usage(product, message) {
|
|
@@ -400,6 +406,28 @@ export async function networkProductCommand(product, argv, args, out, client) {
|
|
|
400
406
|
}
|
|
401
407
|
}
|
|
402
408
|
}
|
|
409
|
+
if (product === "network" && verb === "private") {
|
|
410
|
+
const describe = (state) => state.enabled
|
|
411
|
+
? "On: your sandboxes reach each other at <name>.sandbox.internal:<port> over TCP."
|
|
412
|
+
: state.allowed
|
|
413
|
+
? "Off. Turn it on: runtime network private on"
|
|
414
|
+
: "Off. Reaching your sandboxes by name needs a kept top-up.";
|
|
415
|
+
switch (rest[0]) {
|
|
416
|
+
case "on":
|
|
417
|
+
case "off": {
|
|
418
|
+
const state = await runtime.network.private.set({ enabled: rest[0] === "on" });
|
|
419
|
+
print(state.enabled ? describe(state) : "Off. Open connections between your sandboxes are cut.", state);
|
|
420
|
+
return 0;
|
|
421
|
+
}
|
|
422
|
+
case "status":
|
|
423
|
+
case undefined: {
|
|
424
|
+
const state = await runtime.network.private.get();
|
|
425
|
+
print(describe(state), state);
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
throw usage(product, "private takes on, off or status.");
|
|
430
|
+
}
|
|
403
431
|
if (product === "network") {
|
|
404
432
|
if (verb !== "upstream-proxy")
|
|
405
433
|
throw usage(product, `Unknown network command ${verb}.`);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Sandbox } from "../sandbox.js";
|
|
2
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
3
|
+
export type SandboxBrowser = {
|
|
4
|
+
running: false;
|
|
5
|
+
} | {
|
|
6
|
+
running: true;
|
|
7
|
+
headless: boolean;
|
|
8
|
+
/** Chromium's version, e.g. "Chrome/154.0.8037.92". */
|
|
9
|
+
version: string;
|
|
10
|
+
/** The browser's DevTools WebSocket with its private token: give it as it
|
|
11
|
+
* is to Playwright's `chromium.connectOverCDP`, `puppeteer.connect({
|
|
12
|
+
* browserWSEndpoint })`, browser-use or Stagehand. */
|
|
13
|
+
cdpUrl: string;
|
|
14
|
+
/** The DevTools HTTP endpoint; send `headers` with it. */
|
|
15
|
+
httpUrl: string;
|
|
16
|
+
headers: Record<string, string>;
|
|
17
|
+
/** When the token in cdpUrl ends; `get()` returns a fresh one. */
|
|
18
|
+
expiresAt: string | null;
|
|
19
|
+
/** headless: false only: the desktop's live view. */
|
|
20
|
+
streamUrl?: string;
|
|
21
|
+
};
|
|
22
|
+
export type BrowserStartOptions = {
|
|
23
|
+
/** true (the default): no window. false: on the sandbox's desktop, with a live view. */
|
|
24
|
+
headless?: boolean;
|
|
25
|
+
width?: number;
|
|
26
|
+
height?: number;
|
|
27
|
+
};
|
|
28
|
+
/** `sbx.browser`: Chromium in the sandbox, for agents that speak CDP.
|
|
29
|
+
*
|
|
30
|
+
* const { cdpUrl } = await sbx.browser.start();
|
|
31
|
+
* const browser = await chromium.connectOverCDP(cdpUrl);
|
|
32
|
+
*
|
|
33
|
+
* Inside the sandbox the same browser is at http://127.0.0.1:9222. */
|
|
34
|
+
export declare function sandboxBrowser(t: Transport, sandbox: Sandbox): {
|
|
35
|
+
/** Starts Chromium and returns its CDP address. The first start in a
|
|
36
|
+
* sandbox installs Chromium, about a minute; this waits for it (up to 10
|
|
37
|
+
* minutes, or the call's timeoutMs). Starting a running browser returns it
|
|
38
|
+
* as it is. */
|
|
39
|
+
start(input?: BrowserStartOptions, options?: RequestOptions): Promise<{
|
|
40
|
+
running: true;
|
|
41
|
+
headless: boolean;
|
|
42
|
+
/** Chromium's version, e.g. "Chrome/154.0.8037.92". */
|
|
43
|
+
version: string;
|
|
44
|
+
/** The browser's DevTools WebSocket with its private token: give it as it
|
|
45
|
+
* is to Playwright's `chromium.connectOverCDP`, `puppeteer.connect({
|
|
46
|
+
* browserWSEndpoint })`, browser-use or Stagehand. */
|
|
47
|
+
cdpUrl: string;
|
|
48
|
+
/** The DevTools HTTP endpoint; send `headers` with it. */
|
|
49
|
+
httpUrl: string;
|
|
50
|
+
headers: Record<string, string>;
|
|
51
|
+
/** When the token in cdpUrl ends; `get()` returns a fresh one. */
|
|
52
|
+
expiresAt: string | null;
|
|
53
|
+
/** headless: false only: the desktop's live view. */
|
|
54
|
+
streamUrl?: string;
|
|
55
|
+
}>;
|
|
56
|
+
/** Whether it runs, and a fresh cdpUrl when it does. */
|
|
57
|
+
get: (options?: RequestOptions) => Promise<SandboxBrowser>;
|
|
58
|
+
stop: (options?: RequestOptions) => Promise<{
|
|
59
|
+
stopped: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { whileInstalling } from "../wait.js";
|
|
2
|
+
/** `sbx.browser`: Chromium in the sandbox, for agents that speak CDP.
|
|
3
|
+
*
|
|
4
|
+
* const { cdpUrl } = await sbx.browser.start();
|
|
5
|
+
* const browser = await chromium.connectOverCDP(cdpUrl);
|
|
6
|
+
*
|
|
7
|
+
* Inside the sandbox the same browser is at http://127.0.0.1:9222. */
|
|
8
|
+
export function sandboxBrowser(t, sandbox) {
|
|
9
|
+
const base = () => `/v1/sandboxes/${encodeURIComponent(sandbox.id)}/browser`;
|
|
10
|
+
return {
|
|
11
|
+
/** Starts Chromium and returns its CDP address. The first start in a
|
|
12
|
+
* sandbox installs Chromium, about a minute; this waits for it (up to 10
|
|
13
|
+
* minutes, or the call's timeoutMs). Starting a running browser returns it
|
|
14
|
+
* as it is. */
|
|
15
|
+
async start(input = {}, options) {
|
|
16
|
+
return whileInstalling(["browser_installing", "desktop_installing"], options, (request) => t.json({
|
|
17
|
+
method: "POST",
|
|
18
|
+
path: `${base()}:start`,
|
|
19
|
+
body: input,
|
|
20
|
+
...request,
|
|
21
|
+
}));
|
|
22
|
+
},
|
|
23
|
+
/** Whether it runs, and a fresh cdpUrl when it does. */
|
|
24
|
+
get: (options) => t.json({ method: "GET", path: base(), ...options }),
|
|
25
|
+
stop: (options) => t.json({ method: "POST", path: `${base()}:stop`, ...options }),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -53,7 +53,8 @@ export type RecordOptions = {
|
|
|
53
53
|
* Coordinates are pixels from the top left of the screen. */
|
|
54
54
|
export declare function sandboxDesktop(t: Transport, sandbox: Sandbox): {
|
|
55
55
|
/** Starts the desktop. The first start in a sandbox installs it, which
|
|
56
|
-
* takes a minute or two; this waits for that (up to 10 minutes
|
|
56
|
+
* takes a minute or two; this waits for that (up to 10 minutes, or the
|
|
57
|
+
* call's timeoutMs). */
|
|
57
58
|
start(size?: {
|
|
58
59
|
width?: number;
|
|
59
60
|
height?: number;
|
|
@@ -115,8 +116,8 @@ export declare function sandboxDesktop(t: Transport, sandbox: Sandbox): {
|
|
|
115
116
|
focus: (windowId: string, options?: RequestOptions) => Promise<{
|
|
116
117
|
ok: true;
|
|
117
118
|
}>;
|
|
118
|
-
/** Opens `url` in
|
|
119
|
-
* start,
|
|
119
|
+
/** Opens `url` in Chromium on the desktop. Right after a sandbox's first
|
|
120
|
+
* start, Chromium may still be installing; this waits for it. */
|
|
120
121
|
open(url: string, options?: RequestOptions): Promise<{
|
|
121
122
|
ok: true;
|
|
122
123
|
}>;
|
package/dist/products/desktop.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { whileInstalling } from "../wait.js";
|
|
1
2
|
/** `sbx.desktop`: a Linux desktop in the sandbox, driven like a person would.
|
|
2
3
|
*
|
|
3
4
|
* const { streamUrl } = await sbx.desktop.start();
|
|
@@ -12,25 +13,10 @@ export function sandboxDesktop(t, sandbox) {
|
|
|
12
13
|
const act = (body, options) => t.json({ method: "POST", path: `${base()}:act`, body, ...options });
|
|
13
14
|
return {
|
|
14
15
|
/** Starts the desktop. The first start in a sandbox installs it, which
|
|
15
|
-
* takes a minute or two; this waits for that (up to 10 minutes
|
|
16
|
+
* takes a minute or two; this waits for that (up to 10 minutes, or the
|
|
17
|
+
* call's timeoutMs). */
|
|
16
18
|
async start(size = {}, options) {
|
|
17
|
-
|
|
18
|
-
for (;;) {
|
|
19
|
-
try {
|
|
20
|
-
return await t.json({
|
|
21
|
-
method: "POST",
|
|
22
|
-
path: `${base()}:start`,
|
|
23
|
-
body: size,
|
|
24
|
-
...options,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
const code = error.code;
|
|
29
|
-
if (code !== "desktop_installing" || Date.now() > deadline)
|
|
30
|
-
throw error;
|
|
31
|
-
await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs ?? 10_000));
|
|
32
|
-
}
|
|
33
|
-
}
|
|
19
|
+
return whileInstalling(["desktop_installing"], options, (request) => t.json({ method: "POST", path: `${base()}:start`, body: size, ...request }));
|
|
34
20
|
},
|
|
35
21
|
stop: (options) => t.json({ method: "POST", path: `${base()}:stop`, ...options }),
|
|
36
22
|
/** PNG bytes, or JPEG with `format: "jpeg"`. */
|
|
@@ -50,21 +36,10 @@ export function sandboxDesktop(t, sandbox) {
|
|
|
50
36
|
cursor: (options) => act({ action: "cursor" }, options),
|
|
51
37
|
windows: async (options) => (await act({ action: "windows" }, options)).windows,
|
|
52
38
|
focus: (windowId, options) => act({ action: "focus", windowId }, options),
|
|
53
|
-
/** Opens `url` in
|
|
54
|
-
* start,
|
|
39
|
+
/** Opens `url` in Chromium on the desktop. Right after a sandbox's first
|
|
40
|
+
* start, Chromium may still be installing; this waits for it. */
|
|
55
41
|
async open(url, options) {
|
|
56
|
-
|
|
57
|
-
for (;;) {
|
|
58
|
-
try {
|
|
59
|
-
return await act({ action: "open", url }, options);
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
const code = error.code;
|
|
63
|
-
if (code !== "desktop_installing" || Date.now() > deadline)
|
|
64
|
-
throw error;
|
|
65
|
-
await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs ?? 10_000));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
42
|
+
return whileInstalling(["desktop_installing"], options, (request) => act({ action: "open", url }, request));
|
|
68
43
|
},
|
|
69
44
|
/** Starts a program on the desktop, detached. */
|
|
70
45
|
launch: (argv, options) => act({ action: "launch", argv }, options),
|
|
@@ -212,7 +212,9 @@ export declare function images(t: Transport): {
|
|
|
212
212
|
/** Point `tag` of the image's name at this version. */
|
|
213
213
|
tag(ref: string, tag: string, options?: RequestOptions): Promise<Image>;
|
|
214
214
|
untag(ref: string, tag: string, options?: RequestOptions): Promise<Image>;
|
|
215
|
-
/** Delete one version (by id, name:tag or name@version) and its tags.
|
|
215
|
+
/** Delete one version (by id, name:tag or name@version) and its tags. A
|
|
216
|
+
* bare name deletes its latest tag's version, or its only version when
|
|
217
|
+
* it has one and no latest tag; with several, the error names its tags. */
|
|
216
218
|
delete(ref: string, options?: RequestOptions): Promise<Image>;
|
|
217
219
|
/** Credentials for private registries. The secret is sealed on arrival
|
|
218
220
|
* and never returned. */
|
package/dist/products/images.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
1
2
|
import { Page } from "../page.js";
|
|
2
3
|
const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
3
4
|
const PARALLEL_UPLOADS = 4;
|
|
@@ -189,11 +190,22 @@ export function images(t) {
|
|
|
189
190
|
...options,
|
|
190
191
|
});
|
|
191
192
|
},
|
|
192
|
-
/** Delete one version (by id, name:tag or name@version) and its tags.
|
|
193
|
+
/** Delete one version (by id, name:tag or name@version) and its tags. A
|
|
194
|
+
* bare name deletes its latest tag's version, or its only version when
|
|
195
|
+
* it has one and no latest tag; with several, the error names its tags. */
|
|
193
196
|
async delete(ref, options) {
|
|
197
|
+
const id = await idOf(ref, options).catch(async (error) => {
|
|
198
|
+
if (!(error instanceof RuntimeError && error.code === "image_not_found") ||
|
|
199
|
+
/[:@]/.test(ref))
|
|
200
|
+
throw error;
|
|
201
|
+
const live = (await list({ name: ref, limit: 100 }, options)).data.filter((image) => image.state !== "deleted" && image.state !== "deleting");
|
|
202
|
+
if (live.length !== 1)
|
|
203
|
+
throw error;
|
|
204
|
+
return live[0].id;
|
|
205
|
+
});
|
|
194
206
|
return t.json({
|
|
195
207
|
method: "POST",
|
|
196
|
-
path: `/v1/images/${enc(
|
|
208
|
+
path: `/v1/images/${enc(id)}:delete`,
|
|
197
209
|
body: {},
|
|
198
210
|
...options,
|
|
199
211
|
});
|
package/dist/products/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Transport } from "../transport.js";
|
|
|
2
2
|
import type { Sandbox } from "../sandbox.js";
|
|
3
3
|
import { images } from "./images.js";
|
|
4
4
|
import { sandboxDesktop } from "./desktop.js";
|
|
5
|
+
import { sandboxBrowser } from "./browser.js";
|
|
5
6
|
import { sandboxInterpreter } from "./interpreter.js";
|
|
6
7
|
import { sandboxNetwork } from "./network.js";
|
|
7
8
|
import { addresses, domains, network, ports, tunnel } from "./network-products.js";
|
|
@@ -55,6 +56,7 @@ export declare const sandboxExtensions: {
|
|
|
55
56
|
previews: typeof sandboxPreviews;
|
|
56
57
|
network: typeof sandboxNetwork;
|
|
57
58
|
desktop: typeof sandboxDesktop;
|
|
59
|
+
browser: typeof sandboxBrowser;
|
|
58
60
|
mounts: typeof sandboxMounts;
|
|
59
61
|
tailscale: typeof sandboxTailscale;
|
|
60
62
|
metrics: typeof sandboxMetrics;
|
package/dist/products/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { images } from "./images.js";
|
|
2
2
|
import { sandboxDesktop } from "./desktop.js";
|
|
3
|
+
import { sandboxBrowser } from "./browser.js";
|
|
3
4
|
import { sandboxInterpreter } from "./interpreter.js";
|
|
4
5
|
import { sandboxNetwork } from "./network.js";
|
|
5
6
|
import { addresses, domains, network, ports, tunnel } from "./network-products.js";
|
|
@@ -68,6 +69,7 @@ export const sandboxExtensions = {
|
|
|
68
69
|
previews: sandboxPreviews,
|
|
69
70
|
network: sandboxNetwork,
|
|
70
71
|
desktop: sandboxDesktop,
|
|
72
|
+
browser: sandboxBrowser,
|
|
71
73
|
mounts: sandboxMounts,
|
|
72
74
|
tailscale: sandboxTailscale,
|
|
73
75
|
metrics: sandboxMetrics,
|
package/dist/products/jobs.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Page } from "../page.js";
|
|
2
2
|
import type { RequestOptions, Transport } from "../transport.js";
|
|
3
|
-
/** A run's sandbox. Every field has a default; a run is a
|
|
4
|
-
* size,
|
|
3
|
+
/** A run's sandbox. Every field has a default; a run is a sandbox of this
|
|
4
|
+
* size, on the trial's hours first and then on credit at the sandbox rates. */
|
|
5
5
|
export type JobCompute = {
|
|
6
6
|
region: string;
|
|
7
7
|
vcpu: number;
|
|
@@ -147,11 +147,12 @@ export declare const JOB_DEFAULTS: {
|
|
|
147
147
|
startSeconds: number;
|
|
148
148
|
};
|
|
149
149
|
/** A run is one sandbox: at most 16 vCPU and 64 GiB, a disk no smaller than
|
|
150
|
-
* the system image, and paid for at most an hour. */
|
|
150
|
+
* the system image and no larger than 400 GiB, and paid for at most an hour. */
|
|
151
151
|
export declare const JOB_LIMITS: {
|
|
152
152
|
maxVcpu: number;
|
|
153
153
|
maxMemoryMiB: number;
|
|
154
154
|
minDiskMiB: number;
|
|
155
|
+
maxDiskMiB: number;
|
|
155
156
|
maxDurationSeconds: number;
|
|
156
157
|
maxAttempts: number;
|
|
157
158
|
maxSecrets: number;
|
|
@@ -167,8 +168,9 @@ export declare function jobBody(input: CreateJob): Record<string, unknown>;
|
|
|
167
168
|
* request id, and says no retry will change it. */
|
|
168
169
|
export declare function switchedOff(product: string): (error: unknown) => never;
|
|
169
170
|
/** Scheduled jobs: a command run in a fresh sandbox, once or on a cron
|
|
170
|
-
* schedule. Each run is a
|
|
171
|
-
*
|
|
171
|
+
* schedule. Each run is a sandbox, paid for as one: from the free trial's
|
|
172
|
+
* hours first while the run fits the trial's size and count, then from credit
|
|
173
|
+
* at the sandbox rates, through the same holds and spending limits.
|
|
172
174
|
*
|
|
173
175
|
* const job = await runtime.jobs.create({
|
|
174
176
|
* name: "nightly-report",
|
package/dist/products/jobs.js
CHANGED
|
@@ -15,11 +15,12 @@ export const JOB_DEFAULTS = {
|
|
|
15
15
|
startSeconds: JOB_START_SECONDS,
|
|
16
16
|
};
|
|
17
17
|
/** A run is one sandbox: at most 16 vCPU and 64 GiB, a disk no smaller than
|
|
18
|
-
* the system image, and paid for at most an hour. */
|
|
18
|
+
* the system image and no larger than 400 GiB, and paid for at most an hour. */
|
|
19
19
|
export const JOB_LIMITS = {
|
|
20
20
|
maxVcpu: 16,
|
|
21
21
|
maxMemoryMiB: 65_536,
|
|
22
22
|
minDiskMiB: 3072,
|
|
23
|
+
maxDiskMiB: 409_600,
|
|
23
24
|
maxDurationSeconds: 3600,
|
|
24
25
|
maxAttempts: 5,
|
|
25
26
|
maxSecrets: 16,
|
|
@@ -88,6 +89,8 @@ export function jobBody(input) {
|
|
|
88
89
|
throw invalid(`A run's sandbox is at most ${JOB_LIMITS.maxVcpu} vCPU and ${JOB_LIMITS.maxMemoryMiB / 1024} GiB of memory; asked for ${compute.vcpu} vCPU and ${compute.memoryMiB} MiB.`, compute.vcpu > JOB_LIMITS.maxVcpu ? "compute.vcpu" : "compute.memoryMiB");
|
|
89
90
|
if (compute.diskMiB < JOB_LIMITS.minDiskMiB)
|
|
90
91
|
throw invalid(`A run's disk is at least ${JOB_LIMITS.minDiskMiB} MiB, the size of the system image; asked for ${compute.diskMiB}.`, "compute.diskMiB");
|
|
92
|
+
if (compute.diskMiB > JOB_LIMITS.maxDiskMiB)
|
|
93
|
+
throw invalid(`A run's disk is at most ${JOB_LIMITS.maxDiskMiB} MiB (${JOB_LIMITS.maxDiskMiB / 1024} GiB); asked for ${compute.diskMiB}.`, "compute.diskMiB");
|
|
91
94
|
if (timeoutSeconds > compute.durationSeconds ||
|
|
92
95
|
compute.durationSeconds > JOB_LIMITS.maxDurationSeconds)
|
|
93
96
|
throw invalid(`timeoutSeconds (${timeoutSeconds}) must fit in the time a run is paid for (compute.durationSeconds ${compute.durationSeconds}), which is at most ${JOB_LIMITS.maxDurationSeconds} seconds.`, "timeoutSeconds");
|
|
@@ -125,8 +128,9 @@ export function switchedOff(product) {
|
|
|
125
128
|
};
|
|
126
129
|
}
|
|
127
130
|
/** Scheduled jobs: a command run in a fresh sandbox, once or on a cron
|
|
128
|
-
* schedule. Each run is a
|
|
129
|
-
*
|
|
131
|
+
* schedule. Each run is a sandbox, paid for as one: from the free trial's
|
|
132
|
+
* hours first while the run fits the trial's size and count, then from credit
|
|
133
|
+
* at the sandbox rates, through the same holds and spending limits.
|
|
130
134
|
*
|
|
131
135
|
* const job = await runtime.jobs.create({
|
|
132
136
|
* name: "nightly-report",
|
package/dist/products/mcp.d.ts
CHANGED
|
@@ -68,10 +68,14 @@ export declare function sandboxMcp(t: Transport, sandbox: Sandbox): {
|
|
|
68
68
|
}, options?: RequestOptions) => Promise<McpGateway>;
|
|
69
69
|
/** Their state, and fresh URLs. */
|
|
70
70
|
get: (options?: RequestOptions) => Promise<McpGateway>;
|
|
71
|
-
/** Wait until every server is ready (or one failed).
|
|
71
|
+
/** Wait until every server is ready (or one failed). Past `timeoutMs`
|
|
72
|
+
* (default ten minutes), the last state read; a status request still
|
|
73
|
+
* unanswered then is cut off at the deadline, and throws its timeout when
|
|
74
|
+
* no state was read at all. */
|
|
72
75
|
ready(input?: {
|
|
73
76
|
timeoutMs?: number;
|
|
74
77
|
intervalMs?: number;
|
|
78
|
+
signal?: AbortSignal;
|
|
75
79
|
}): Promise<McpGateway>;
|
|
76
80
|
stop: (options?: RequestOptions) => Promise<{
|
|
77
81
|
stopped: boolean;
|
package/dist/products/mcp.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { pause } from "../wait.js";
|
|
1
2
|
/** `runtime.mcp`: the catalog of MCP servers a sandbox can run. */
|
|
2
3
|
export function mcp(t) {
|
|
3
4
|
return {
|
|
@@ -20,16 +21,36 @@ export function sandboxMcp(t, sandbox) {
|
|
|
20
21
|
start: (servers, input = {}, options) => t.json({ method: "POST", path: path(), body: { servers, ...input }, ...options }),
|
|
21
22
|
/** Their state, and fresh URLs. */
|
|
22
23
|
get: (options) => t.json({ method: "GET", path: path(), ...options }),
|
|
23
|
-
/** Wait until every server is ready (or one failed).
|
|
24
|
+
/** Wait until every server is ready (or one failed). Past `timeoutMs`
|
|
25
|
+
* (default ten minutes), the last state read; a status request still
|
|
26
|
+
* unanswered then is cut off at the deadline, and throws its timeout when
|
|
27
|
+
* no state was read at all. */
|
|
24
28
|
async ready(input = {}) {
|
|
25
|
-
const deadline =
|
|
29
|
+
const deadline = performance.now() + (input.timeoutMs ?? 600_000);
|
|
30
|
+
let last;
|
|
26
31
|
for (;;) {
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const left = Math.ceil(deadline - performance.now());
|
|
33
|
+
if (left <= 0 && last)
|
|
34
|
+
return last;
|
|
35
|
+
try {
|
|
36
|
+
last = await t.json({
|
|
37
|
+
method: "GET",
|
|
38
|
+
path: path(),
|
|
39
|
+
timeoutMs: Math.max(1, left),
|
|
40
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (last && !input.signal?.aborted && error.code === "timeout")
|
|
45
|
+
return last;
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
if (!last.running || last.servers.every((server) => server.status !== "installing"))
|
|
49
|
+
return last;
|
|
50
|
+
const rest = deadline - performance.now();
|
|
51
|
+
if (rest <= 0)
|
|
52
|
+
return last;
|
|
53
|
+
await pause(Math.min(input.intervalMs ?? 2_000, rest), input.signal);
|
|
33
54
|
}
|
|
34
55
|
},
|
|
35
56
|
stop: (options) => t.json({ method: "DELETE", path: path(), ...options }),
|
|
@@ -193,8 +193,15 @@ export type SetUpstreamProxy = {
|
|
|
193
193
|
* `upstreamProxy`: after Runtime's own rules allow a connection, the host
|
|
194
194
|
* reaches it with CONNECT through your proxy, so your proxy's controls and
|
|
195
195
|
* logs apply. A proxy that refuses or cannot be reached fails the connection
|
|
196
|
-
* (upstream-proxy-failed); nothing goes around it.
|
|
196
|
+
* (upstream-proxy-failed); nothing goes around it. Needs a kept top-up. */
|
|
197
197
|
export declare function network(t: Transport): {
|
|
198
|
+
/** Your sandboxes reaching each other by name (`private-network.ts`). */
|
|
199
|
+
private: {
|
|
200
|
+
get: (options?: RequestOptions) => Promise<import("./private-network.js").PrivateNetwork>;
|
|
201
|
+
set: (input: {
|
|
202
|
+
enabled: boolean;
|
|
203
|
+
}, options?: RequestOptions) => Promise<import("./private-network.js").PrivateNetwork>;
|
|
204
|
+
};
|
|
198
205
|
upstreamProxy: {
|
|
199
206
|
/** Send outbound connections through your proxy, replacing any set before. */
|
|
200
207
|
set: (input: SetUpstreamProxy, options?: RequestOptions) => Promise<UpstreamProxy & {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { privateNetwork } from "./private-network.js";
|
|
1
2
|
const enc = encodeURIComponent;
|
|
2
3
|
/** `runtime.domains`: serve a sandbox's port at your own hostname, with HTTPS. */
|
|
3
4
|
export function domains(t) {
|
|
@@ -87,10 +88,12 @@ export function tunnel(t) {
|
|
|
87
88
|
* `upstreamProxy`: after Runtime's own rules allow a connection, the host
|
|
88
89
|
* reaches it with CONNECT through your proxy, so your proxy's controls and
|
|
89
90
|
* logs apply. A proxy that refuses or cannot be reached fails the connection
|
|
90
|
-
* (upstream-proxy-failed); nothing goes around it.
|
|
91
|
+
* (upstream-proxy-failed); nothing goes around it. Needs a kept top-up. */
|
|
91
92
|
export function network(t) {
|
|
92
93
|
const path = "/v1/network/upstream-proxy";
|
|
93
94
|
return {
|
|
95
|
+
/** Your sandboxes reaching each other by name (`private-network.ts`). */
|
|
96
|
+
private: privateNetwork(t),
|
|
94
97
|
upstreamProxy: {
|
|
95
98
|
/** Send outbound connections through your proxy, replacing any set before. */
|
|
96
99
|
set: (input, options) => t.json({
|
|
@@ -35,7 +35,7 @@ export type SandboxMetrics = {
|
|
|
35
35
|
latest: MetricPoint | null;
|
|
36
36
|
points: MetricPoint[];
|
|
37
37
|
};
|
|
38
|
-
export type WebhookEventType = "sandbox.created" | "sandbox.running" | "sandbox.paused" | "sandbox.woken" | "sandbox.stopped" | "sandbox.start_failed" | "sandbox.wake_failed" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted";
|
|
38
|
+
export type WebhookEventType = "sandbox.created" | "sandbox.running" | "sandbox.paused" | "sandbox.woken" | "sandbox.stopped" | "sandbox.start_failed" | "sandbox.wake_failed" | "sandbox.host_unreachable" | "sandbox.host_reachable" | "sandbox.recovered" | "sandbox.recovery_failed" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted";
|
|
39
39
|
/** An event as /v1/events lists it and a webhook delivers it. */
|
|
40
40
|
export type RuntimeEvent = {
|
|
41
41
|
id: string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
export type PrivateNetwork = {
|
|
3
|
+
/** Whether your sandboxes reach each other by name now. */
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
/** `sandbox.internal`. */
|
|
6
|
+
suffix: string;
|
|
7
|
+
/** Whether this account may turn it on: it must have a kept top-up. */
|
|
8
|
+
allowed: boolean;
|
|
9
|
+
/** Why not, when `allowed` is false: `not_paid`, `revoked` or `suspended`. */
|
|
10
|
+
why: string | null;
|
|
11
|
+
enabledAt: string | null;
|
|
12
|
+
disabledAt: string | null;
|
|
13
|
+
};
|
|
14
|
+
export declare function privateNetwork(t: Transport): {
|
|
15
|
+
/** On or off, and whether this account may turn it on. */
|
|
16
|
+
get: (options?: RequestOptions) => Promise<PrivateNetwork>;
|
|
17
|
+
/** `enabled: true` lets your sandboxes reach each other by name; `false`
|
|
18
|
+
* stops it and cuts open connections between them within seconds. */
|
|
19
|
+
set: (input: {
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
}, options?: RequestOptions) => Promise<PrivateNetwork>;
|
|
22
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function privateNetwork(t) {
|
|
2
|
+
const path = "/v1/network/private";
|
|
3
|
+
return {
|
|
4
|
+
/** On or off, and whether this account may turn it on. */
|
|
5
|
+
get: (options) => t.json({ method: "GET", path, ...options }),
|
|
6
|
+
/** `enabled: true` lets your sandboxes reach each other by name; `false`
|
|
7
|
+
* stops it and cuts open connections between them within seconds. */
|
|
8
|
+
set: (input, options) => t.json({ method: "PUT", path, body: input, ...options }),
|
|
9
|
+
};
|
|
10
|
+
}
|