withruntime 0.11.1 → 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.
- package/BLAXEL.md +1 -1
- package/DAYTONA.md +1 -1
- package/E2B.md +57 -29
- package/README.md +4 -3
- package/README.src.md +4 -3
- package/compatibility-lock.json +14 -14
- package/dist/blaxel/errors.js +4 -4
- package/dist/blaxel/sandbox.d.ts +1 -2
- package/dist/blaxel/sandbox.js +1 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +63 -15
- package/dist/client.d.ts +11 -59
- package/dist/client.js +8 -113
- package/dist/daytona/daytona.d.ts +1 -2
- package/dist/daytona/daytona.js +1 -2
- package/dist/daytona/sandbox.d.ts +1 -1
- package/dist/daytona/sandbox.js +1 -1
- package/dist/e2b/client.d.ts +15 -2
- package/dist/e2b/client.js +61 -7
- package/dist/e2b/commands.d.ts +3 -0
- package/dist/e2b/commands.js +16 -5
- package/dist/e2b/errors.d.ts +26 -2
- package/dist/e2b/errors.js +38 -5
- package/dist/e2b/filesystem.d.ts +1 -1
- package/dist/e2b/filesystem.js +82 -16
- package/dist/e2b/index.d.ts +2 -2
- package/dist/e2b/index.js +2 -2
- package/dist/e2b/sandbox.d.ts +23 -14
- package/dist/e2b/sandbox.js +195 -178
- package/dist/e2b/unsupported.d.ts +19 -0
- package/dist/e2b/unsupported.js +21 -0
- package/dist/e2b/users.d.ts +9 -0
- package/dist/e2b/users.js +22 -0
- package/dist/errors.d.ts +4 -4
- package/dist/errors.js +12 -10
- package/dist/machine.d.ts +180 -0
- package/dist/machine.js +504 -0
- package/dist/openai-agents/index.d.ts +1 -1
- package/dist/openai-agents/index.js +1 -1
- package/dist/products/jobs.d.ts +2 -3
- package/dist/products/jobs.js +1 -2
- package/dist/products/limits.d.ts +4 -10
- package/dist/products/network.d.ts +1 -1
- package/dist/products/secrets.d.ts +1 -1
- package/dist/products/switching.d.ts +2 -3
- package/dist/sandbox.d.ts +7 -92
- package/dist/sandbox.js +8 -362
- package/dist/transport.d.ts +4 -2
- package/dist/transport.js +6 -4
- package/dist/types.d.ts +53 -8
- package/dist/vercel/sandbox.d.ts +1 -2
- package/dist/vercel/sandbox.js +1 -2
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { RuntimeError } from "./errors.js";
|
|
2
|
-
import type { Page } from "./page.js";
|
|
3
1
|
import { type ClientExtensions } from "./products/index.js";
|
|
4
2
|
import { usageExport as makeUsageExport } from "./products/observability.js";
|
|
3
|
+
import { Machines } from "./machine.js";
|
|
5
4
|
import { Sandbox } from "./sandbox.js";
|
|
6
5
|
import { Snapshots } from "./snapshots.js";
|
|
7
6
|
import { Transport, type RequestOptions } from "./transport.js";
|
|
8
7
|
import type { CreateSandbox, DeletedSandbox, FeedbackKind, SandboxInfo, Usage } from "./types.js";
|
|
8
|
+
export type { CreateOptions } from "./machine.js";
|
|
9
9
|
export type RuntimeOptions = {
|
|
10
10
|
/** Default: the RUNTIME_API_KEY environment variable. */
|
|
11
11
|
apiKey?: string;
|
|
@@ -22,9 +22,12 @@ export type RuntimeOptions = {
|
|
|
22
22
|
* before it has used a valid key. 8 are kept for calls whatever the
|
|
23
23
|
* streams hold. */
|
|
24
24
|
maxConnections?: number;
|
|
25
|
+
/** Called each time a call has to wait for one of those connections: an
|
|
26
|
+
* adapter warns with it, once, that its caller is being held back. */
|
|
27
|
+
onQueued?: (maxConnections: number) => void;
|
|
25
28
|
/** How long `sandboxes.create` keeps retrying, with the same key and input,
|
|
26
|
-
* when the
|
|
27
|
-
* (
|
|
29
|
+
* when the slots without credit, the account's quota or the region is full
|
|
30
|
+
* (no_credit_running_limit, quota_exceeded, no_capacity and the like). Default 120 000
|
|
28
31
|
* (two minutes); 0 fails at once. The refusal is thrown as it came when the
|
|
29
32
|
* wait runs out. */
|
|
30
33
|
waitForCapacityMs?: number;
|
|
@@ -57,8 +60,8 @@ export declare class Runtime {
|
|
|
57
60
|
/** The role of the member who made this key: owner, admin, developer or billing. */
|
|
58
61
|
role?: string | null;
|
|
59
62
|
}>;
|
|
60
|
-
/** Balance, holds,
|
|
61
|
-
/** Credit, holds,
|
|
63
|
+
/** Balance, holds, free time and per-resource charges, in integer microdollars. */
|
|
64
|
+
/** Credit, holds, free time and per-resource charges. */
|
|
62
65
|
usage(options?: RequestOptions): Promise<Usage>;
|
|
63
66
|
/** This account's authenticated API answers, in hourly windows. Counts are
|
|
64
67
|
* exact decimal strings, and an empty window has a null error percentage.
|
|
@@ -80,60 +83,9 @@ export declare class Runtime {
|
|
|
80
83
|
}>;
|
|
81
84
|
}>;
|
|
82
85
|
}
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
export type CreateOptions = RequestOptions & {
|
|
86
|
-
/** How long to keep retrying a refusal that clears by itself. Default: the
|
|
87
|
-
* client's, two minutes; 0 fails at once. */
|
|
88
|
-
waitForCapacityMs?: number;
|
|
89
|
-
/** Called before each wait, with the refusal and the milliseconds until the
|
|
90
|
-
* next try: to tell a person why nothing has happened yet. */
|
|
91
|
-
onCapacityWait?: (refusal: RuntimeError, waitMs: number) => void;
|
|
92
|
-
};
|
|
93
|
-
export declare class Sandboxes {
|
|
94
|
-
private readonly t;
|
|
86
|
+
/** `runtime.sandboxes`: the sandbox product of the machine engine. */
|
|
87
|
+
export declare class Sandboxes extends Machines<Sandbox, SandboxInfo, CreateSandbox, DeletedSandbox> {
|
|
95
88
|
constructor(t: Transport);
|
|
96
|
-
/** Creates a sandbox and waits until it is running. Every field is optional:
|
|
97
|
-
* with none you get the free trial while it lasts, the default region and a
|
|
98
|
-
* 2 vCPU / 4 GiB machine from a warm template. `wait: false` returns at once.
|
|
99
|
-
* When every trial slot or the account's quota is taken, it waits for one to
|
|
100
|
-
* free, up to `waitForCapacityMs` (the client's, two minutes by default). */
|
|
101
|
-
create(input?: CreateSandbox & {
|
|
102
|
-
wait?: boolean;
|
|
103
|
-
}, options?: CreateOptions): Promise<Sandbox>;
|
|
104
|
-
/** The sandbox named `name` in this account, ready to use: running as it
|
|
105
|
-
* is, woken if it is paused, restarted if it is stopped and persistent, or
|
|
106
|
-
* created with `input` when no sandbox has the name. `sandbox.info.reused`
|
|
107
|
-
* says which. The other fields apply only when it is created. */
|
|
108
|
-
getOrCreate(name: string, input?: Omit<CreateSandbox, "name" | "getOrCreate"> & {
|
|
109
|
-
wait?: boolean;
|
|
110
|
-
}, options?: CreateOptions): Promise<Sandbox>;
|
|
111
|
-
get(id: string, options?: RequestOptions): Promise<Sandbox>;
|
|
112
|
-
/** Deletes a sandbox for good, by id, without reading it first: see
|
|
113
|
-
* `sandbox.delete()`. Deleting it again answers the same. */
|
|
114
|
-
delete(id: string, options?: RequestOptions): Promise<DeletedSandbox>;
|
|
115
|
-
/** Live sandboxes, oldest first. Await for a page, or `for await` over all.
|
|
116
|
-
* Request options apply to the initial request and every subsequent page. */
|
|
117
|
-
list(filter?: {
|
|
118
|
-
state?: SandboxInfo["state"][];
|
|
119
|
-
includeStopped?: boolean;
|
|
120
|
-
/** Every label must match. */
|
|
121
|
-
labels?: Record<string, string>;
|
|
122
|
-
name?: string;
|
|
123
|
-
limit?: number;
|
|
124
|
-
}, options?: RequestOptions): Promise<Page<Sandbox>>;
|
|
125
|
-
/** Stops every live sandbox whose labels all match, eight at a time, and
|
|
126
|
-
* says which stopped and which failed; one failure does not stop the rest.
|
|
127
|
-
* Needs at least one label, so stopping everything is never one call. */
|
|
128
|
-
stopAll(filter: {
|
|
129
|
-
labels: Record<string, string>;
|
|
130
|
-
}, options?: RequestOptions): Promise<{
|
|
131
|
-
stopped: string[];
|
|
132
|
-
failed: {
|
|
133
|
-
id: string;
|
|
134
|
-
error: unknown;
|
|
135
|
-
}[];
|
|
136
|
-
}>;
|
|
137
89
|
}
|
|
138
90
|
export declare class FeedbackApi {
|
|
139
91
|
private readonly t;
|
package/dist/client.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { WAIT_FOR_TIMEOUT_SECONDS } from "./api-defaults.js";
|
|
2
|
-
import { RuntimeError } from "./errors.js";
|
|
3
1
|
import { clientFactories, clientProductAliases } from "./products/index.js";
|
|
4
2
|
import { usageExport as makeUsageExport } from "./products/observability.js";
|
|
5
|
-
import {
|
|
3
|
+
import { Machines } from "./machine.js";
|
|
4
|
+
import { SANDBOXES, Sandbox } from "./sandbox.js";
|
|
6
5
|
import { Snapshots } from "./snapshots.js";
|
|
7
6
|
import { DEFAULT_BASE_URL, Transport, missingKey } from "./transport.js";
|
|
8
7
|
/** The key `runtime login` saved for this machine and this API origin, found
|
|
@@ -43,6 +42,7 @@ export class Runtime {
|
|
|
43
42
|
...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
|
44
43
|
...(options.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}),
|
|
45
44
|
...(options.maxConnections !== undefined ? { maxConnections: options.maxConnections } : {}),
|
|
45
|
+
...(options.onQueued ? { onQueued: options.onQueued } : {}),
|
|
46
46
|
...(options.waitForCapacityMs !== undefined
|
|
47
47
|
? { waitForCapacityMs: options.waitForCapacityMs }
|
|
48
48
|
: {}),
|
|
@@ -68,8 +68,8 @@ export class Runtime {
|
|
|
68
68
|
...options,
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
-
/** Balance, holds,
|
|
72
|
-
/** Credit, holds,
|
|
71
|
+
/** Balance, holds, free time and per-resource charges, in integer microdollars. */
|
|
72
|
+
/** Credit, holds, free time and per-resource charges. */
|
|
73
73
|
usage(options = {}) {
|
|
74
74
|
return this.transport.json({
|
|
75
75
|
method: "GET",
|
|
@@ -89,115 +89,10 @@ export class Runtime {
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
/** `runtime.sandboxes`: the sandbox product of the machine engine. */
|
|
93
|
+
export class Sandboxes extends Machines {
|
|
94
94
|
constructor(t) {
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
/** Creates a sandbox and waits until it is running. Every field is optional:
|
|
98
|
-
* with none you get the free trial while it lasts, the default region and a
|
|
99
|
-
* 2 vCPU / 4 GiB machine from a warm template. `wait: false` returns at once.
|
|
100
|
-
* When every trial slot or the account's quota is taken, it waits for one to
|
|
101
|
-
* free, up to `waitForCapacityMs` (the client's, two minutes by default). */
|
|
102
|
-
async create(input = {}, options = {}) {
|
|
103
|
-
const { wait, ...body } = input;
|
|
104
|
-
const began = performance.now();
|
|
105
|
-
// Time spent waiting for capacity is the room's, not the deadline's.
|
|
106
|
-
let waited = 0;
|
|
107
|
-
const info = await this.t.json({
|
|
108
|
-
method: "POST",
|
|
109
|
-
path: "/v1/sandboxes",
|
|
110
|
-
body,
|
|
111
|
-
wait: wait === false ? 0 : 60,
|
|
112
|
-
...options,
|
|
113
|
-
waitForCapacityMs: options.waitForCapacityMs ?? this.t.waitForCapacityMs,
|
|
114
|
-
onCapacityWait: (refusal, waitMs) => {
|
|
115
|
-
waited += waitMs;
|
|
116
|
-
options.onCapacityWait?.(refusal, waitMs);
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
const sandbox = new Sandbox(this.t, info);
|
|
120
|
-
if (wait !== false && info.state !== "running") {
|
|
121
|
-
// One deadline for the whole create: the wait for running gets what the
|
|
122
|
-
// create left of it (1 ms when nothing is left, so it ends as a timeout).
|
|
123
|
-
const { timeoutMs } = options;
|
|
124
|
-
await sandbox.waitFor("running", {
|
|
125
|
-
timeoutSeconds: WAIT_FOR_TIMEOUT_SECONDS,
|
|
126
|
-
signal: options.signal,
|
|
127
|
-
timeoutMs: timeoutMs
|
|
128
|
-
? Math.max(1, Math.ceil(timeoutMs - (performance.now() - began - waited)))
|
|
129
|
-
: timeoutMs,
|
|
130
|
-
idempotencyKey: options.idempotencyKey,
|
|
131
|
-
});
|
|
132
|
-
if (sandbox.state !== "running")
|
|
133
|
-
throw new RuntimeError({
|
|
134
|
-
message: `Sandbox ${info.id} is ${sandbox.state}, not running.`,
|
|
135
|
-
code: "start_failed",
|
|
136
|
-
status: 0,
|
|
137
|
-
hint: "Read it with runtime.sandboxes.get(id); stopReason says why.",
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
return sandbox;
|
|
141
|
-
}
|
|
142
|
-
/** The sandbox named `name` in this account, ready to use: running as it
|
|
143
|
-
* is, woken if it is paused, restarted if it is stopped and persistent, or
|
|
144
|
-
* created with `input` when no sandbox has the name. `sandbox.info.reused`
|
|
145
|
-
* says which. The other fields apply only when it is created. */
|
|
146
|
-
async getOrCreate(name, input = {}, options = {}) {
|
|
147
|
-
return this.create({ ...input, name, getOrCreate: true }, options);
|
|
148
|
-
}
|
|
149
|
-
async get(id, options = {}) {
|
|
150
|
-
return new Sandbox(this.t, await this.t.json({
|
|
151
|
-
method: "GET",
|
|
152
|
-
path: `/v1/sandboxes/${encodeURIComponent(id)}`,
|
|
153
|
-
...options,
|
|
154
|
-
}));
|
|
155
|
-
}
|
|
156
|
-
/** Deletes a sandbox for good, by id, without reading it first: see
|
|
157
|
-
* `sandbox.delete()`. Deleting it again answers the same. */
|
|
158
|
-
delete(id, options = {}) {
|
|
159
|
-
return deleteSandbox(this.t, id, options);
|
|
160
|
-
}
|
|
161
|
-
/** Live sandboxes, oldest first. Await for a page, or `for await` over all.
|
|
162
|
-
* Request options apply to the initial request and every subsequent page. */
|
|
163
|
-
async list(filter = {}, options = {}) {
|
|
164
|
-
const query = {
|
|
165
|
-
...(filter.state ? { state: filter.state } : {}),
|
|
166
|
-
...(filter.includeStopped ? { includeStopped: true } : {}),
|
|
167
|
-
...(filter.labels
|
|
168
|
-
? { label: Object.entries(filter.labels).map(([k, v]) => `${k}:${v}`) }
|
|
169
|
-
: {}),
|
|
170
|
-
...(filter.name ? { name: filter.name } : {}),
|
|
171
|
-
...(filter.limit ? { limit: filter.limit } : {}),
|
|
172
|
-
};
|
|
173
|
-
return sandboxPage(this.t, await this.t.json({ method: "GET", path: "/v1/sandboxes", query, ...options }), query, options);
|
|
174
|
-
}
|
|
175
|
-
/** Stops every live sandbox whose labels all match, eight at a time, and
|
|
176
|
-
* says which stopped and which failed; one failure does not stop the rest.
|
|
177
|
-
* Needs at least one label, so stopping everything is never one call. */
|
|
178
|
-
async stopAll(filter, options = {}) {
|
|
179
|
-
if (!filter?.labels || Object.keys(filter.labels).length === 0)
|
|
180
|
-
throw new RuntimeError({
|
|
181
|
-
message: "stopAll needs at least one label to match.",
|
|
182
|
-
code: "invalid_request",
|
|
183
|
-
status: 0,
|
|
184
|
-
hint: "Stop one sandbox with sandbox.stop(), or label the ones to stop together.",
|
|
185
|
-
});
|
|
186
|
-
const live = await (await this.list({ labels: filter.labels, limit: 100 }, options)).toArray(Infinity);
|
|
187
|
-
// One key cannot name several stops: each stop makes its own.
|
|
188
|
-
const { idempotencyKey: _one, ...each } = options;
|
|
189
|
-
// In list order, oldest first, whichever finishes first.
|
|
190
|
-
const errors = new Array(live.length);
|
|
191
|
-
let next = 0;
|
|
192
|
-
const worker = async () => {
|
|
193
|
-
for (let at = next++; at < live.length; at = next++)
|
|
194
|
-
await live[at].stop(each).catch((error) => (errors[at] = error ?? "failed"));
|
|
195
|
-
};
|
|
196
|
-
await Promise.all(Array.from({ length: Math.min(8, live.length) }, worker));
|
|
197
|
-
return {
|
|
198
|
-
stopped: live.filter((_, at) => errors[at] === undefined).map((sbx) => sbx.id),
|
|
199
|
-
failed: live.flatMap((sbx, at) => errors[at] === undefined ? [] : [{ id: sbx.id, error: errors[at] }]),
|
|
200
|
-
};
|
|
95
|
+
super(SANDBOXES, t, (transport, info) => new Sandbox(transport, info));
|
|
201
96
|
}
|
|
202
97
|
}
|
|
203
98
|
export class FeedbackApi {
|
|
@@ -177,8 +177,7 @@ export declare class Daytona implements AsyncDisposable {
|
|
|
177
177
|
[Symbol.asyncDispose](): Promise<void>;
|
|
178
178
|
/** Creates a sandbox and waits until it runs, with Daytona's defaults: 1
|
|
179
179
|
* vCPU, 1 GiB, 3 GiB disk, pausing after 15 minutes without calls. Funding
|
|
180
|
-
* is left to Runtime: the
|
|
181
|
-
* prepaid credit, exactly as withruntime's own create. */
|
|
180
|
+
* is left to Runtime: the included usage first, then prepaid credit, exactly as withruntime's own create. */
|
|
182
181
|
create(params?: CreateSandboxFromSnapshotParams | CreateSandboxFromImageParams, options?: {
|
|
183
182
|
timeout?: number;
|
|
184
183
|
onSnapshotCreateLogs?: (chunk: string) => void;
|
package/dist/daytona/daytona.js
CHANGED
|
@@ -183,8 +183,7 @@ export class Daytona {
|
|
|
183
183
|
async [Symbol.asyncDispose]() { }
|
|
184
184
|
/** Creates a sandbox and waits until it runs, with Daytona's defaults: 1
|
|
185
185
|
* vCPU, 1 GiB, 3 GiB disk, pausing after 15 minutes without calls. Funding
|
|
186
|
-
* is left to Runtime: the
|
|
187
|
-
* prepaid credit, exactly as withruntime's own create. */
|
|
186
|
+
* is left to Runtime: the included usage first, then prepaid credit, exactly as withruntime's own create. */
|
|
188
187
|
async create(params = {}, options = {}) {
|
|
189
188
|
refuseCreate(params);
|
|
190
189
|
const client = params.withruntime?.client ?? this.#client;
|
|
@@ -125,7 +125,7 @@ export declare class Sandbox {
|
|
|
125
125
|
/** Pauses the sandbox with its memory. */
|
|
126
126
|
pause(_timeout?: number): Promise<void>;
|
|
127
127
|
/** Runtime has no archive tier: a stopped sandbox stays paused, kept for
|
|
128
|
-
* its retention (30 days paid, 7
|
|
128
|
+
* its retention (30 days paid, 7 without credit, or autoDeleteInterval). */
|
|
129
129
|
archive(): Promise<void>;
|
|
130
130
|
/** Ends the sandbox for good. */
|
|
131
131
|
delete(_timeout?: number): Promise<void>;
|
package/dist/daytona/sandbox.js
CHANGED
|
@@ -269,7 +269,7 @@ export class Sandbox {
|
|
|
269
269
|
this.#pausedByPause = true;
|
|
270
270
|
}
|
|
271
271
|
/** Runtime has no archive tier: a stopped sandbox stays paused, kept for
|
|
272
|
-
* its retention (30 days paid, 7
|
|
272
|
+
* its retention (30 days paid, 7 without credit, or autoDeleteInterval). */
|
|
273
273
|
async archive() {
|
|
274
274
|
await this.stop();
|
|
275
275
|
}
|
package/dist/e2b/client.d.ts
CHANGED
|
@@ -43,15 +43,28 @@ export interface RuntimeOpts {
|
|
|
43
43
|
/** Refuses the E2B-only connection options: they point at E2B, and quietly
|
|
44
44
|
* dropping one would send the call somewhere its author did not mean. */
|
|
45
45
|
export declare function refuseE2BConnection(opts?: ConnectionOpts): void;
|
|
46
|
+
/** Connections the adapter's own client may hold at once: E2B's SDK has no
|
|
47
|
+
* cap of its own, so an orchestrator that drives a thousand sandboxes from one
|
|
48
|
+
* process runs every command at once. 4,096 is the widest room Runtime's edge
|
|
49
|
+
* gives an address that has used a valid key (api.md, "Limits"); the edge and
|
|
50
|
+
* the API answer anything past an account's room with a retry, which the
|
|
51
|
+
* client waits out. Runtime's own SDK keeps 48. */
|
|
52
|
+
export declare const E2B_MAX_CONNECTIONS = 4096;
|
|
53
|
+
/** Said once per process, the first time a call has to wait for a
|
|
54
|
+
* connection: E2B never holds a call back, so a caller should hear it. */
|
|
55
|
+
export declare function warnQueued(maxConnections: number): void;
|
|
46
56
|
/** The Runtime client for these options: an explicit client, else one per key,
|
|
47
57
|
* made once and reused so its connections stay open. */
|
|
48
58
|
export declare function clientFor(opts?: ConnectionOpts & {
|
|
49
59
|
runtime?: RuntimeOpts;
|
|
50
60
|
}): Runtime;
|
|
51
61
|
/** Explicit key, then RUNTIME_API_KEY, then E2B_API_KEY when it holds a
|
|
52
|
-
* Runtime key; undefined lets the Runtime SDK find the
|
|
62
|
+
* Runtime key; undefined, when none is set, lets the Runtime SDK find the
|
|
63
|
+
* saved login. An E2B key is refused, never sent. */
|
|
53
64
|
export declare function pickKey(explicit?: string): string | undefined;
|
|
54
|
-
/**
|
|
65
|
+
/** Where the key in use came from, as an error names it. */
|
|
66
|
+
export declare function keySource(explicit?: string): string;
|
|
67
|
+
/** Test hook: forget the cached clients and the warnings. */
|
|
55
68
|
export declare function resetClients(): void;
|
|
56
69
|
/** Request options for a Runtime call from E2B's. */
|
|
57
70
|
export declare function request(opts?: {
|
package/dist/e2b/client.js
CHANGED
|
@@ -26,6 +26,23 @@ export function refuseE2BConnection(opts = {}) {
|
|
|
26
26
|
throw new NotSupportedError("E2B's debug mode (a local envd)", "Remove debug: true; there is no local Runtime guest to connect to.");
|
|
27
27
|
}
|
|
28
28
|
const clients = new Map();
|
|
29
|
+
/** Connections the adapter's own client may hold at once: E2B's SDK has no
|
|
30
|
+
* cap of its own, so an orchestrator that drives a thousand sandboxes from one
|
|
31
|
+
* process runs every command at once. 4,096 is the widest room Runtime's edge
|
|
32
|
+
* gives an address that has used a valid key (api.md, "Limits"); the edge and
|
|
33
|
+
* the API answer anything past an account's room with a retry, which the
|
|
34
|
+
* client waits out. Runtime's own SDK keeps 48. */
|
|
35
|
+
export const E2B_MAX_CONNECTIONS = 4096;
|
|
36
|
+
let warnedQueued = false;
|
|
37
|
+
/** Said once per process, the first time a call has to wait for a
|
|
38
|
+
* connection: E2B never holds a call back, so a caller should hear it. */
|
|
39
|
+
export function warnQueued(maxConnections) {
|
|
40
|
+
if (warnedQueued || typeof process === "undefined" || !process.emitWarning)
|
|
41
|
+
return;
|
|
42
|
+
warnedQueued = true;
|
|
43
|
+
process.emitWarning(`More than ${maxConnections} calls and command streams are open at once from this process, so the rest wait their turn. ` +
|
|
44
|
+
"Pass runtime: { client: new Runtime({ maxConnections }) } for more.", { code: "RUNTIME_E2B_QUEUED" });
|
|
45
|
+
}
|
|
29
46
|
/** The Runtime client for these options: an explicit client, else one per key,
|
|
30
47
|
* made once and reused so its connections stay open. */
|
|
31
48
|
export function clientFor(opts = {}) {
|
|
@@ -36,30 +53,67 @@ export function clientFor(opts = {}) {
|
|
|
36
53
|
const cacheKey = key ?? "";
|
|
37
54
|
let client = clients.get(cacheKey);
|
|
38
55
|
if (!client) {
|
|
39
|
-
client = new Runtime(
|
|
56
|
+
client = new Runtime({
|
|
57
|
+
...(key ? { apiKey: key } : {}),
|
|
58
|
+
maxConnections: E2B_MAX_CONNECTIONS,
|
|
59
|
+
onQueued: warnQueued,
|
|
60
|
+
});
|
|
40
61
|
clients.set(cacheKey, client);
|
|
41
62
|
}
|
|
42
63
|
return client;
|
|
43
64
|
}
|
|
44
65
|
/** Explicit key, then RUNTIME_API_KEY, then E2B_API_KEY when it holds a
|
|
45
|
-
* Runtime key; undefined lets the Runtime SDK find the
|
|
66
|
+
* Runtime key; undefined, when none is set, lets the Runtime SDK find the
|
|
67
|
+
* saved login. An E2B key is refused, never sent. */
|
|
46
68
|
export function pickKey(explicit) {
|
|
47
69
|
const runtimeKey = env("RUNTIME_API_KEY");
|
|
48
70
|
if (explicit !== undefined && !isE2BKey(explicit))
|
|
49
71
|
return explicit;
|
|
50
|
-
if (runtimeKey)
|
|
72
|
+
if (runtimeKey) {
|
|
73
|
+
warnTwoKeys(runtimeKey, env("E2B_API_KEY"));
|
|
51
74
|
return runtimeKey;
|
|
75
|
+
}
|
|
52
76
|
if (explicit !== undefined)
|
|
53
77
|
throw new AuthenticationError("The apiKey passed is an E2B API key (e2b_...), and it was not sent. Set RUNTIME_API_KEY to a Runtime key " +
|
|
54
78
|
"(https://withruntime.com/account/keys, or run `npx withruntime login`), or pass the Runtime key as apiKey.");
|
|
55
|
-
// An E2B key left in E2B_API_KEY is
|
|
56
|
-
//
|
|
79
|
+
// An E2B key left in E2B_API_KEY is never sent, and never quietly passed
|
|
80
|
+
// over for the key `npx withruntime login` saved, which may be another
|
|
81
|
+
// account's.
|
|
57
82
|
const e2bVariable = env("E2B_API_KEY");
|
|
58
|
-
|
|
83
|
+
if (e2bVariable && isE2BKey(e2bVariable))
|
|
84
|
+
throw new AuthenticationError("E2B_API_KEY holds an E2B API key (e2b_...), and it was not sent. Set RUNTIME_API_KEY to a Runtime key " +
|
|
85
|
+
"(https://withruntime.com/account/keys, or run `npx withruntime login`), or put the Runtime key in E2B_API_KEY.");
|
|
86
|
+
return e2bVariable || undefined;
|
|
87
|
+
}
|
|
88
|
+
/** Where the key in use came from, as an error names it. */
|
|
89
|
+
export function keySource(explicit) {
|
|
90
|
+
if (explicit !== undefined && !isE2BKey(explicit))
|
|
91
|
+
return "apiKey";
|
|
92
|
+
if (env("RUNTIME_API_KEY"))
|
|
93
|
+
return "RUNTIME_API_KEY";
|
|
94
|
+
if (env("E2B_API_KEY"))
|
|
95
|
+
return "E2B_API_KEY";
|
|
96
|
+
return "the saved login";
|
|
97
|
+
}
|
|
98
|
+
let warnedTwoKeys = false;
|
|
99
|
+
/** Said once per process: RUNTIME_API_KEY wins, as in Runtime's own SDK, but
|
|
100
|
+
* code written for E2B means E2B_API_KEY, so two different Runtime keys are
|
|
101
|
+
* likely two accounts, and the wrong one fails later as a missing image
|
|
102
|
+
* (5 October 2026). */
|
|
103
|
+
function warnTwoKeys(runtimeKey, e2bVariable) {
|
|
104
|
+
if (!e2bVariable || isE2BKey(e2bVariable) || e2bVariable === runtimeKey)
|
|
105
|
+
return;
|
|
106
|
+
if (warnedTwoKeys || typeof process === "undefined" || !process.emitWarning)
|
|
107
|
+
return;
|
|
108
|
+
warnedTwoKeys = true;
|
|
109
|
+
process.emitWarning("RUNTIME_API_KEY and E2B_API_KEY hold different Runtime keys, which may be different accounts; this package uses " +
|
|
110
|
+
"RUNTIME_API_KEY. Unset one, or set both to the same key.", { code: "RUNTIME_E2B_TWO_KEYS" });
|
|
59
111
|
}
|
|
60
|
-
/** Test hook: forget the cached clients. */
|
|
112
|
+
/** Test hook: forget the cached clients and the warnings. */
|
|
61
113
|
export function resetClients() {
|
|
62
114
|
clients.clear();
|
|
115
|
+
warnedQueued = false;
|
|
116
|
+
warnedTwoKeys = false;
|
|
63
117
|
}
|
|
64
118
|
/** Request options for a Runtime call from E2B's. */
|
|
65
119
|
export function request(opts = {}) {
|
package/dist/e2b/commands.d.ts
CHANGED
|
@@ -43,6 +43,9 @@ export interface SandboxContext {
|
|
|
43
43
|
/** Makes /home/user (E2B's home) lead to /workspace (Runtime's), once, when
|
|
44
44
|
* something names it. */
|
|
45
45
|
ensureHome(text: string | undefined, options?: RequestOptions): Promise<void>;
|
|
46
|
+
/** Whether /home/user leads to /workspace, linking it first if nothing is
|
|
47
|
+
* there; false when that cannot be told. Never fails. */
|
|
48
|
+
homeIsWorkspace(): Promise<boolean>;
|
|
46
49
|
}
|
|
47
50
|
/** E2B's pids are numbers; Runtime's process ids are strings. The number is a
|
|
48
51
|
* 31-bit FNV-1a hash of the id, so every client derives the same one. */
|
package/dist/e2b/commands.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CommandExitError, guard, InvalidArgumentError, SandboxError, TimeoutError, translate, } from "./errors.js";
|
|
2
|
-
import { commandAs, runAs } from "./users.js";
|
|
1
|
+
import { CommandExitError, guard, InvalidArgumentError, SandboxError, SandboxNotFoundError, TimeoutError, translate, } from "./errors.js";
|
|
2
|
+
import { commandAs, listedAs, runAs } from "./users.js";
|
|
3
3
|
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
4
4
|
/** How long a command may run on Runtime: a day, E2B's longest sandbox. E2B's
|
|
5
5
|
* own `timeoutMs` bounds only the connection, so the process gets this. */
|
|
@@ -238,12 +238,19 @@ export class Commands {
|
|
|
238
238
|
function describe(info) {
|
|
239
239
|
return {
|
|
240
240
|
pid: pidOf(info.id),
|
|
241
|
-
|
|
242
|
-
args: ["-c", info.command],
|
|
241
|
+
...listedAs(info.command),
|
|
243
242
|
envs: {},
|
|
244
243
|
cwd: info.cwd,
|
|
245
244
|
};
|
|
246
245
|
}
|
|
246
|
+
/** A command whose sandbox went away under it, as E2B says it: a
|
|
247
|
+
* TimeoutError, which code written for E2B catches (5 October 2026: it was a
|
|
248
|
+
* SandboxNotFoundError). */
|
|
249
|
+
function sandboxEnded(cause) {
|
|
250
|
+
const error = new TimeoutError("The command ended before the stream completed: the sandbox was killed or reached its end of life.");
|
|
251
|
+
error.cause = cause;
|
|
252
|
+
return error;
|
|
253
|
+
}
|
|
247
254
|
/** Reader cancellation also releases a callback whose promise never settles. */
|
|
248
255
|
async function deliver(signal, callback) {
|
|
249
256
|
signal.throwIfAborted();
|
|
@@ -349,7 +356,11 @@ export class CommandHandle {
|
|
|
349
356
|
if (!this.#disconnected && !this.#failure) {
|
|
350
357
|
const translated = translate(error, "sandbox");
|
|
351
358
|
this.#failure =
|
|
352
|
-
translated instanceof
|
|
359
|
+
translated instanceof SandboxNotFoundError
|
|
360
|
+
? sandboxEnded(translated)
|
|
361
|
+
: translated instanceof Error
|
|
362
|
+
? translated
|
|
363
|
+
: new SandboxError(String(translated));
|
|
353
364
|
}
|
|
354
365
|
}
|
|
355
366
|
finally {
|
package/dist/e2b/errors.d.ts
CHANGED
|
@@ -37,6 +37,31 @@ export declare class ServiceBusyError extends Error {
|
|
|
37
37
|
requestId?: string;
|
|
38
38
|
constructor(message: string);
|
|
39
39
|
}
|
|
40
|
+
/** E2B's other error classes, by the same names and parents, so a module
|
|
41
|
+
* that imports or catches them loads and works: nothing in this package
|
|
42
|
+
* throws them, since the features behind them (template builds, git,
|
|
43
|
+
* volumes, secrets) answer NotSupportedError here. */
|
|
44
|
+
export declare class GitAuthError extends AuthenticationError {
|
|
45
|
+
}
|
|
46
|
+
export declare class GitUpstreamError extends SandboxError {
|
|
47
|
+
}
|
|
48
|
+
export declare class BuildError extends Error {
|
|
49
|
+
constructor(message?: string);
|
|
50
|
+
}
|
|
51
|
+
export declare class FileUploadError extends BuildError {
|
|
52
|
+
}
|
|
53
|
+
export declare class VolumeError extends Error {
|
|
54
|
+
constructor(message?: string);
|
|
55
|
+
}
|
|
56
|
+
export declare class VolumeNotFoundError extends VolumeError {
|
|
57
|
+
}
|
|
58
|
+
export declare class VolumePathNotFoundError extends VolumeError {
|
|
59
|
+
}
|
|
60
|
+
export declare class SecretError extends Error {
|
|
61
|
+
constructor(message?: string);
|
|
62
|
+
}
|
|
63
|
+
export declare class SecretNotFoundError extends SecretError {
|
|
64
|
+
}
|
|
40
65
|
/** A call that E2B supports and Runtime does not, or not in the same way.
|
|
41
66
|
* Thrown before anything is done, never after doing something different.
|
|
42
67
|
* `feature` names what was asked for; `alternative` says what to use on
|
|
@@ -46,8 +71,7 @@ export declare class NotSupportedError extends SandboxError {
|
|
|
46
71
|
readonly alternative: string;
|
|
47
72
|
constructor(feature: string, alternative: string, message?: string);
|
|
48
73
|
}
|
|
49
|
-
/** Runtime's addition, for `getHost` and `getPublicHost`: a
|
|
50
|
-
* sandbox shares a port only privately, so a request needs the port's token,
|
|
74
|
+
/** Runtime's addition, for `getHost` and `getPublicHost`: a sandbox without credit shares a port only privately, so a request needs the port's token,
|
|
51
75
|
* and a host name alone cannot carry one. The message says what works. A
|
|
52
76
|
* NotSupportedError, so code that catches those catches this too. */
|
|
53
77
|
export declare class PublicPreviewNotAllowedError extends NotSupportedError {
|
package/dist/e2b/errors.js
CHANGED
|
@@ -58,6 +58,40 @@ export class ServiceBusyError extends Error {
|
|
|
58
58
|
this.name = new.target.name;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
/** E2B's other error classes, by the same names and parents, so a module
|
|
62
|
+
* that imports or catches them loads and works: nothing in this package
|
|
63
|
+
* throws them, since the features behind them (template builds, git,
|
|
64
|
+
* volumes, secrets) answer NotSupportedError here. */
|
|
65
|
+
export class GitAuthError extends AuthenticationError {
|
|
66
|
+
}
|
|
67
|
+
export class GitUpstreamError extends SandboxError {
|
|
68
|
+
}
|
|
69
|
+
export class BuildError extends Error {
|
|
70
|
+
constructor(message) {
|
|
71
|
+
super(message);
|
|
72
|
+
this.name = new.target.name;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export class FileUploadError extends BuildError {
|
|
76
|
+
}
|
|
77
|
+
export class VolumeError extends Error {
|
|
78
|
+
constructor(message) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.name = new.target.name;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export class VolumeNotFoundError extends VolumeError {
|
|
84
|
+
}
|
|
85
|
+
export class VolumePathNotFoundError extends VolumeError {
|
|
86
|
+
}
|
|
87
|
+
export class SecretError extends Error {
|
|
88
|
+
constructor(message) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = new.target.name;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class SecretNotFoundError extends SecretError {
|
|
94
|
+
}
|
|
61
95
|
/** A call that E2B supports and Runtime does not, or not in the same way.
|
|
62
96
|
* Thrown before anything is done, never after doing something different.
|
|
63
97
|
* `feature` names what was asked for; `alternative` says what to use on
|
|
@@ -72,19 +106,18 @@ export class NotSupportedError extends SandboxError {
|
|
|
72
106
|
this.code = "not_supported";
|
|
73
107
|
}
|
|
74
108
|
}
|
|
75
|
-
/** Runtime's addition, for `getHost` and `getPublicHost`: a
|
|
76
|
-
* sandbox shares a port only privately, so a request needs the port's token,
|
|
109
|
+
/** Runtime's addition, for `getHost` and `getPublicHost`: a sandbox without credit shares a port only privately, so a request needs the port's token,
|
|
77
110
|
* and a host name alone cannot carry one. The message says what works. A
|
|
78
111
|
* NotSupportedError, so code that catches those catches this too. */
|
|
79
112
|
export class PublicPreviewNotAllowedError extends NotSupportedError {
|
|
80
113
|
constructor(sandboxId, port, message) {
|
|
81
114
|
const where = port === undefined ? "<port>" : String(port);
|
|
82
|
-
const alternative = `For an address that works
|
|
115
|
+
const alternative = `For an address that works without credit, use (await sandbox.runtime.previews.create(${where})).urlWithToken: ` +
|
|
83
116
|
"it carries the token, in a browser, fetch or curl. For other paths on it, send the token as the " +
|
|
84
117
|
"x-runtime-preview-token header or the runtime_preview_token query parameter. A public host needs a paid " +
|
|
85
118
|
"sandbox, which is the account owner's decision.";
|
|
86
|
-
super("A public address on a
|
|
87
|
-
`Sandbox ${sandboxId} runs
|
|
119
|
+
super("A public address on a sandbox without credit", alternative, message ??
|
|
120
|
+
`Sandbox ${sandboxId} runs without credit, where a shared port is private: every request needs the ` +
|
|
88
121
|
`port's token, and a host name alone cannot carry one. ${alternative}`);
|
|
89
122
|
this.code = "public_preview_not_allowed";
|
|
90
123
|
}
|
package/dist/e2b/filesystem.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ export interface FilesystemListOpts extends FilesystemRequestOpts {
|
|
|
72
72
|
}
|
|
73
73
|
/** `sandbox.files`: E2B's filesystem module over Runtime's files API. Relative
|
|
74
74
|
* paths resolve against the home directory, as in E2B (Runtime's is
|
|
75
|
-
* /workspace). */
|
|
75
|
+
* /workspace), and come back under /home/user, as E2B gives them. */
|
|
76
76
|
export declare class Filesystem {
|
|
77
77
|
#private;
|
|
78
78
|
constructor(ctx: SandboxContext);
|