withruntime 0.10.0 → 0.11.0

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.
Files changed (65) hide show
  1. package/DAYTONA.md +40 -34
  2. package/E2B.md +56 -57
  3. package/VERCEL.md +21 -19
  4. package/compatibility-lock.json +8 -84
  5. package/dist/cli.js +73 -2
  6. package/dist/client.d.ts +12 -0
  7. package/dist/client.js +27 -0
  8. package/dist/compat/lease.d.ts +36 -0
  9. package/dist/compat/lease.js +87 -0
  10. package/dist/daytona/computer-use.d.ts +162 -0
  11. package/dist/daytona/computer-use.js +324 -0
  12. package/dist/daytona/context.d.ts +10 -0
  13. package/dist/daytona/context.js +24 -0
  14. package/dist/daytona/daytona.d.ts +20 -0
  15. package/dist/daytona/daytona.js +123 -16
  16. package/dist/daytona/filesystem.js +8 -0
  17. package/dist/daytona/index.d.ts +2 -26
  18. package/dist/daytona/index.js +2 -7
  19. package/dist/daytona/process.d.ts +63 -6
  20. package/dist/daytona/process.js +224 -23
  21. package/dist/daytona/sandbox.d.ts +19 -5
  22. package/dist/daytona/sandbox.js +39 -25
  23. package/dist/e2b/client.d.ts +5 -0
  24. package/dist/e2b/client.js +5 -1
  25. package/dist/e2b/commands.d.ts +15 -6
  26. package/dist/e2b/commands.js +83 -18
  27. package/dist/e2b/errors.d.ts +7 -0
  28. package/dist/e2b/errors.js +20 -0
  29. package/dist/e2b/filesystem.d.ts +2 -1
  30. package/dist/e2b/filesystem.js +43 -6
  31. package/dist/e2b/index.d.ts +2 -2
  32. package/dist/e2b/index.js +1 -1
  33. package/dist/e2b/pty.js +6 -3
  34. package/dist/e2b/sandbox.d.ts +15 -5
  35. package/dist/e2b/sandbox.js +190 -28
  36. package/dist/e2b/users.d.ts +30 -0
  37. package/dist/e2b/users.js +185 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/mcp.d.ts +2 -1
  40. package/dist/mcp.js +6 -1
  41. package/dist/network-cli.js +28 -0
  42. package/dist/products/browser.d.ts +60 -0
  43. package/dist/products/browser.js +37 -0
  44. package/dist/products/desktop.d.ts +2 -2
  45. package/dist/products/desktop.js +2 -2
  46. package/dist/products/images.d.ts +3 -1
  47. package/dist/products/images.js +14 -2
  48. package/dist/products/index.d.ts +2 -0
  49. package/dist/products/index.js +2 -0
  50. package/dist/products/network-products.d.ts +7 -0
  51. package/dist/products/network-products.js +3 -0
  52. package/dist/products/private-network.d.ts +22 -0
  53. package/dist/products/private-network.js +10 -0
  54. package/dist/sandbox.d.ts +22 -0
  55. package/dist/sandbox.js +47 -0
  56. package/dist/transport.d.ts +1 -1
  57. package/dist/transport.js +1 -1
  58. package/dist/types.d.ts +5 -2
  59. package/dist/vercel/index.d.ts +1 -7
  60. package/dist/vercel/index.js +1 -3
  61. package/dist/vercel/sandbox-user.d.ts +70 -0
  62. package/dist/vercel/sandbox-user.js +206 -0
  63. package/dist/vercel/sandbox.d.ts +47 -12
  64. package/dist/vercel/sandbox.js +201 -42
  65. package/package.json +1 -1
@@ -70,6 +70,12 @@ export const NETWORK_HELP = {
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
72
  around it. Paid accounts only.
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. Paid accounts only, and 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 is for paid accounts; add credit to turn it on.";
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,60 @@
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). Starting a running browser returns it as it is. */
38
+ start(input?: BrowserStartOptions, options?: RequestOptions): Promise<{
39
+ running: true;
40
+ headless: boolean;
41
+ /** Chromium's version, e.g. "Chrome/154.0.8037.92". */
42
+ version: string;
43
+ /** The browser's DevTools WebSocket with its private token: give it as it
44
+ * is to Playwright's `chromium.connectOverCDP`, `puppeteer.connect({
45
+ * browserWSEndpoint })`, browser-use or Stagehand. */
46
+ cdpUrl: string;
47
+ /** The DevTools HTTP endpoint; send `headers` with it. */
48
+ httpUrl: string;
49
+ headers: Record<string, string>;
50
+ /** When the token in cdpUrl ends; `get()` returns a fresh one. */
51
+ expiresAt: string | null;
52
+ /** headless: false only: the desktop's live view. */
53
+ streamUrl?: string;
54
+ }>;
55
+ /** Whether it runs, and a fresh cdpUrl when it does. */
56
+ get: (options?: RequestOptions) => Promise<SandboxBrowser>;
57
+ stop: (options?: RequestOptions) => Promise<{
58
+ stopped: boolean;
59
+ }>;
60
+ };
@@ -0,0 +1,37 @@
1
+ /** `sbx.browser`: Chromium in the sandbox, for agents that speak CDP.
2
+ *
3
+ * const { cdpUrl } = await sbx.browser.start();
4
+ * const browser = await chromium.connectOverCDP(cdpUrl);
5
+ *
6
+ * Inside the sandbox the same browser is at http://127.0.0.1:9222. */
7
+ export function sandboxBrowser(t, sandbox) {
8
+ const base = () => `/v1/sandboxes/${encodeURIComponent(sandbox.id)}/browser`;
9
+ return {
10
+ /** Starts Chromium and returns its CDP address. The first start in a
11
+ * sandbox installs Chromium, about a minute; this waits for it (up to 10
12
+ * minutes). Starting a running browser returns it as it is. */
13
+ async start(input = {}, options) {
14
+ const deadline = Date.now() + 600_000;
15
+ for (;;) {
16
+ try {
17
+ return await t.json({
18
+ method: "POST",
19
+ path: `${base()}:start`,
20
+ body: input,
21
+ ...options,
22
+ });
23
+ }
24
+ catch (error) {
25
+ const code = error.code;
26
+ if ((code !== "browser_installing" && code !== "desktop_installing") ||
27
+ Date.now() > deadline)
28
+ throw error;
29
+ await new Promise((resolve) => setTimeout(resolve, error.retryAfterMs ?? 10_000));
30
+ }
31
+ }
32
+ },
33
+ /** Whether it runs, and a fresh cdpUrl when it does. */
34
+ get: (options) => t.json({ method: "GET", path: base(), ...options }),
35
+ stop: (options) => t.json({ method: "POST", path: `${base()}:stop`, ...options }),
36
+ };
37
+ }
@@ -115,8 +115,8 @@ export declare function sandboxDesktop(t: Transport, sandbox: Sandbox): {
115
115
  focus: (windowId: string, options?: RequestOptions) => Promise<{
116
116
  ok: true;
117
117
  }>;
118
- /** Opens `url` in Firefox on the desktop. Right after a sandbox's first
119
- * start, Firefox may still be installing; this waits for it. */
118
+ /** Opens `url` in Chromium on the desktop. Right after a sandbox's first
119
+ * start, Chromium may still be installing; this waits for it. */
120
120
  open(url: string, options?: RequestOptions): Promise<{
121
121
  ok: true;
122
122
  }>;
@@ -50,8 +50,8 @@ export function sandboxDesktop(t, sandbox) {
50
50
  cursor: (options) => act({ action: "cursor" }, options),
51
51
  windows: async (options) => (await act({ action: "windows" }, options)).windows,
52
52
  focus: (windowId, options) => act({ action: "focus", windowId }, options),
53
- /** Opens `url` in Firefox on the desktop. Right after a sandbox's first
54
- * start, Firefox may still be installing; this waits for it. */
53
+ /** Opens `url` in Chromium on the desktop. Right after a sandbox's first
54
+ * start, Chromium may still be installing; this waits for it. */
55
55
  async open(url, options) {
56
56
  const deadline = Date.now() + 600_000;
57
57
  for (;;) {
@@ -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. */
@@ -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(await idOf(ref, options))}:delete`,
208
+ path: `/v1/images/${enc(id)}:delete`,
197
209
  body: {},
198
210
  ...options,
199
211
  });
@@ -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;
@@ -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,
@@ -195,6 +195,13 @@ export type SetUpstreamProxy = {
195
195
  * logs apply. A proxy that refuses or cannot be reached fails the connection
196
196
  * (upstream-proxy-failed); nothing goes around it. Paid accounts only. */
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) {
@@ -91,6 +92,8 @@ export function tunnel(t) {
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({
@@ -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: paid accounts only. */
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
+ }
package/dist/sandbox.d.ts CHANGED
@@ -127,6 +127,21 @@ export declare class Sandbox implements AsyncDisposable {
127
127
  switchImage(image: string, options: RequestOptions & {
128
128
  keep: "workspace";
129
129
  }): Promise<this>;
130
+ /** Gives it more or fewer vCPUs or more or less memory by a restart: its id,
131
+ * whole disk, volumes, environment, name and previews stay, and its
132
+ * programs stop, which `restart: true` says you know (snapshot it first to
133
+ * keep its memory too). A running sandbox is paused, or stopped if it is
134
+ * persistent, and comes back running at the new size on the same server; a
135
+ * paused or stopped one is started. Memory bills on the new size from then.
136
+ * Refused, with nothing changed, when the server has no room
137
+ * (`no_capacity`), above your quota or the trial's 2 vCPU and 4 GiB, or
138
+ * while a snapshot or fork of it is being taken. */
139
+ resize(size: {
140
+ vcpu?: number;
141
+ memoryMiB?: number;
142
+ }, options: RequestOptions & {
143
+ restart: true;
144
+ }): Promise<this>;
130
145
  /** Keeps a running sandbox's lease ahead of now, in the background, until
131
146
  * stop() or the returned function ends it: every `everySeconds` (60) it
132
147
  * extends the lease so that `marginSeconds` (600) remain, never more than
@@ -229,6 +244,13 @@ export declare class Process {
229
244
  info: ProcessInfo;
230
245
  constructor(t: Transport, sandboxId: string, info: ProcessInfo);
231
246
  get id(): string;
247
+ /** The command line as the sandbox reports it. */
248
+ get command(): string;
249
+ /** As of the last answer: spawn, `wait()` or `refresh()`. */
250
+ get state(): ProcessInfo["state"];
251
+ /** null while it runs, and when it was killed or timed out. */
252
+ get exitCode(): number | null;
253
+ toJSON(): ProcessInfo;
232
254
  /** Every output event from the start (or `cursor`) until exit. */
233
255
  output(options?: {
234
256
  cursor?: number;
package/dist/sandbox.js CHANGED
@@ -427,6 +427,27 @@ export class Sandbox {
427
427
  }));
428
428
  return this;
429
429
  }
430
+ /** Gives it more or fewer vCPUs or more or less memory by a restart: its id,
431
+ * whole disk, volumes, environment, name and previews stay, and its
432
+ * programs stop, which `restart: true` says you know (snapshot it first to
433
+ * keep its memory too). A running sandbox is paused, or stopped if it is
434
+ * persistent, and comes back running at the new size on the same server; a
435
+ * paused or stopped one is started. Memory bills on the new size from then.
436
+ * Refused, with nothing changed, when the server has no room
437
+ * (`no_capacity`), above your quota or the trial's 2 vCPU and 4 GiB, or
438
+ * while a snapshot or fork of it is being taken. */
439
+ async resize(size, options) {
440
+ const { restart, ...rest } = options;
441
+ this.#keep(await this.#t.json({
442
+ method: "POST",
443
+ path: `/v1/sandboxes/${enc(this.id)}:resize`,
444
+ body: { ...size, restart },
445
+ // A pause or stop and a cold boot.
446
+ wait: 120,
447
+ ...pick(rest),
448
+ }));
449
+ return this;
450
+ }
430
451
  /** Keeps a running sandbox's lease ahead of now, in the background, until
431
452
  * stop() or the returned function ends it: every `everySeconds` (60) it
432
453
  * extends the lease so that `marginSeconds` (600) remain, never more than
@@ -839,6 +860,26 @@ export class Process {
839
860
  get id() {
840
861
  return this.info.id;
841
862
  }
863
+ /** The command line as the sandbox reports it. */
864
+ get command() {
865
+ return this.info.command;
866
+ }
867
+ /** As of the last answer: spawn, `wait()` or `refresh()`. */
868
+ get state() {
869
+ return this.info.state;
870
+ }
871
+ /** null while it runs, and when it was killed or timed out. */
872
+ get exitCode() {
873
+ return this.info.exitCode;
874
+ }
875
+ toJSON() {
876
+ return this.info;
877
+ }
878
+ /** console.log shows what the process is, not the client inside it. */
879
+ [Symbol.for("nodejs.util.inspect.custom")](_depth, options, show) {
880
+ const { id, sandboxId, command, state, exitCode } = this;
881
+ return `Process ${show({ id, sandboxId, command, state, exitCode }, options)}`;
882
+ }
842
883
  /** Every output event from the start (or `cursor`) until exit. */
843
884
  output(options = {}) {
844
885
  return new Processes(this.t, this.sandboxId).follow(this.id, options);
@@ -884,6 +925,12 @@ export class Process {
884
925
  if (event.type === "exit")
885
926
  exit = event;
886
927
  }
928
+ if (exit)
929
+ this.info = {
930
+ ...this.info,
931
+ state: exit.state,
932
+ exitCode: exit.exitCode,
933
+ };
887
934
  return {
888
935
  exitCode: exit?.exitCode ?? null,
889
936
  ...out,
@@ -1,5 +1,5 @@
1
1
  import { RuntimeError } from "./errors.js";
2
- export declare const VERSION = "0.10.0";
2
+ export declare const VERSION = "0.11.0";
3
3
  export declare const DEFAULT_BASE_URL = "https://api.withruntime.com";
4
4
  /** Runtime's API as code inside a Runtime sandbox reaches it: the sandbox's
5
5
  * own host sends each request on to DEFAULT_BASE_URL over HTTPS. The API runs
package/dist/transport.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ConnectionError, DELIBERATE, errorFor, RuntimeError, WAITS_FOR_ROOM } from "./errors.js";
2
2
  import { describeRoute, envFetch, openWebSocket } from "./proxy.js";
3
- export const VERSION = "0.10.0";
3
+ export const VERSION = "0.11.0";
4
4
  export const DEFAULT_BASE_URL = "https://api.withruntime.com";
5
5
  /** Runtime's API as code inside a Runtime sandbox reaches it: the sandbox's
6
6
  * own host sends each request on to DEFAULT_BASE_URL over HTTPS. The API runs
package/dist/types.d.ts CHANGED
@@ -42,8 +42,9 @@ export type SandboxInfo = {
42
42
  /** The names of its own environment variables (`env`), on a create, an
43
43
  * update and a read of one sandbox. Values are never shown. */
44
44
  envNames?: string[];
45
- /** On a create from an image with a start command: whether it started,
46
- * became ready (readyMs), timed out, or exited first. The create's answer
45
+ /** On a create from an image with a start command: whether it started
46
+ * (and was still running half a second later), became ready (readyMs),
47
+ * timed out, or exited first (exitCode, and stderr's last lines). The create's answer
47
48
  * alone carries it, and the Sandbox that create returned keeps it through
48
49
  * later reads; `sandboxes.get` and `list` have none, because the API keeps
49
50
  * no record of it. */
@@ -52,6 +53,8 @@ export type SandboxInfo = {
52
53
  processId?: string;
53
54
  exitCode?: number | null;
54
55
  readyMs?: number;
56
+ /** With exited: the last lines the start command wrote to stderr. */
57
+ stderr?: string;
55
58
  };
56
59
  /** Present and true when getOrCreate answered a sandbox that already held the name. */
57
60
  reused?: boolean;
@@ -1,6 +1,7 @@
1
1
  export { Sandbox, DEFAULT_TIMEOUT_MS, DEFAULT_VCPUS, MEMORY_MIB_PER_VCPU, networkRules, toRuntimePath, type CreateSandboxParams, type RunCommandParams, type NetworkPolicy, type SandboxRoute, } from "./sandbox.js";
2
2
  export { Command, CommandFinished, type CommandOutput, type LogOutputLine, type Signal, } from "./command.js";
3
3
  export { FileSystem, Stats, Dirent } from "./filesystem.js";
4
+ export { SandboxUser, SandboxUserAlreadyExistsError } from "./sandbox-user.js";
4
5
  export { Snapshot } from "./snapshot.js";
5
6
  export { APIError, StreamError, AuthenticationError, NotSupportedError } from "./errors.js";
6
7
  export type { Credentials, WithRuntime } from "./client.js";
@@ -16,13 +17,6 @@ export declare const Session: {
16
17
  new (...args: unknown[]): never;
17
18
  readonly [key: string]: (...args: unknown[]) => never;
18
19
  };
19
- export declare const SandboxUser: {
20
- (...args: unknown[]): never;
21
- new (...args: unknown[]): never;
22
- readonly [key: string]: (...args: unknown[]) => never;
23
- };
24
- export declare class SandboxUserAlreadyExistsError extends Error {
25
- }
26
20
  export declare const defineSandboxProxy: {
27
21
  (...args: unknown[]): never;
28
22
  new (...args: unknown[]): never;
@@ -9,6 +9,7 @@ import { NotSupportedError } from "./errors.js";
9
9
  export { Sandbox, DEFAULT_TIMEOUT_MS, DEFAULT_VCPUS, MEMORY_MIB_PER_VCPU, networkRules, toRuntimePath, } from "./sandbox.js";
10
10
  export { Command, CommandFinished, } from "./command.js";
11
11
  export { FileSystem, Stats, Dirent } from "./filesystem.js";
12
+ export { SandboxUser, SandboxUserAlreadyExistsError } from "./sandbox-user.js";
12
13
  export { Snapshot } from "./snapshot.js";
13
14
  export { APIError, StreamError, AuthenticationError, NotSupportedError } from "./errors.js";
14
15
  /** Vercel's default region; Runtime runs in one US region. */
@@ -32,7 +33,4 @@ function unsupportedExport(name, alternative) {
32
33
  }
33
34
  export const Drive = unsupportedExport("Drive", "Use a Runtime volume (runtime.volumes) and mount it with withruntime: { create: { volumes: [{ volumeId, path }] } }.");
34
35
  export const Session = unsupportedExport("Session", "A Runtime sandbox is its own session: call the methods on the sandbox.");
35
- export const SandboxUser = unsupportedExport("SandboxUser", "Commands run as the sandbox owner with passwordless sudo; create users with `sudo useradd` in runCommand.");
36
- export class SandboxUserAlreadyExistsError extends Error {
37
- }
38
36
  export const defineSandboxProxy = unsupportedExport("sandbox proxy (defineSandboxProxy)", "Share a port with sandbox.withruntime.previews.create(port) instead.");
@@ -0,0 +1,70 @@
1
+ import type { Command, CommandFinished } from "./command.js";
2
+ import type { RunCommandParams, Sandbox } from "./sandbox.js";
3
+ /** A Linux user or group name Vercel accepts, which is also safe to pass to
4
+ * useradd, groupadd and sudo. */
5
+ export declare function validateName(name: string, kind: string): void;
6
+ /** Thrown when `sandbox.createUser` is called for an existing username. */
7
+ export declare class SandboxUserAlreadyExistsError extends Error {
8
+ readonly username: string;
9
+ constructor(username: string);
10
+ }
11
+ type Signal = {
12
+ signal?: AbortSignal;
13
+ };
14
+ /** A user in a sandbox, made with `sandbox.createUser` or found with
15
+ * `sandbox.asUser`. Commands and file calls run as this user. */
16
+ export declare class SandboxUser {
17
+ #private;
18
+ readonly username: string;
19
+ /** `/root` for root, else `/home/<username>`. */
20
+ readonly homeDir: string;
21
+ /** Use sandbox.createUser or sandbox.asUser. */
22
+ constructor({ sandbox, username }: {
23
+ sandbox: Sandbox;
24
+ username: string;
25
+ });
26
+ /** Runs a command as this user. `sudo: true` runs it as root instead. */
27
+ runCommand(command: string, args?: string[], opts?: {
28
+ signal?: AbortSignal;
29
+ timeoutMs?: number;
30
+ }): Promise<CommandFinished>;
31
+ runCommand(params: RunCommandParams & {
32
+ detached: true;
33
+ }): Promise<Command>;
34
+ runCommand(params: RunCommandParams): Promise<CommandFinished>;
35
+ /** Writes files into this user's home (or absolute paths), then gives them
36
+ * and the directories made for them to this user. */
37
+ writeFiles(files: {
38
+ path: string;
39
+ content: string | Uint8Array;
40
+ mode?: number;
41
+ }[], opts?: Signal): Promise<void>;
42
+ /** The file as this user may read it, as a stream; null when missing. */
43
+ readFile(file: {
44
+ path: string;
45
+ cwd?: string;
46
+ }, opts?: Signal): Promise<NodeJS.ReadableStream | null>;
47
+ /** The file as this user may read it; null when missing. */
48
+ readFileToBuffer(file: {
49
+ path: string;
50
+ cwd?: string;
51
+ }, opts?: Signal): Promise<Buffer | null>;
52
+ /** Copies a file this user may read to the local disk; null when missing. */
53
+ downloadFile(src: {
54
+ path: string;
55
+ cwd?: string;
56
+ }, dst: {
57
+ path: string;
58
+ cwd?: string;
59
+ }, opts?: {
60
+ mkdirRecursive?: boolean;
61
+ signal?: AbortSignal;
62
+ }): Promise<string | null>;
63
+ /** Makes a directory owned by this user. */
64
+ mkDir(path: string, opts?: Signal): Promise<void>;
65
+ addToGroup(groupname: string, opts?: Signal): Promise<void>;
66
+ removeFromGroup(groupname: string, opts?: Signal): Promise<void>;
67
+ }
68
+ /** Runs `cmd args` under sudo; a non-zero exit throws `what(): <stderr>`. */
69
+ export declare function rootOrThrow(sandbox: Sandbox, cmd: string, args: string[], signal: AbortSignal | undefined, what: () => string): Promise<CommandFinished>;
70
+ export {};