withruntime 0.6.0 → 0.7.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.
- package/E2B.md +32 -32
- package/README.md +8 -5
- package/dist/ai/index.d.ts +21 -5
- package/dist/ai/index.js +14 -21
- package/dist/ai-harness/index.d.ts +194 -0
- package/dist/ai-harness/index.js +517 -0
- package/dist/billing-cli.d.ts +21 -0
- package/dist/billing-cli.js +158 -0
- package/dist/cli-extras.d.ts +15 -0
- package/dist/cli-extras.js +60 -4
- package/dist/cli-name.d.ts +6 -0
- package/dist/cli-name.js +8 -0
- package/dist/cli.d.ts +17 -1
- package/dist/cli.js +537 -130
- package/dist/client.d.ts +35 -6
- package/dist/client.js +23 -0
- package/dist/credentials.js +1 -2
- package/dist/daytona/filesystem.d.ts +2 -0
- package/dist/daytona/filesystem.js +9 -7
- package/dist/e2b/filesystem.js +3 -2
- package/dist/e2b/sandbox.d.ts +9 -6
- package/dist/e2b/sandbox.js +31 -7
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +7 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +1 -0
- package/dist/keys.js +1 -1
- package/dist/login.d.ts +2 -6
- package/dist/login.js +3 -8
- package/dist/network-cli.d.ts +1 -1
- package/dist/network-cli.js +64 -2
- package/dist/products/billing.d.ts +35 -0
- package/dist/products/billing.js +13 -0
- package/dist/products/index.d.ts +4 -1
- package/dist/products/index.js +4 -1
- package/dist/products/network-products.d.ts +45 -0
- package/dist/products/network-products.js +27 -0
- package/dist/products/previews.d.ts +1 -2
- package/dist/products/secrets.d.ts +14 -0
- package/dist/sandbox.d.ts +17 -3
- package/dist/sandbox.js +233 -62
- package/dist/transport.d.ts +17 -1
- package/dist/transport.js +124 -7
- package/dist/types.d.ts +0 -2
- package/dist/wallet.d.ts +30 -0
- package/dist/wallet.js +48 -0
- package/package.json +44 -17
package/dist/client.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RuntimeError } from "./errors.js";
|
|
1
2
|
import type { Page } from "./page.js";
|
|
2
3
|
import { type ClientExtensions } from "./products/index.js";
|
|
3
4
|
import { Sandbox } from "./sandbox.js";
|
|
@@ -33,6 +34,7 @@ export declare class Runtime {
|
|
|
33
34
|
readonly snapshots: Snapshots;
|
|
34
35
|
readonly feedback: FeedbackApi;
|
|
35
36
|
readonly support: SupportApi;
|
|
37
|
+
readonly account: AccountApi;
|
|
36
38
|
constructor(options?: RuntimeOptions);
|
|
37
39
|
/** Who this key is: organization, agent and credential. */
|
|
38
40
|
me(options?: RequestOptions): Promise<{
|
|
@@ -49,6 +51,16 @@ export declare class Runtime {
|
|
|
49
51
|
/** Credit, holds, trial time and per-resource charges. */
|
|
50
52
|
usage(options?: RequestOptions): Promise<Usage>;
|
|
51
53
|
}
|
|
54
|
+
/** How `sandboxes.create` waits when every trial slot, the account's quota or
|
|
55
|
+
* the region is full. */
|
|
56
|
+
export type CreateOptions = RequestOptions & {
|
|
57
|
+
/** How long to keep retrying a refusal that clears by itself. Default: the
|
|
58
|
+
* client's, two minutes; 0 fails at once. */
|
|
59
|
+
waitForCapacityMs?: number;
|
|
60
|
+
/** Called before each wait, with the refusal and the milliseconds until the
|
|
61
|
+
* next try: to tell a person why nothing has happened yet. */
|
|
62
|
+
onCapacityWait?: (refusal: RuntimeError, waitMs: number) => void;
|
|
63
|
+
};
|
|
52
64
|
export declare class Sandboxes {
|
|
53
65
|
private readonly t;
|
|
54
66
|
constructor(t: Transport);
|
|
@@ -59,18 +71,14 @@ export declare class Sandboxes {
|
|
|
59
71
|
* free, up to `waitForCapacityMs` (the client's, two minutes by default). */
|
|
60
72
|
create(input?: CreateSandbox & {
|
|
61
73
|
wait?: boolean;
|
|
62
|
-
}, options?:
|
|
63
|
-
waitForCapacityMs?: number;
|
|
64
|
-
}): Promise<Sandbox>;
|
|
74
|
+
}, options?: CreateOptions): Promise<Sandbox>;
|
|
65
75
|
/** The sandbox named `name` in this account, ready to use: running as it
|
|
66
76
|
* is, woken if it is paused, restarted if it is stopped and persistent, or
|
|
67
77
|
* created with `input` when no sandbox has the name. `sandbox.info.reused`
|
|
68
78
|
* says which. The other fields apply only when it is created. */
|
|
69
79
|
getOrCreate(name: string, input?: Omit<CreateSandbox, "name" | "getOrCreate"> & {
|
|
70
80
|
wait?: boolean;
|
|
71
|
-
}, options?:
|
|
72
|
-
waitForCapacityMs?: number;
|
|
73
|
-
}): Promise<Sandbox>;
|
|
81
|
+
}, options?: CreateOptions): Promise<Sandbox>;
|
|
74
82
|
get(id: string, options?: RequestOptions): Promise<Sandbox>;
|
|
75
83
|
/** Live sandboxes, oldest first. Await for a page, or `for await` over all. */
|
|
76
84
|
list(filter?: {
|
|
@@ -142,5 +150,26 @@ export declare class SupportApi {
|
|
|
142
150
|
}): Promise<SupportReply>;
|
|
143
151
|
read(conversationId: string): Promise<SupportReply>;
|
|
144
152
|
}
|
|
153
|
+
/** What closing the account answered. */
|
|
154
|
+
export type ClosedAccount = {
|
|
155
|
+
orgId: string;
|
|
156
|
+
name: string;
|
|
157
|
+
closedAt: string;
|
|
158
|
+
/** False while what was running is still stopping; it is gone within minutes. */
|
|
159
|
+
released: boolean;
|
|
160
|
+
};
|
|
161
|
+
/** The account this key belongs to: `runtime.account`. */
|
|
162
|
+
export declare class AccountApi {
|
|
163
|
+
private readonly t;
|
|
164
|
+
constructor(t: Transport);
|
|
165
|
+
/** Close the account for good: stop and delete everything it runs and
|
|
166
|
+
* stores, end every key and dissolve it. `confirm` must be the account's
|
|
167
|
+
* name exactly (`me().orgName`). Needs a key for every product made by an
|
|
168
|
+
* owner. Moves no money: what is unspent of a purchase made in the last 15
|
|
169
|
+
* days is refunded on request; other credit is forfeited. */
|
|
170
|
+
close(input: {
|
|
171
|
+
confirm: string;
|
|
172
|
+
}, options?: RequestOptions): Promise<ClosedAccount>;
|
|
173
|
+
}
|
|
145
174
|
/** The client behind the static helpers, from the environment. */
|
|
146
175
|
export declare function defaultClient(): Runtime;
|
package/dist/client.js
CHANGED
|
@@ -20,6 +20,7 @@ export class Runtime {
|
|
|
20
20
|
snapshots;
|
|
21
21
|
feedback;
|
|
22
22
|
support;
|
|
23
|
+
account;
|
|
23
24
|
constructor(options = {}) {
|
|
24
25
|
this.transport = new Transport({
|
|
25
26
|
// A key given, then RUNTIME_API_KEY, then (in Node and Bun) the key
|
|
@@ -38,6 +39,7 @@ export class Runtime {
|
|
|
38
39
|
this.snapshots = new Snapshots(this.transport);
|
|
39
40
|
this.feedback = new FeedbackApi(this.transport);
|
|
40
41
|
this.support = new SupportApi(this.transport);
|
|
42
|
+
this.account = new AccountApi(this.transport);
|
|
41
43
|
for (const [name, make] of clientFactories())
|
|
42
44
|
Object.defineProperty(this, name, { value: make(this.transport), enumerable: true });
|
|
43
45
|
}
|
|
@@ -165,6 +167,27 @@ export class SupportApi {
|
|
|
165
167
|
});
|
|
166
168
|
}
|
|
167
169
|
}
|
|
170
|
+
/** The account this key belongs to: `runtime.account`. */
|
|
171
|
+
export class AccountApi {
|
|
172
|
+
t;
|
|
173
|
+
constructor(t) {
|
|
174
|
+
this.t = t;
|
|
175
|
+
}
|
|
176
|
+
/** Close the account for good: stop and delete everything it runs and
|
|
177
|
+
* stores, end every key and dissolve it. `confirm` must be the account's
|
|
178
|
+
* name exactly (`me().orgName`). Needs a key for every product made by an
|
|
179
|
+
* owner. Moves no money: what is unspent of a purchase made in the last 15
|
|
180
|
+
* days is refunded on request; other credit is forfeited. */
|
|
181
|
+
close(input, options = {}) {
|
|
182
|
+
return this.t.json({
|
|
183
|
+
method: "POST",
|
|
184
|
+
path: "/v1/account:close",
|
|
185
|
+
body: { confirm: input.confirm },
|
|
186
|
+
retry: false,
|
|
187
|
+
...options,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
168
191
|
let shared;
|
|
169
192
|
/** The client behind the static helpers, from the environment. */
|
|
170
193
|
export function defaultClient() {
|
package/dist/credentials.js
CHANGED
|
@@ -3,8 +3,7 @@ import { constants } from "node:fs";
|
|
|
3
3
|
import { lstat, mkdir, open, rename, unlink } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { isAbsolute, join } from "node:path";
|
|
6
|
-
import { apiOrigin } from "./
|
|
7
|
-
import { missingKey } from "./transport.js";
|
|
6
|
+
import { apiOrigin, missingKey } from "./transport.js";
|
|
8
7
|
/** How many other accounts' connections one machine keeps beside the one in use. */
|
|
9
8
|
const SAVED_ACCOUNTS = 20;
|
|
10
9
|
export function connectionOrigins(env) {
|
|
@@ -60,6 +60,8 @@ export declare class FileSystem {
|
|
|
60
60
|
/** The file's bytes, or with a local path, the file written there. */
|
|
61
61
|
downloadFile(remotePath: string, timeout?: number): Promise<Buffer>;
|
|
62
62
|
downloadFile(remotePath: string, localPath: string, timeout?: number): Promise<void>;
|
|
63
|
+
/** The file as it arrives, without holding it in memory. It errors with
|
|
64
|
+
* `download_incomplete` if it ends short of the file's length. */
|
|
63
65
|
downloadFileStream(remotePath: string): Promise<Readable>;
|
|
64
66
|
/** Several files; a file that fails carries `error` instead of `result`. */
|
|
65
67
|
downloadFiles(files: FileDownloadRequest[]): Promise<FileDownloadResponse[]>;
|
|
@@ -69,17 +69,19 @@ export class FileSystem {
|
|
|
69
69
|
async downloadFile(remotePath, localOrTimeout) {
|
|
70
70
|
const target = await this.#path(remotePath);
|
|
71
71
|
const files = await this.#files();
|
|
72
|
-
const bytes = Buffer.from(await guard("file", () => files.read(target)));
|
|
73
72
|
if (typeof localOrTimeout !== "string")
|
|
74
|
-
return
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
await mkdir(paths.dirname(localOrTimeout), { recursive: true });
|
|
78
|
-
await writeFile(localOrTimeout, bytes);
|
|
73
|
+
return Buffer.from(await guard("file", () => files.read(target)));
|
|
74
|
+
// Streamed to disk, any size, checked against the file's length.
|
|
75
|
+
await guard("file", () => files.download(target, localOrTimeout));
|
|
79
76
|
}
|
|
77
|
+
/** The file as it arrives, without holding it in memory. It errors with
|
|
78
|
+
* `download_incomplete` if it ends short of the file's length. */
|
|
80
79
|
async downloadFileStream(remotePath) {
|
|
81
80
|
const { Readable } = await import("node:stream");
|
|
82
|
-
|
|
81
|
+
const target = await this.#path(remotePath);
|
|
82
|
+
const files = await this.#files();
|
|
83
|
+
const stream = await guard("file", () => files.readStream(target));
|
|
84
|
+
return Readable.fromWeb(stream);
|
|
83
85
|
}
|
|
84
86
|
/** Several files; a file that fails carries `error` instead of `result`. */
|
|
85
87
|
async downloadFiles(files) {
|
package/dist/e2b/filesystem.js
CHANGED
|
@@ -79,14 +79,15 @@ export class Filesystem {
|
|
|
79
79
|
}
|
|
80
80
|
async read(path, opts = {}) {
|
|
81
81
|
const file = await this.#path(path, opts);
|
|
82
|
+
// A real stream, any size, never the whole file held first.
|
|
83
|
+
if (opts.format === "stream")
|
|
84
|
+
return guard("file", () => this.#files.readStream(file, request(opts)));
|
|
82
85
|
const bytes = await guard("file", () => this.#files.read(file, request(opts)));
|
|
83
86
|
switch (opts.format) {
|
|
84
87
|
case "bytes":
|
|
85
88
|
return bytes;
|
|
86
89
|
case "blob":
|
|
87
90
|
return new Blob([bytes]);
|
|
88
|
-
case "stream":
|
|
89
|
-
return new Blob([bytes]).stream();
|
|
90
91
|
default:
|
|
91
92
|
return new TextDecoder().decode(bytes);
|
|
92
93
|
}
|
package/dist/e2b/sandbox.d.ts
CHANGED
|
@@ -86,8 +86,6 @@ export type SandboxListOpts = SandboxApiOpts & {
|
|
|
86
86
|
limit?: number;
|
|
87
87
|
nextToken?: string;
|
|
88
88
|
};
|
|
89
|
-
/** A sandbox, with E2B's methods. `sandbox.runtime` is the Runtime sandbox
|
|
90
|
-
* underneath, for anything E2B has no name for. */
|
|
91
89
|
export declare class Sandbox {
|
|
92
90
|
#private;
|
|
93
91
|
protected static readonly defaultTemplate: string;
|
|
@@ -156,12 +154,17 @@ export declare class Sandbox {
|
|
|
156
154
|
name?: string;
|
|
157
155
|
}): Promise<SnapshotInfo>;
|
|
158
156
|
static deleteSnapshot(snapshotId: string, opts?: SandboxApiOpts): Promise<boolean>;
|
|
159
|
-
/**
|
|
160
|
-
*
|
|
157
|
+
/** E2B's getHost, answered at once as E2B answers it:
|
|
158
|
+
* `<port>-<id>.runtimehost.com`. A Runtime preview's address is made from
|
|
159
|
+
* the sandbox and the port alone, so it is known without a call; the port
|
|
160
|
+
* is shared publicly the first time it is asked for, in about a tenth of a
|
|
161
|
+
* second, beside the caller. A request that lands before the share may be
|
|
162
|
+
* answered 404 for up to two seconds; `await getPublicHost(port)` returns
|
|
163
|
+
* once the share has landed. */
|
|
161
164
|
getHost(port: number): string;
|
|
162
165
|
/** Shares `port` at a public HTTPS address (a Runtime preview) and returns
|
|
163
|
-
* its host, `<port>-<id>.<domain>`,
|
|
164
|
-
* address can reach it; a browser sees a one-time page naming Runtime. */
|
|
166
|
+
* its host, `<port>-<id>.<domain>`, once the share has landed. Anyone with
|
|
167
|
+
* the address can reach it; a browser sees a one-time page naming Runtime. */
|
|
165
168
|
getPublicHost(port: number): Promise<string>;
|
|
166
169
|
get pty(): never;
|
|
167
170
|
get git(): never;
|
package/dist/e2b/sandbox.js
CHANGED
|
@@ -128,6 +128,8 @@ function unsupported(feature, alternative) {
|
|
|
128
128
|
}
|
|
129
129
|
/** A sandbox, with E2B's methods. `sandbox.runtime` is the Runtime sandbox
|
|
130
130
|
* underneath, for anything E2B has no name for. */
|
|
131
|
+
/** Where Runtime serves previews; getHost names a host under it. */
|
|
132
|
+
const PREVIEW_DOMAIN = "runtimehost.com";
|
|
131
133
|
export class Sandbox {
|
|
132
134
|
static defaultTemplate = "base";
|
|
133
135
|
files;
|
|
@@ -136,6 +138,8 @@ export class Sandbox {
|
|
|
136
138
|
#runtime;
|
|
137
139
|
#envs;
|
|
138
140
|
#home;
|
|
141
|
+
/** Ports shared as public previews, by port: the one share each asked for. */
|
|
142
|
+
#shares = new Map();
|
|
139
143
|
/** Use Sandbox.create or Sandbox.connect. */
|
|
140
144
|
constructor(runtime, client, envs = {}) {
|
|
141
145
|
this.#runtime = runtime;
|
|
@@ -332,17 +336,37 @@ export class Sandbox {
|
|
|
332
336
|
}
|
|
333
337
|
}
|
|
334
338
|
// ---- ports ------------------------------------------------------------
|
|
335
|
-
/**
|
|
336
|
-
*
|
|
339
|
+
/** E2B's getHost, answered at once as E2B answers it:
|
|
340
|
+
* `<port>-<id>.runtimehost.com`. A Runtime preview's address is made from
|
|
341
|
+
* the sandbox and the port alone, so it is known without a call; the port
|
|
342
|
+
* is shared publicly the first time it is asked for, in about a tenth of a
|
|
343
|
+
* second, beside the caller. A request that lands before the share may be
|
|
344
|
+
* answered 404 for up to two seconds; `await getPublicHost(port)` returns
|
|
345
|
+
* once the share has landed. */
|
|
337
346
|
getHost(port) {
|
|
338
|
-
|
|
347
|
+
if (!Number.isInteger(port) || port < 1 || port > 65_535)
|
|
348
|
+
throw new InvalidArgumentError(`port must be a whole number from 1 to 65535, not ${port}.`);
|
|
349
|
+
void this.#share(port).catch((error) => {
|
|
350
|
+
if (typeof process !== "undefined" && process.emitWarning)
|
|
351
|
+
process.emitWarning(`Sharing port ${port} for getHost failed: ${error instanceof Error ? error.message : String(error)}. getPublicHost(${port}) says why.`, { code: "RUNTIME_E2B_GET_HOST" });
|
|
352
|
+
});
|
|
353
|
+
return `${port}-${this.sandboxId.replaceAll("-", "").toLowerCase()}.${PREVIEW_DOMAIN}`;
|
|
339
354
|
}
|
|
340
355
|
/** Shares `port` at a public HTTPS address (a Runtime preview) and returns
|
|
341
|
-
* its host, `<port>-<id>.<domain>`,
|
|
342
|
-
* address can reach it; a browser sees a one-time page naming Runtime. */
|
|
356
|
+
* its host, `<port>-<id>.<domain>`, once the share has landed. Anyone with
|
|
357
|
+
* the address can reach it; a browser sees a one-time page naming Runtime. */
|
|
343
358
|
async getPublicHost(port) {
|
|
344
|
-
|
|
345
|
-
|
|
359
|
+
return this.#share(port);
|
|
360
|
+
}
|
|
361
|
+
#share(port) {
|
|
362
|
+
let share = this.#shares.get(port);
|
|
363
|
+
if (!share) {
|
|
364
|
+
share = guard("sandbox", () => this.#runtime.previews.create(port, { visibility: "public" })).then((preview) => new URL(preview.url).host);
|
|
365
|
+
// A failed share is asked again next time, not remembered.
|
|
366
|
+
share.catch(() => this.#shares.delete(port));
|
|
367
|
+
this.#shares.set(port, share);
|
|
368
|
+
}
|
|
369
|
+
return share;
|
|
346
370
|
}
|
|
347
371
|
// ---- what Runtime does differently -----------------------------------
|
|
348
372
|
get pty() {
|
package/dist/errors.d.ts
CHANGED
|
@@ -45,6 +45,11 @@ export declare class RateLimitError extends RuntimeError {
|
|
|
45
45
|
}
|
|
46
46
|
export declare class ServiceUnavailableError extends RuntimeError {
|
|
47
47
|
}
|
|
48
|
+
/** The account may not spend: a payment on it is disputed or under review
|
|
49
|
+
* (`account_blocked`, 402). The message says which and what clears it; a
|
|
50
|
+
* retry cannot, and adding credit alone may not. */
|
|
51
|
+
export declare class AccountBlockedError extends RuntimeError {
|
|
52
|
+
}
|
|
48
53
|
/** No answer arrived. A write may or may not have happened; retrying with the
|
|
49
54
|
* same idempotencyKey (the SDK does, automatically) settles it safely. */
|
|
50
55
|
export declare class ConnectionError extends RuntimeError {
|
package/dist/errors.js
CHANGED
|
@@ -74,6 +74,11 @@ export class RateLimitError extends RuntimeError {
|
|
|
74
74
|
}
|
|
75
75
|
export class ServiceUnavailableError extends RuntimeError {
|
|
76
76
|
}
|
|
77
|
+
/** The account may not spend: a payment on it is disputed or under review
|
|
78
|
+
* (`account_blocked`, 402). The message says which and what clears it; a
|
|
79
|
+
* retry cannot, and adding credit alone may not. */
|
|
80
|
+
export class AccountBlockedError extends RuntimeError {
|
|
81
|
+
}
|
|
77
82
|
/** No answer arrived. A write may or may not have happened; retrying with the
|
|
78
83
|
* same idempotencyKey (the SDK does, automatically) settles it safely. */
|
|
79
84
|
export class ConnectionError extends RuntimeError {
|
|
@@ -110,6 +115,8 @@ export function errorFor(status, body, idempotencyKey) {
|
|
|
110
115
|
...(typeof error.retryAfterMs === "number" ? { retryAfterMs: error.retryAfterMs } : {}),
|
|
111
116
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
112
117
|
};
|
|
118
|
+
if (init.code === "account_blocked")
|
|
119
|
+
return new AccountBlockedError(init);
|
|
113
120
|
if (status === 401)
|
|
114
121
|
return new AuthenticationError(init);
|
|
115
122
|
if (status === 403)
|
package/dist/index.d.ts
CHANGED
|
@@ -5,22 +5,22 @@
|
|
|
5
5
|
* console.log((await sbx.exec("echo hello")).stdout);
|
|
6
6
|
*/
|
|
7
7
|
import type { Runtime } from "./client.js";
|
|
8
|
-
import { type RuntimeOptions } from "./client.js";
|
|
8
|
+
import { type CreateOptions, type RuntimeOptions } from "./client.js";
|
|
9
9
|
import { Sandbox as SandboxClass } from "./sandbox.js";
|
|
10
10
|
import type { CreateSandbox, KeepAliveOptions } from "./types.js";
|
|
11
11
|
import type { RequestOptions } from "./transport.js";
|
|
12
|
-
export { Runtime, Sandboxes, FeedbackApi, SupportApi, type RuntimeOptions, type SupportReply, } from "./client.js";
|
|
12
|
+
export { Runtime, Sandboxes, FeedbackApi, SupportApi, type CreateOptions, type RuntimeOptions, type SupportReply, } from "./client.js";
|
|
13
13
|
export { Files, Process, Processes, Terminal } from "./sandbox.js";
|
|
14
14
|
export { Tunnel, TunnelStream, type PortForward } from "./tunnel.js";
|
|
15
15
|
export { Page } from "./page.js";
|
|
16
16
|
export type { KeyLimits } from "./products/limits.js";
|
|
17
17
|
export type { AuditEvent, AuditPage } from "./products/audit.js";
|
|
18
|
-
export type { Secret, SetSecret } from "./products/secrets.js";
|
|
18
|
+
export type { Secret, SecretRule, SetSecret } from "./products/secrets.js";
|
|
19
19
|
export type { McpCatalogEntry, McpGateway, McpServerRequest } from "./products/mcp.js";
|
|
20
20
|
export type { FileEvent, FileEventType, WatchHandle, WatchNotice, WatchOptions, } from "./products/watch.js";
|
|
21
21
|
export type { Mount, MountBucket } from "./products/mounts.js";
|
|
22
22
|
export type { Volume, VolumeBackup, CreateVolume } from "./products/volumes.js";
|
|
23
|
-
export type { CheckedDomain, DnsRecord, Domain, EgressAddress, TcpPort, Tunnel as PrivateTunnel, TunnelPeer, TunnelPeerCreated, } from "./products/network-products.js";
|
|
23
|
+
export type { CheckedDomain, DnsRecord, Domain, EgressAddress, TcpPort, Tunnel as PrivateTunnel, TunnelPeer, TunnelPeerCreated, SetUpstreamProxy, UpstreamProxy, } from "./products/network-products.js";
|
|
24
24
|
export { verifyWebhook, WebhookVerificationError, type MetricPoint, type MetricRange, type OtelExport, type RuntimeEvent, type SandboxMetrics, type Webhook, type WebhookDelivery, type WebhookEventType, } from "./products/observability.js";
|
|
25
25
|
export { Snapshots, type Snapshot, type SnapshotOptions } from "./snapshots.js";
|
|
26
26
|
export { Transport, VERSION, apiOrigin, type RequestOptions, type Call } from "./transport.js";
|
|
@@ -35,7 +35,7 @@ export declare class Sandbox extends SandboxClass {
|
|
|
35
35
|
static create(input?: CreateSandbox & {
|
|
36
36
|
wait?: boolean;
|
|
37
37
|
keepAlive?: boolean | KeepAliveOptions;
|
|
38
|
-
}, options?:
|
|
38
|
+
}, options?: CreateOptions & {
|
|
39
39
|
client?: Runtime;
|
|
40
40
|
}): Promise<SandboxClass>;
|
|
41
41
|
/** The sandbox named `name` in this account, ready to use: running as it
|
|
@@ -45,7 +45,7 @@ export declare class Sandbox extends SandboxClass {
|
|
|
45
45
|
static getOrCreate(name: string, input?: Omit<CreateSandbox, "name" | "getOrCreate"> & {
|
|
46
46
|
wait?: boolean;
|
|
47
47
|
keepAlive?: boolean | KeepAliveOptions;
|
|
48
|
-
}, options?:
|
|
48
|
+
}, options?: CreateOptions & {
|
|
49
49
|
client?: Runtime;
|
|
50
50
|
}): Promise<SandboxClass>;
|
|
51
51
|
/** Reconnects to an existing sandbox by id. */
|
|
@@ -65,4 +65,6 @@ export declare class Sandbox extends SandboxClass {
|
|
|
65
65
|
}
|
|
66
66
|
export type { RuntimeOptions as ClientOptions };
|
|
67
67
|
export { identityToken, type IdentityToken } from "./identity.js";
|
|
68
|
+
export { openWalletAccount, claimWalletAccount, type OpenedWalletAccount, type WalletClaim, type WalletOptions, } from "./wallet.js";
|
|
69
|
+
export type { Topup } from "./products/billing.js";
|
|
68
70
|
export type { SsoConnection, SsoStatus } from "./products/sso.js";
|
package/dist/index.js
CHANGED
package/dist/keys.js
CHANGED
|
@@ -4,7 +4,7 @@ import { hostname } from "node:os";
|
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { connectionOrigins } from "./credentials.js";
|
|
6
6
|
import { RuntimeError } from "./errors.js";
|
|
7
|
-
import { named } from "./
|
|
7
|
+
import { named } from "./cli-name.js";
|
|
8
8
|
import { describeRoute, envFetch } from "./proxy.js";
|
|
9
9
|
const KEY = /^rtcloud_([a-f0-9-]{36})_[A-Za-z0-9_-]{43}$/;
|
|
10
10
|
/** How often to ask whether the owner has answered. The website answers
|
package/dist/login.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare const me: string;
|
|
4
|
-
/** Text that names a command, with the command spelled the way it was run. */
|
|
5
|
-
export declare function named(text: string, name?: string): string;
|
|
1
|
+
import { me, named } from "./cli-name.js";
|
|
2
|
+
export { me, named };
|
|
6
3
|
type LoginOptions = {
|
|
7
4
|
readKey?: () => Promise<string>;
|
|
8
5
|
fetch?: typeof fetch;
|
|
@@ -116,4 +113,3 @@ export type PendingLogin = {
|
|
|
116
113
|
* waiting: `runtime login` waits on it, and the MCP bridge gives the link to
|
|
117
114
|
* the agent, which shows it to the person it works for. */
|
|
118
115
|
export declare function beginDeviceLogin(env: NodeJS.ProcessEnv, agentName: string, options?: LoginOptions): Promise<PendingLogin>;
|
|
119
|
-
export {};
|
package/dist/login.js
CHANGED
|
@@ -2,7 +2,8 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import { generateKeyPair, privateDecrypt } from "node:crypto";
|
|
3
3
|
import { hostname } from "node:os";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
-
import {
|
|
5
|
+
import { me, named } from "./cli-name.js";
|
|
6
|
+
import { Runtime } from "./client.js";
|
|
6
7
|
import { connectionOrigins, connectionStore } from "./credentials.js";
|
|
7
8
|
import { describeRoute, envFetch } from "./proxy.js";
|
|
8
9
|
class ConnectionError extends Error {
|
|
@@ -12,13 +13,7 @@ class ConnectionError extends Error {
|
|
|
12
13
|
this.status = status;
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
* the command is `npx withruntime`, installed it is `runtime`. */
|
|
17
|
-
export const me = /[\\/]_npx[\\/]/.test(process.argv[1] ?? "") ? "npx withruntime" : "runtime";
|
|
18
|
-
/** Text that names a command, with the command spelled the way it was run. */
|
|
19
|
-
export function named(text, name = me) {
|
|
20
|
-
return name === "runtime" ? text : text.replace(/(^|[\s`(])runtime(?= [a-z<[])/g, `$1${name}`);
|
|
21
|
-
}
|
|
16
|
+
export { me, named };
|
|
22
17
|
/** The connection id recorded for a key pasted with `login --with-key`. */
|
|
23
18
|
const PASTED = "pasted";
|
|
24
19
|
/** A key from standard input: piped, or typed at a prompt that does not echo. */
|
package/dist/network-cli.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ type Args = {
|
|
|
8
8
|
positional: string[];
|
|
9
9
|
flags: Map<string, string[]>;
|
|
10
10
|
};
|
|
11
|
-
export declare const NETWORK_PRODUCTS: readonly ["domain", "port", "address", "tunnel"];
|
|
11
|
+
export declare const NETWORK_PRODUCTS: readonly ["domain", "port", "address", "tunnel", "network"];
|
|
12
12
|
export type NetworkProduct = (typeof NETWORK_PRODUCTS)[number];
|
|
13
13
|
export declare const NETWORK_HELP: Record<NetworkProduct, string>;
|
|
14
14
|
export declare function networkProductCommand(product: NetworkProduct, argv: string[], args: Args, out: Out, client: () => Promise<Runtime>): Promise<number>;
|
package/dist/network-cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { chmod, writeFile } from "node:fs/promises";
|
|
2
2
|
import { RuntimeError } from "./errors.js";
|
|
3
|
-
import { named } from "./
|
|
3
|
+
import { named } from "./cli-name.js";
|
|
4
4
|
import { generateWireGuardKeyPair } from "./wireguard.js";
|
|
5
5
|
function fundingState(value) {
|
|
6
6
|
if (value.funded === false)
|
|
@@ -11,7 +11,7 @@ function fundingState(value) {
|
|
|
11
11
|
? `Funded until ${value.fundedUntil}.`
|
|
12
12
|
: "Funding active; no deadline reported.";
|
|
13
13
|
}
|
|
14
|
-
export const NETWORK_PRODUCTS = ["domain", "port", "address", "tunnel"];
|
|
14
|
+
export const NETWORK_PRODUCTS = ["domain", "port", "address", "tunnel", "network"];
|
|
15
15
|
export const NETWORK_HELP = {
|
|
16
16
|
domain: `runtime domain <command>
|
|
17
17
|
|
|
@@ -54,6 +54,19 @@ export const NETWORK_HELP = {
|
|
|
54
54
|
A new key; the old one stops working within seconds
|
|
55
55
|
peer rm <peerId> Remove it; its tunnel ends within seconds
|
|
56
56
|
--route: your own ranges behind the peer that sandboxes may reach. Paid accounts only.
|
|
57
|
+
`,
|
|
58
|
+
network: `runtime network <command>
|
|
59
|
+
|
|
60
|
+
upstream-proxy set <http://host:port|https://host:port> [--secret NAME] [--host <host>]...
|
|
61
|
+
Send your sandboxes' outbound connections through your
|
|
62
|
+
own proxy, after Runtime's own rules allow them.
|
|
63
|
+
--secret: one of your secrets, sent as Proxy-Authorization
|
|
64
|
+
(its hosts must name the proxy's host). --host: only
|
|
65
|
+
these destinations (or *.domain) go through it
|
|
66
|
+
upstream-proxy get The proxy in use
|
|
67
|
+
upstream-proxy remove Connections leave directly again
|
|
68
|
+
A proxy that refuses or cannot be reached fails the connection; nothing goes
|
|
69
|
+
around it. Paid accounts only.
|
|
57
70
|
`,
|
|
58
71
|
};
|
|
59
72
|
function usage(product, message) {
|
|
@@ -319,5 +332,54 @@ export async function networkProductCommand(product, argv, args, out, client) {
|
|
|
319
332
|
}
|
|
320
333
|
}
|
|
321
334
|
}
|
|
335
|
+
if (product === "network") {
|
|
336
|
+
if (verb !== "upstream-proxy")
|
|
337
|
+
throw usage(product, `Unknown network command ${verb}.`);
|
|
338
|
+
const upstream = runtime.network.upstreamProxy;
|
|
339
|
+
const describe = (proxy) => [
|
|
340
|
+
`Outbound connections${proxy.hosts?.length ? ` to ${proxy.hosts.join(", ")}` : ""} go through ${proxy.url}.`,
|
|
341
|
+
...(proxy.secret ? [`${proxy.secret} is sent as Proxy-Authorization.`] : []),
|
|
342
|
+
].join("\n");
|
|
343
|
+
switch (rest[0]) {
|
|
344
|
+
case "set": {
|
|
345
|
+
const hosts = args.flags.get("host");
|
|
346
|
+
const secret = flag("secret");
|
|
347
|
+
const saved = await upstream.set({
|
|
348
|
+
url: need(rest[1], "the proxy's url, such as http://proxy.example.com:3128"),
|
|
349
|
+
...(secret ? { secret } : {}),
|
|
350
|
+
...(hosts ? { hosts } : {}),
|
|
351
|
+
});
|
|
352
|
+
print([
|
|
353
|
+
describe(saved),
|
|
354
|
+
saved.enforced
|
|
355
|
+
? "A connection your proxy refuses fails; nothing goes around it."
|
|
356
|
+
: "A host is catching up; running sandboxes use it within a minute.",
|
|
357
|
+
].join("\n"), saved);
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
case "get":
|
|
361
|
+
case undefined: {
|
|
362
|
+
let found;
|
|
363
|
+
try {
|
|
364
|
+
found = await upstream.get();
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
if (!(error instanceof RuntimeError) || error.code !== "not_found")
|
|
368
|
+
throw error;
|
|
369
|
+
print(named("No upstream proxy. Set one: runtime network upstream-proxy set http://proxy.example.com:3128"), null);
|
|
370
|
+
return 0;
|
|
371
|
+
}
|
|
372
|
+
print(describe(found), found);
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
case "remove":
|
|
376
|
+
case "rm": {
|
|
377
|
+
const gone = await upstream.remove();
|
|
378
|
+
print("Connections leave directly again.", gone);
|
|
379
|
+
return 0;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
throw usage(product, "upstream-proxy takes set, get or remove.");
|
|
383
|
+
}
|
|
322
384
|
throw usage(product, `Unknown ${product} command ${verb}.`);
|
|
323
385
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
/** Where to pay for a stablecoin top-up, and whether the payment arrived. */
|
|
3
|
+
export type Topup = {
|
|
4
|
+
/** Poll this until `status` is `paid`. */
|
|
5
|
+
purchaseId: string;
|
|
6
|
+
/** open: waiting for your payment. pending: Stripe saw it and is confirming.
|
|
7
|
+
* paid: the credit is on the account. expired: nothing arrived in time. */
|
|
8
|
+
status: "open" | "pending" | "paid" | "failed" | "expired";
|
|
9
|
+
/** The credit this buys, in dollars, such as "20.00". */
|
|
10
|
+
amountUsd: string;
|
|
11
|
+
/** The exact token amount to send, to six decimals, such as "20.000000".
|
|
12
|
+
* A different amount, token or network cannot be matched or returned
|
|
13
|
+
* automatically. */
|
|
14
|
+
amount: string;
|
|
15
|
+
/** Send before this. */
|
|
16
|
+
payBy: string | null;
|
|
17
|
+
/** Pay on any one of these, with one of its tokens. */
|
|
18
|
+
networks: {
|
|
19
|
+
network: string;
|
|
20
|
+
address: string;
|
|
21
|
+
tokens: {
|
|
22
|
+
currency: string;
|
|
23
|
+
contract: string;
|
|
24
|
+
}[];
|
|
25
|
+
}[];
|
|
26
|
+
};
|
|
27
|
+
export declare function billing(t: Transport): {
|
|
28
|
+
/** Open a stablecoin top-up of `usd` dollars ($10 to $10,000). Pass the
|
|
29
|
+
* same `idempotencyKey` when retrying to get the same top-up back. */
|
|
30
|
+
topup: (input: {
|
|
31
|
+
usd: number;
|
|
32
|
+
}, options?: RequestOptions) => Promise<Topup>;
|
|
33
|
+
/** Read a top-up: whether its payment has arrived. */
|
|
34
|
+
topupStatus: (purchaseId: string, options?: RequestOptions) => Promise<Topup>;
|
|
35
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function billing(t) {
|
|
2
|
+
return {
|
|
3
|
+
/** Open a stablecoin top-up of `usd` dollars ($10 to $10,000). Pass the
|
|
4
|
+
* same `idempotencyKey` when retrying to get the same top-up back. */
|
|
5
|
+
topup: (input, options) => t.json({ method: "POST", path: "/v1/billing/topups", body: input, ...options }),
|
|
6
|
+
/** Read a top-up: whether its payment has arrived. */
|
|
7
|
+
topupStatus: (purchaseId, options) => t.json({
|
|
8
|
+
method: "GET",
|
|
9
|
+
path: `/v1/billing/topups/${encodeURIComponent(purchaseId)}`,
|
|
10
|
+
...options,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
}
|
package/dist/products/index.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ import { images } from "./images.js";
|
|
|
4
4
|
import { sandboxDesktop } from "./desktop.js";
|
|
5
5
|
import { sandboxInterpreter } from "./interpreter.js";
|
|
6
6
|
import { sandboxNetwork } from "./network.js";
|
|
7
|
-
import { addresses, domains, ports, tunnel } from "./network-products.js";
|
|
7
|
+
import { addresses, domains, network, ports, tunnel } from "./network-products.js";
|
|
8
8
|
import { sandboxPreviews } from "./previews.js";
|
|
9
9
|
import { referrals } from "./referrals.js";
|
|
10
|
+
import { billing } from "./billing.js";
|
|
10
11
|
import { audit } from "./audit.js";
|
|
11
12
|
import { sso } from "./sso.js";
|
|
12
13
|
import { switching } from "./switching.js";
|
|
@@ -20,6 +21,7 @@ export declare const clientExtensions: {
|
|
|
20
21
|
images: typeof images;
|
|
21
22
|
volumes: typeof volumes;
|
|
22
23
|
referrals: typeof referrals;
|
|
24
|
+
billing: typeof billing;
|
|
23
25
|
limits: typeof limits;
|
|
24
26
|
switching: typeof switching;
|
|
25
27
|
secrets: typeof secrets;
|
|
@@ -33,6 +35,7 @@ export declare const clientExtensions: {
|
|
|
33
35
|
ports: typeof ports;
|
|
34
36
|
addresses: typeof addresses;
|
|
35
37
|
tunnel: typeof tunnel;
|
|
38
|
+
network: typeof network;
|
|
36
39
|
};
|
|
37
40
|
export declare const sandboxExtensions: {
|
|
38
41
|
interpreter: typeof sandboxInterpreter;
|
package/dist/products/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import { images } from "./images.js";
|
|
|
2
2
|
import { sandboxDesktop } from "./desktop.js";
|
|
3
3
|
import { sandboxInterpreter } from "./interpreter.js";
|
|
4
4
|
import { sandboxNetwork } from "./network.js";
|
|
5
|
-
import { addresses, domains, ports, tunnel } from "./network-products.js";
|
|
5
|
+
import { addresses, domains, network, ports, tunnel } from "./network-products.js";
|
|
6
6
|
import { sandboxPreviews } from "./previews.js";
|
|
7
7
|
import { referrals } from "./referrals.js";
|
|
8
|
+
import { billing } from "./billing.js";
|
|
8
9
|
import { audit } from "./audit.js";
|
|
9
10
|
import { sso } from "./sso.js";
|
|
10
11
|
import { switching } from "./switching.js";
|
|
@@ -33,6 +34,7 @@ export const clientExtensions = {
|
|
|
33
34
|
images,
|
|
34
35
|
volumes,
|
|
35
36
|
referrals,
|
|
37
|
+
billing,
|
|
36
38
|
limits,
|
|
37
39
|
switching,
|
|
38
40
|
secrets,
|
|
@@ -46,6 +48,7 @@ export const clientExtensions = {
|
|
|
46
48
|
ports,
|
|
47
49
|
addresses,
|
|
48
50
|
tunnel,
|
|
51
|
+
network,
|
|
49
52
|
};
|
|
50
53
|
export const sandboxExtensions = {
|
|
51
54
|
interpreter: sandboxInterpreter,
|