withruntime 0.11.0 → 0.11.2

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 (84) hide show
  1. package/BLAXEL.md +8 -9
  2. package/DAYTONA.md +8 -9
  3. package/E2B.md +63 -21
  4. package/README.md +6 -5
  5. package/README.src.md +6 -5
  6. package/VERCEL.md +3 -2
  7. package/compatibility-lock.json +69 -14
  8. package/dist/api-defaults.d.ts +1 -1
  9. package/dist/api-defaults.js +1 -1
  10. package/dist/blaxel/errors.js +4 -4
  11. package/dist/blaxel/lookup.d.ts +2 -1
  12. package/dist/blaxel/lookup.js +2 -1
  13. package/dist/blaxel/sandbox.d.ts +8 -7
  14. package/dist/blaxel/sandbox.js +16 -12
  15. package/dist/cli.d.ts +1 -1
  16. package/dist/cli.js +99 -27
  17. package/dist/client.d.ts +16 -60
  18. package/dist/client.js +14 -103
  19. package/dist/compat/files.js +5 -1
  20. package/dist/compat/lease.d.ts +1 -0
  21. package/dist/compat/lease.js +14 -8
  22. package/dist/credentials.d.ts +9 -0
  23. package/dist/credentials.js +26 -4
  24. package/dist/daytona/daytona.d.ts +1 -2
  25. package/dist/daytona/daytona.js +30 -14
  26. package/dist/daytona/sandbox.d.ts +9 -4
  27. package/dist/daytona/sandbox.js +24 -5
  28. package/dist/e2b/client.d.ts +15 -2
  29. package/dist/e2b/client.js +61 -7
  30. package/dist/e2b/commands.d.ts +3 -0
  31. package/dist/e2b/commands.js +16 -5
  32. package/dist/e2b/errors.d.ts +26 -2
  33. package/dist/e2b/errors.js +38 -5
  34. package/dist/e2b/filesystem.d.ts +1 -1
  35. package/dist/e2b/filesystem.js +82 -16
  36. package/dist/e2b/index.d.ts +2 -2
  37. package/dist/e2b/index.js +2 -2
  38. package/dist/e2b/sandbox.d.ts +25 -12
  39. package/dist/e2b/sandbox.js +196 -165
  40. package/dist/e2b/unsupported.d.ts +19 -0
  41. package/dist/e2b/unsupported.js +21 -0
  42. package/dist/e2b/users.d.ts +9 -0
  43. package/dist/e2b/users.js +22 -0
  44. package/dist/errors.d.ts +10 -4
  45. package/dist/errors.js +18 -10
  46. package/dist/identity.js +2 -1
  47. package/dist/index.d.ts +2 -1
  48. package/dist/index.js +2 -1
  49. package/dist/machine.d.ts +180 -0
  50. package/dist/machine.js +504 -0
  51. package/dist/modal/index.js +6 -2
  52. package/dist/network-cli.js +7 -7
  53. package/dist/openai-agents/index.d.ts +1 -1
  54. package/dist/openai-agents/index.js +1 -1
  55. package/dist/products/browser.d.ts +2 -1
  56. package/dist/products/browser.js +9 -19
  57. package/dist/products/desktop.d.ts +2 -1
  58. package/dist/products/desktop.js +5 -30
  59. package/dist/products/jobs.d.ts +6 -5
  60. package/dist/products/jobs.js +6 -3
  61. package/dist/products/limits.d.ts +4 -10
  62. package/dist/products/mcp.d.ts +5 -1
  63. package/dist/products/mcp.js +29 -8
  64. package/dist/products/network-products.d.ts +1 -1
  65. package/dist/products/network-products.js +1 -1
  66. package/dist/products/network.d.ts +1 -1
  67. package/dist/products/observability.d.ts +1 -1
  68. package/dist/products/private-network.d.ts +1 -1
  69. package/dist/products/secrets.d.ts +3 -3
  70. package/dist/products/switching.d.ts +2 -3
  71. package/dist/runloop/index.js +6 -2
  72. package/dist/sandbox.d.ts +7 -84
  73. package/dist/sandbox.js +58 -345
  74. package/dist/tar.d.ts +2 -0
  75. package/dist/tar.js +74 -16
  76. package/dist/transport.d.ts +36 -8
  77. package/dist/transport.js +174 -37
  78. package/dist/types.d.ts +102 -12
  79. package/dist/vercel/filesystem.js +3 -1
  80. package/dist/vercel/sandbox.d.ts +18 -12
  81. package/dist/vercel/sandbox.js +27 -15
  82. package/dist/wait.d.ts +12 -0
  83. package/dist/wait.js +47 -0
  84. package/package.json +1 -1
@@ -119,7 +119,9 @@ export class FileSystem {
119
119
  const result = await this.#call(syscall, path, () => this.#ctx.run(argv, options));
120
120
  if (result.exitCode === 0)
121
121
  return result.stdout;
122
- if (/No such file or directory/.test(result.stderr))
122
+ // dash, the sh of Debian and Ubuntu (a Runtime sandbox's), says "cannot
123
+ // create ...: Directory nonexistent" for a missing parent.
124
+ if (/No such file or directory|Directory nonexistent/.test(result.stderr))
123
125
  throw fsError("ENOENT", syscall, path);
124
126
  if (syscall === "unlink" || syscall === "rm")
125
127
  throw fsError("EACCES", syscall, path);
@@ -9,7 +9,9 @@ import { Snapshot } from "./snapshot.js";
9
9
  * 2026). Runtime gives 2 vCPU and 4096 MiB. */
10
10
  export declare const DEFAULT_VCPUS = 2;
11
11
  export declare const MEMORY_MIB_PER_VCPU = 2048;
12
- /** Vercel's default timeout, 5 minutes. */
12
+ /** Vercel's default timeout, 5 minutes. Not sent: a sandbox created with no
13
+ * timeout has no time limit on Runtime, running while it works and pausing
14
+ * when idle (0300). Kept for code that imports it. */
13
15
  export declare const DEFAULT_TIMEOUT_MS = 300000;
14
16
  /** Vercel's working directory; `/workspace` on Runtime. */
15
17
  export declare const HOME = "/vercel/sandbox";
@@ -40,9 +42,10 @@ export interface CreateSandboxParams extends Credentials {
40
42
  /** Shared at public HTTPS addresses (Runtime previews); `domain(port)`
41
43
  * answers from them. */
42
44
  ports?: number[];
43
- /** Milliseconds. Default 300 000, at least 60 s. Over an hour, the
44
- * sandbox's hour-long lease is extended while this object lives, up to the
45
- * timeout (`sandbox.timeout`). */
45
+ /** Milliseconds, at least 60 s: when it stops. Leave it out for no time
46
+ * limit: it runs while it works and pauses when idle. Over an hour, the
47
+ * hour-long limit is extended while this object lives, up to the timeout
48
+ * (`sandbox.timeout`). */
46
49
  timeout?: number;
47
50
  resources?: {
48
51
  vcpus: number;
@@ -135,15 +138,16 @@ export declare class Sandbox {
135
138
  get cwd(): string;
136
139
  get status(): "pending" | "running" | "stopping" | "stopped";
137
140
  /** Milliseconds from the start of the session: the timeout given at
138
- * create, with every extension, or the lease of a sandbox found by name. */
141
+ * create, with every extension, or the time limit of a sandbox found by
142
+ * name. 0 for one with no time limit, which runs while it works. */
139
143
  get timeout(): number;
140
144
  get expiresAt(): Date;
141
145
  get tags(): Record<string, string>;
142
146
  get sourceSnapshotId(): string | undefined;
143
147
  /** Creates a sandbox and waits until it runs. Vercel's defaults: 2 vCPUs,
144
- * 2048 MiB per vCPU, a 5-minute timeout, persistent. Funding is left to
145
- * Runtime: the free trial while the account has trial time, then prepaid
146
- * credit, exactly as withruntime's own create. */
148
+ * 2048 MiB per vCPU, persistent. With no `timeout` it has no time limit: it
149
+ * runs while it works and pauses when idle. A `timeout` is kept as given. Funding is left to
150
+ * Runtime: the included usage first, then prepaid credit, exactly as withruntime's own create. */
147
151
  static create(params?: CreateSandboxParams): Promise<Sandbox & AsyncDisposable>;
148
152
  /** A sandbox by name (or Runtime id), woken if it is paused unless
149
153
  * `resume: false`. */
@@ -269,9 +273,10 @@ export declare class Sandbox {
269
273
  signal?: AbortSignal;
270
274
  }): Promise<void>;
271
275
  [Symbol.asyncDispose](): Promise<void>;
272
- /** Moves the end `duration` milliseconds later. The lease moves at once
273
- * as far as it may (an hour ahead of now); past that it is extended while
274
- * this object lives. */
276
+ /** Moves the end `duration` milliseconds later. The time limit moves at
277
+ * once as far as it may (an hour ahead of now); past that it is extended
278
+ * while this object lives. A sandbox with no time limit has no end to
279
+ * move, and nothing changes. */
275
280
  extendTimeout(duration: number, opts?: {
276
281
  signal?: AbortSignal;
277
282
  }): Promise<void>;
@@ -281,7 +286,8 @@ export declare class Sandbox {
281
286
  }): Promise<NetworkPolicy>;
282
287
  /** Changes what Runtime can change on a sandbox: `timeout`, `ports`,
283
288
  * `networkPolicy` and `snapshotExpiration`. Anything else is refused before
284
- * anything changes. */
289
+ * anything changes. A `timeout` on a sandbox with no time limit changes
290
+ * nothing: it runs while it works. */
285
291
  update(params: {
286
292
  timeout?: number;
287
293
  ports?: number[];
@@ -13,7 +13,9 @@ import { Snapshot } from "./snapshot.js";
13
13
  * 2026). Runtime gives 2 vCPU and 4096 MiB. */
14
14
  export const DEFAULT_VCPUS = 2;
15
15
  export const MEMORY_MIB_PER_VCPU = 2048;
16
- /** Vercel's default timeout, 5 minutes. */
16
+ /** Vercel's default timeout, 5 minutes. Not sent: a sandbox created with no
17
+ * timeout has no time limit on Runtime, running while it works and pausing
18
+ * when idle (0300). Kept for code that imports it. */
17
19
  export const DEFAULT_TIMEOUT_MS = 300_000;
18
20
  const MIN_LEASE_SECONDS = 60;
19
21
  /** Extend a long timeout's lease when less than this is left. */
@@ -235,7 +237,8 @@ export class Sandbox {
235
237
  return statusOf(this.#rt.state);
236
238
  }
237
239
  /** Milliseconds from the start of the session: the timeout given at
238
- * create, with every extension, or the lease of a sandbox found by name. */
240
+ * create, with every extension, or the time limit of a sandbox found by
241
+ * name. 0 for one with no time limit, which runs while it works. */
239
242
  get timeout() {
240
243
  return this.#timeoutMs ?? this.#rt.info.timeoutSeconds * 1000;
241
244
  }
@@ -255,9 +258,9 @@ export class Sandbox {
255
258
  }
256
259
  // ---- create, get, list ------------------------------------------------
257
260
  /** Creates a sandbox and waits until it runs. Vercel's defaults: 2 vCPUs,
258
- * 2048 MiB per vCPU, a 5-minute timeout, persistent. Funding is left to
259
- * Runtime: the free trial while the account has trial time, then prepaid
260
- * credit, exactly as withruntime's own create. */
261
+ * 2048 MiB per vCPU, persistent. With no `timeout` it has no time limit: it
262
+ * runs while it works and pauses when idle. A `timeout` is kept as given. Funding is left to
263
+ * Runtime: the included usage first, then prepaid credit, exactly as withruntime's own create. */
261
264
  static async create(params = {}) {
262
265
  refuseCreate(params);
263
266
  const client = clientFor(params);
@@ -268,7 +271,8 @@ export class Sandbox {
268
271
  const source = await guard(() => resolveImage(client, params));
269
272
  const input = {
270
273
  ...(source.snapshot ? {} : { vcpu: vcpus, memoryMiB: vcpus * MEMORY_MIB_PER_VCPU }),
271
- timeoutSeconds: leaseSeconds(params.timeout ?? DEFAULT_TIMEOUT_MS),
274
+ // No timeout, no time limit: it runs while it works (0300).
275
+ ...(params.timeout === undefined ? {} : { timeoutSeconds: leaseSeconds(params.timeout) }),
272
276
  onLeaseEnd: persistent ? "pause" : "stop",
273
277
  ...(params.name ? { name: params.name } : {}),
274
278
  ...(params.tags && Object.keys(params.tags).length ? { labels: params.tags } : {}),
@@ -280,7 +284,7 @@ export class Sandbox {
280
284
  const sandbox = new Sandbox({
281
285
  runtime,
282
286
  client,
283
- params: { ...params, persistent, timeout: params.timeout ?? DEFAULT_TIMEOUT_MS },
287
+ params: { ...params, persistent },
284
288
  });
285
289
  try {
286
290
  await sandbox.#setUp(params);
@@ -643,20 +647,25 @@ export class Sandbox {
643
647
  return;
644
648
  await this.stop().catch(() => undefined);
645
649
  }
646
- /** Moves the end `duration` milliseconds later. The lease moves at once
647
- * as far as it may (an hour ahead of now); past that it is extended while
648
- * this object lives. */
650
+ /** Moves the end `duration` milliseconds later. The time limit moves at
651
+ * once as far as it may (an hour ahead of now); past that it is extended
652
+ * while this object lives. A sandbox with no time limit has no end to
653
+ * move, and nothing changes. */
649
654
  async extendTimeout(duration, opts = {}) {
650
655
  if (!Number.isFinite(duration) || duration <= 0)
651
656
  throw new RangeError(`duration must be a positive number of milliseconds, not ${duration}.`);
652
657
  await this.#withResume(async (runtime) => {
658
+ if (runtime.info.endsAt === null)
659
+ return;
653
660
  this.#timeoutMs = this.timeout + duration;
654
661
  await this.#leaseToTimeout(runtime, opts);
655
662
  }, opts);
656
663
  }
657
664
  /** Extends the lease now toward the timeout, an hour ahead at most. */
658
665
  async #leaseToTimeout(runtime, opts) {
659
- const seconds = extensionSeconds(Date.parse(runtime.info.expiresAt), this.#until(), Date.now(), Infinity);
666
+ if (runtime.info.endsAt === null)
667
+ return;
668
+ const seconds = extensionSeconds(Date.parse(runtime.info.endsAt ?? runtime.info.expiresAt), this.#until(), Date.now(), Infinity);
660
669
  if (seconds >= 1)
661
670
  await runtime.extend(seconds, signalOf(opts));
662
671
  }
@@ -669,7 +678,8 @@ export class Sandbox {
669
678
  }
670
679
  /** Changes what Runtime can change on a sandbox: `timeout`, `ports`,
671
680
  * `networkPolicy` and `snapshotExpiration`. Anything else is refused before
672
- * anything changes. */
681
+ * anything changes. A `timeout` on a sandbox with no time limit changes
682
+ * nothing: it runs while it works. */
673
683
  async update(params, opts = {}) {
674
684
  opts.signal?.throwIfAborted();
675
685
  const allowed = new Set(["timeout", "ports", "networkPolicy", "snapshotExpiration"]);
@@ -683,13 +693,15 @@ export class Sandbox {
683
693
  if (params.ports !== undefined)
684
694
  validatePorts(params.ports);
685
695
  const wanted = params.ports === undefined ? undefined : new Set(params.ports);
686
- if (params.timeout !== undefined) {
696
+ // A sandbox with no time limit has none to change (0300).
697
+ if (params.timeout !== undefined && this.#rt.info.endsAt !== null) {
687
698
  const timeout = checkTimeout(params.timeout);
688
699
  // A shorter timeout is kept when the lease has not reached it yet: the
689
700
  // lease then stops being extended there. Runtime cannot end a lease
690
701
  // earlier than it was given.
691
- if (this.#sessionStart + timeout < Date.parse(this.#rt.info.expiresAt) - 1000)
692
- throw new NotSupportedError("A timeout that ends earlier than the current lease", `The lease runs to ${this.#rt.info.expiresAt}; call stop() when the work is done, or pass a timeout that ends after it.`);
702
+ const end = this.#rt.info.endsAt ?? this.#rt.info.expiresAt;
703
+ if (this.#sessionStart + timeout < Date.parse(end) - 1000)
704
+ throw new NotSupportedError("A timeout that ends earlier than the current lease", `The lease runs to ${end}; call stop() when the work is done, or pass a timeout that ends after it.`);
693
705
  const longer = timeout > this.timeout;
694
706
  this.#timeoutMs = timeout;
695
707
  if (longer)
package/dist/wait.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { RequestOptions } from "./transport.js";
2
+ /** A wait that an abort ends at once, rejecting with the signal's reason. */
3
+ export declare function pause(ms: number, signal?: AbortSignal): Promise<void>;
4
+ export declare function abortError(signal: AbortSignal): Error;
5
+ /**
6
+ * Calls `attempt` until it stops answering one of `codes` (something is
7
+ * still installing), within one budget: the caller's `timeoutMs`, else ten
8
+ * minutes. Each try gets what is left of it; a wait between tries ends at once
9
+ * on abort, and no try starts once the budget cannot cover the wait the API
10
+ * asked for: the installing error is thrown instead.
11
+ */
12
+ export declare function whileInstalling<T>(codes: readonly string[], options: RequestOptions | undefined, attempt: (options: RequestOptions) => Promise<T>): Promise<T>;
package/dist/wait.js ADDED
@@ -0,0 +1,47 @@
1
+ /** A wait that an abort ends at once, rejecting with the signal's reason. */
2
+ export function pause(ms, signal) {
3
+ return new Promise((resolve, reject) => {
4
+ if (signal?.aborted)
5
+ return reject(abortError(signal));
6
+ const timer = setTimeout(() => {
7
+ signal?.removeEventListener("abort", stop);
8
+ resolve();
9
+ }, ms);
10
+ function stop() {
11
+ clearTimeout(timer);
12
+ reject(abortError(signal));
13
+ }
14
+ signal?.addEventListener("abort", stop, { once: true });
15
+ });
16
+ }
17
+ export function abortError(signal) {
18
+ return signal.reason instanceof Error ? signal.reason : new Error("Aborted");
19
+ }
20
+ /** How long a start waits for a first install (Chromium, the desktop) when
21
+ * the caller sets no deadline. */
22
+ const INSTALL_WAIT_MS = 600_000;
23
+ /**
24
+ * Calls `attempt` until it stops answering one of `codes` (something is
25
+ * still installing), within one budget: the caller's `timeoutMs`, else ten
26
+ * minutes. Each try gets what is left of it; a wait between tries ends at once
27
+ * on abort, and no try starts once the budget cannot cover the wait the API
28
+ * asked for: the installing error is thrown instead.
29
+ */
30
+ export async function whileInstalling(codes, options, attempt) {
31
+ const deadline = performance.now() + (options?.timeoutMs || INSTALL_WAIT_MS);
32
+ for (;;) {
33
+ if (options?.signal?.aborted)
34
+ throw abortError(options.signal);
35
+ const left = Math.max(1, Math.ceil(deadline - performance.now()));
36
+ try {
37
+ return await attempt(options?.timeoutMs ? { ...options, timeoutMs: left } : { ...options });
38
+ }
39
+ catch (error) {
40
+ const code = error.code;
41
+ const wait = error.retryAfterMs ?? 10_000;
42
+ if (!code || !codes.includes(code) || performance.now() + wait > deadline)
43
+ throw error;
44
+ await pause(wait, options?.signal);
45
+ }
46
+ }
47
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "withruntime",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "license": "Apache-2.0",
5
5
  "mcpName": "com.withruntime/runtime",
6
6
  "type": "module",