withruntime 0.3.1 → 0.5.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/DAYTONA.md +129 -0
- package/E2B.md +146 -0
- package/README.md +84 -12
- package/VERCEL.md +127 -0
- package/dist/ai/index.d.ts +33 -0
- package/dist/ai/index.js +38 -0
- package/dist/claude-agent-sdk/index.d.ts +7 -0
- package/dist/claude-agent-sdk/index.js +65 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +949 -105
- package/dist/client.d.ts +25 -2
- package/dist/client.js +14 -1
- package/dist/credentials.d.ts +10 -0
- package/dist/credentials.js +56 -1
- package/dist/daytona/client.d.ts +44 -0
- package/dist/daytona/client.js +40 -0
- package/dist/daytona/context.d.ts +26 -0
- package/dist/daytona/context.js +22 -0
- package/dist/daytona/daytona.d.ts +185 -0
- package/dist/daytona/daytona.js +416 -0
- package/dist/daytona/errors.d.ts +106 -0
- package/dist/daytona/errors.js +182 -0
- package/dist/daytona/filesystem.d.ts +84 -0
- package/dist/daytona/filesystem.js +206 -0
- package/dist/daytona/git.d.ts +33 -0
- package/dist/daytona/git.js +128 -0
- package/dist/daytona/image.d.ts +45 -0
- package/dist/daytona/image.js +140 -0
- package/dist/daytona/index.d.ts +50 -0
- package/dist/daytona/index.js +50 -0
- package/dist/daytona/process.d.ts +86 -0
- package/dist/daytona/process.js +339 -0
- package/dist/daytona/sandbox.d.ts +196 -0
- package/dist/daytona/sandbox.js +448 -0
- package/dist/e2b/client.d.ts +58 -0
- package/dist/e2b/client.js +66 -0
- package/dist/e2b/code-interpreter.d.ts +144 -0
- package/dist/e2b/code-interpreter.js +244 -0
- package/dist/e2b/commands.d.ts +100 -0
- package/dist/e2b/commands.js +268 -0
- package/dist/e2b/errors.d.ts +72 -0
- package/dist/e2b/errors.js +151 -0
- package/dist/e2b/filesystem.d.ts +82 -0
- package/dist/e2b/filesystem.js +143 -0
- package/dist/e2b/index.d.ts +28 -0
- package/dist/e2b/index.js +61 -0
- package/dist/e2b/sandbox.d.ts +203 -0
- package/dist/e2b/sandbox.js +490 -0
- package/dist/e2b/unsupported.d.ts +19 -0
- package/dist/e2b/unsupported.js +27 -0
- package/dist/errors.d.ts +10 -4
- package/dist/errors.js +26 -6
- package/dist/image-context.d.ts +39 -0
- package/dist/image-context.js +176 -0
- package/dist/index.d.ts +19 -2
- package/dist/index.js +17 -2
- package/dist/keys.d.ts +43 -0
- package/dist/keys.js +196 -0
- package/dist/login.js +27 -6
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +4 -3
- package/dist/openai-agents/index.d.ts +132 -0
- package/dist/openai-agents/index.js +791 -0
- package/dist/products/audit.d.ts +48 -0
- package/dist/products/audit.js +10 -0
- package/dist/products/images.d.ts +113 -7
- package/dist/products/images.js +186 -27
- package/dist/products/index.d.ts +11 -0
- package/dist/products/index.js +17 -1
- package/dist/products/observability.d.ts +186 -0
- package/dist/products/observability.js +117 -0
- package/dist/products/secrets.d.ts +40 -0
- package/dist/products/secrets.js +24 -0
- package/dist/products/switching.d.ts +89 -0
- package/dist/products/switching.js +25 -0
- package/dist/proxy.d.ts +30 -0
- package/dist/proxy.js +178 -0
- package/dist/sandbox.d.ts +30 -2
- package/dist/sandbox.js +101 -1
- package/dist/ssh.d.ts +21 -0
- package/dist/ssh.js +312 -0
- package/dist/tar.d.ts +1 -0
- package/dist/tar.js +4 -4
- package/dist/tools/index.d.ts +62 -0
- package/dist/tools/index.js +180 -0
- package/dist/transport.d.ts +12 -2
- package/dist/transport.js +76 -16
- package/dist/tunnel.d.ts +67 -0
- package/dist/tunnel.js +311 -0
- package/dist/types.d.ts +57 -1
- package/dist/vercel/client.d.ts +40 -0
- package/dist/vercel/client.js +39 -0
- package/dist/vercel/command.d.ts +70 -0
- package/dist/vercel/command.js +148 -0
- package/dist/vercel/errors.d.ts +53 -0
- package/dist/vercel/errors.js +113 -0
- package/dist/vercel/filesystem.d.ts +150 -0
- package/dist/vercel/filesystem.js +248 -0
- package/dist/vercel/index.d.ts +30 -0
- package/dist/vercel/index.js +38 -0
- package/dist/vercel/sandbox.d.ts +317 -0
- package/dist/vercel/sandbox.js +726 -0
- package/dist/vercel/snapshot.d.ts +93 -0
- package/dist/vercel/snapshot.js +123 -0
- package/package.json +69 -5
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Runtime } from "../client.js";
|
|
2
|
+
/** The Runtime sandbox the adapter drives. */
|
|
3
|
+
export type RuntimeSandbox = Awaited<ReturnType<Runtime["sandboxes"]["create"]>>;
|
|
4
|
+
/** What `Sandbox.create` sends to Runtime. */
|
|
5
|
+
export type RuntimeCreate = NonNullable<Parameters<Runtime["sandboxes"]["create"]>[0]>;
|
|
6
|
+
/** Vercel's credentials. A Vercel token is never sent anywhere: only a
|
|
7
|
+
* Runtime key (`rtcloud_...`) given as `token` is used. */
|
|
8
|
+
export interface Credentials {
|
|
9
|
+
token?: string;
|
|
10
|
+
teamId?: string;
|
|
11
|
+
projectId?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Runtime-only options, for code that has been through the switch. The key
|
|
14
|
+
* is `withruntime` because Vercel's own `runtime` field names a Node.js or
|
|
15
|
+
* Python version. */
|
|
16
|
+
export interface WithRuntime {
|
|
17
|
+
/** A Runtime client to use instead of one made from the key. */
|
|
18
|
+
client?: Runtime;
|
|
19
|
+
/** Fields sent as they are with the create, over the adapter's own: for
|
|
20
|
+
* example `{ funding: "trial" }` or `{ memoryMiB: 8192 }`. */
|
|
21
|
+
create?: Partial<RuntimeCreate>;
|
|
22
|
+
}
|
|
23
|
+
/** The key to use: a Runtime key given as `token`, then RUNTIME_API_KEY, then
|
|
24
|
+
* the key `npx withruntime login` saved (undefined lets the Runtime SDK find
|
|
25
|
+
* it). A Vercel token passed as `token` is refused, never sent. */
|
|
26
|
+
export declare function pickKey(token?: string): string | undefined;
|
|
27
|
+
/** The Runtime client for these options: an explicit client, else one per key,
|
|
28
|
+
* made once and reused so its connections stay open. */
|
|
29
|
+
export declare function clientFor(opts?: Credentials & {
|
|
30
|
+
withruntime?: WithRuntime;
|
|
31
|
+
}): Runtime;
|
|
32
|
+
/** Test hook: forget the cached clients. */
|
|
33
|
+
export declare function resetClients(): void;
|
|
34
|
+
export declare function signalOf(opts?: {
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
}): {
|
|
37
|
+
signal: AbortSignal;
|
|
38
|
+
} | {
|
|
39
|
+
signal?: undefined;
|
|
40
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Runtime } from "../client.js";
|
|
2
|
+
import { AuthenticationError } from "./errors.js";
|
|
3
|
+
const env = (name) => typeof process === "undefined" ? undefined : process.env[name];
|
|
4
|
+
const isRuntimeKey = (key) => key.startsWith("rtcloud_");
|
|
5
|
+
const clients = new Map();
|
|
6
|
+
/** The key to use: a Runtime key given as `token`, then RUNTIME_API_KEY, then
|
|
7
|
+
* the key `npx withruntime login` saved (undefined lets the Runtime SDK find
|
|
8
|
+
* it). A Vercel token passed as `token` is refused, never sent. */
|
|
9
|
+
export function pickKey(token) {
|
|
10
|
+
if (token !== undefined && isRuntimeKey(token))
|
|
11
|
+
return token;
|
|
12
|
+
const runtimeKey = env("RUNTIME_API_KEY");
|
|
13
|
+
if (runtimeKey)
|
|
14
|
+
return runtimeKey;
|
|
15
|
+
if (token !== undefined && token !== "")
|
|
16
|
+
throw new AuthenticationError("The token passed is a Vercel token, and it was not sent. Set RUNTIME_API_KEY to a Runtime key " +
|
|
17
|
+
"(https://withruntime.com/account/keys, or run `npx withruntime login`), or pass the Runtime key as token.");
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
/** The Runtime client for these options: an explicit client, else one per key,
|
|
21
|
+
* made once and reused so its connections stay open. */
|
|
22
|
+
export function clientFor(opts = {}) {
|
|
23
|
+
if (opts.withruntime?.client)
|
|
24
|
+
return opts.withruntime.client;
|
|
25
|
+
const key = pickKey(opts.token);
|
|
26
|
+
let client = clients.get(key ?? "");
|
|
27
|
+
if (!client) {
|
|
28
|
+
client = new Runtime(key ? { apiKey: key } : {});
|
|
29
|
+
clients.set(key ?? "", client);
|
|
30
|
+
}
|
|
31
|
+
return client;
|
|
32
|
+
}
|
|
33
|
+
/** Test hook: forget the cached clients. */
|
|
34
|
+
export function resetClients() {
|
|
35
|
+
clients.clear();
|
|
36
|
+
}
|
|
37
|
+
export function signalOf(opts) {
|
|
38
|
+
return opts?.signal ? { signal: opts.signal } : {};
|
|
39
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Process } from "../sandbox.js";
|
|
2
|
+
/** One piece of a command's output, as Vercel's `logs()` yields it. */
|
|
3
|
+
export type LogOutputLine = {
|
|
4
|
+
stream: "stdout" | "stderr";
|
|
5
|
+
data: string;
|
|
6
|
+
};
|
|
7
|
+
/** Cached output from a command, as in Vercel. */
|
|
8
|
+
export interface CommandOutput {
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
}
|
|
12
|
+
export type Signal = "SIGTERM" | "SIGKILL" | "SIGINT" | "SIGHUP" | "SIGQUIT" | "SIGUSR1" | "SIGUSR2" | number;
|
|
13
|
+
/** A command killed by a signal has no exit code on Runtime. One killed at
|
|
14
|
+
* its `timeoutMs` (SIGKILL) reports 137, as a shell does; any other signal
|
|
15
|
+
* reports -1. */
|
|
16
|
+
export declare function exitCodeOf(exitCode: number | null, timedOut: boolean): number;
|
|
17
|
+
type Init = {
|
|
18
|
+
id: string;
|
|
19
|
+
cwd: string;
|
|
20
|
+
startedAt: number;
|
|
21
|
+
sandboxName: string;
|
|
22
|
+
process?: Process;
|
|
23
|
+
lines?: LogOutputLine[];
|
|
24
|
+
};
|
|
25
|
+
/** A command in a sandbox, as Vercel's `Command`. A detached one runs on:
|
|
26
|
+
* `wait()` for its end, `logs()` for its output as it happens. `cmdId` is
|
|
27
|
+
* Runtime's process id. */
|
|
28
|
+
export declare class Command {
|
|
29
|
+
#private;
|
|
30
|
+
exitCode: number | null;
|
|
31
|
+
durationMs?: number;
|
|
32
|
+
protected readonly init: Init;
|
|
33
|
+
constructor(init: Init);
|
|
34
|
+
get cmdId(): string;
|
|
35
|
+
get cwd(): string;
|
|
36
|
+
get startedAt(): number;
|
|
37
|
+
/** The command's output from its start, as it happens:
|
|
38
|
+
* `for await (const log of cmd.logs()) process.stdout.write(log.data)`. */
|
|
39
|
+
logs(opts?: {
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}): AsyncGenerator<LogOutputLine, void, void> & Disposable & {
|
|
42
|
+
close(): void;
|
|
43
|
+
};
|
|
44
|
+
/** Waits for the command to end. */
|
|
45
|
+
wait(params?: {
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
}): Promise<CommandFinished>;
|
|
48
|
+
/** stdout, stderr, or both in the order they were written. For a detached
|
|
49
|
+
* command this waits for it to end. */
|
|
50
|
+
output(stream?: "stdout" | "stderr" | "both", opts?: {
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
}): Promise<string>;
|
|
53
|
+
stdout(opts?: {
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
}): Promise<string>;
|
|
56
|
+
stderr(opts?: {
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}): Promise<string>;
|
|
59
|
+
/** Sends a signal, SIGTERM by default. */
|
|
60
|
+
kill(signal?: Signal, _opts?: {
|
|
61
|
+
abortSignal?: AbortSignal;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/** A command that has ended; `exitCode` is set. */
|
|
65
|
+
export declare class CommandFinished extends Command {
|
|
66
|
+
exitCode: number;
|
|
67
|
+
constructor(init: Init, exitCode: number, durationMs?: number);
|
|
68
|
+
wait(): Promise<CommandFinished>;
|
|
69
|
+
}
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { guard, StreamError, translate } from "./errors.js";
|
|
2
|
+
const SIGNAL_NUMBERS = {
|
|
3
|
+
1: "SIGHUP",
|
|
4
|
+
2: "SIGINT",
|
|
5
|
+
3: "SIGQUIT",
|
|
6
|
+
9: "SIGKILL",
|
|
7
|
+
10: "SIGUSR1",
|
|
8
|
+
12: "SIGUSR2",
|
|
9
|
+
15: "SIGTERM",
|
|
10
|
+
};
|
|
11
|
+
/** A command killed by a signal has no exit code on Runtime. One killed at
|
|
12
|
+
* its `timeoutMs` (SIGKILL) reports 137, as a shell does; any other signal
|
|
13
|
+
* reports -1. */
|
|
14
|
+
export function exitCodeOf(exitCode, timedOut) {
|
|
15
|
+
if (exitCode !== null)
|
|
16
|
+
return exitCode;
|
|
17
|
+
return timedOut ? 137 : -1;
|
|
18
|
+
}
|
|
19
|
+
function join(lines, stream) {
|
|
20
|
+
return lines
|
|
21
|
+
.filter((line) => stream === "both" || line.stream === stream)
|
|
22
|
+
.map((line) => line.data)
|
|
23
|
+
.join("");
|
|
24
|
+
}
|
|
25
|
+
/** A command in a sandbox, as Vercel's `Command`. A detached one runs on:
|
|
26
|
+
* `wait()` for its end, `logs()` for its output as it happens. `cmdId` is
|
|
27
|
+
* Runtime's process id. */
|
|
28
|
+
export class Command {
|
|
29
|
+
exitCode = null;
|
|
30
|
+
durationMs;
|
|
31
|
+
init;
|
|
32
|
+
#finished;
|
|
33
|
+
constructor(init) {
|
|
34
|
+
this.init = init;
|
|
35
|
+
}
|
|
36
|
+
get cmdId() {
|
|
37
|
+
return this.init.id;
|
|
38
|
+
}
|
|
39
|
+
get cwd() {
|
|
40
|
+
return this.init.cwd;
|
|
41
|
+
}
|
|
42
|
+
get startedAt() {
|
|
43
|
+
return this.init.startedAt;
|
|
44
|
+
}
|
|
45
|
+
/** The command's output from its start, as it happens:
|
|
46
|
+
* `for await (const log of cmd.logs()) process.stdout.write(log.data)`. */
|
|
47
|
+
logs(opts = {}) {
|
|
48
|
+
const abort = new AbortController();
|
|
49
|
+
const forward = () => abort.abort();
|
|
50
|
+
opts.signal?.addEventListener("abort", forward, { once: true });
|
|
51
|
+
const lines = this.init.lines;
|
|
52
|
+
const process = this.init.process;
|
|
53
|
+
const sandboxName = this.init.sandboxName;
|
|
54
|
+
async function* read() {
|
|
55
|
+
try {
|
|
56
|
+
if (lines) {
|
|
57
|
+
yield* lines;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
for await (const event of process.output({ signal: abort.signal })) {
|
|
62
|
+
if (event.type === "stdout" || event.type === "stderr")
|
|
63
|
+
yield { stream: event.type, data: event.data };
|
|
64
|
+
if (event.type === "exit")
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (abort.signal.aborted)
|
|
70
|
+
return;
|
|
71
|
+
const translated = translate(error, sandboxName);
|
|
72
|
+
throw translated instanceof Error && translated !== error
|
|
73
|
+
? translated
|
|
74
|
+
: new StreamError("stream_failed", String(error.message ?? error), process.id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
opts.signal?.removeEventListener("abort", forward);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const generator = read();
|
|
82
|
+
return Object.assign(generator, {
|
|
83
|
+
close: () => abort.abort(),
|
|
84
|
+
[Symbol.dispose]: () => abort.abort(),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/** Waits for the command to end. */
|
|
88
|
+
wait(params = {}) {
|
|
89
|
+
this.#finished ??= this.#follow(params);
|
|
90
|
+
return this.#finished;
|
|
91
|
+
}
|
|
92
|
+
async #follow(params) {
|
|
93
|
+
const lines = [];
|
|
94
|
+
let exit;
|
|
95
|
+
await guard(async () => {
|
|
96
|
+
for await (const event of this.init.process.output(params.signal ? { signal: params.signal } : {})) {
|
|
97
|
+
if (event.type === "stdout" || event.type === "stderr")
|
|
98
|
+
lines.push({ stream: event.type, data: event.data });
|
|
99
|
+
else if (event.type === "exit")
|
|
100
|
+
exit = {
|
|
101
|
+
exitCode: event.exitCode,
|
|
102
|
+
timedOut: event.timedOut,
|
|
103
|
+
...(event.durationMs === undefined ? {} : { durationMs: event.durationMs }),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}, this.init.sandboxName);
|
|
107
|
+
if (!exit)
|
|
108
|
+
throw new StreamError("stream_ended", "The command's output ended before it exited.", this.init.process.id);
|
|
109
|
+
this.exitCode = exitCodeOf(exit.exitCode, exit.timedOut);
|
|
110
|
+
if (exit.durationMs !== undefined)
|
|
111
|
+
this.durationMs = exit.durationMs;
|
|
112
|
+
return new CommandFinished({ ...this.init, lines }, this.exitCode, exit.durationMs ?? undefined);
|
|
113
|
+
}
|
|
114
|
+
/** stdout, stderr, or both in the order they were written. For a detached
|
|
115
|
+
* command this waits for it to end. */
|
|
116
|
+
async output(stream = "both", opts = {}) {
|
|
117
|
+
if (this.init.lines)
|
|
118
|
+
return join(this.init.lines, stream);
|
|
119
|
+
return (await this.wait(opts)).output(stream);
|
|
120
|
+
}
|
|
121
|
+
stdout(opts = {}) {
|
|
122
|
+
return this.output("stdout", opts);
|
|
123
|
+
}
|
|
124
|
+
stderr(opts = {}) {
|
|
125
|
+
return this.output("stderr", opts);
|
|
126
|
+
}
|
|
127
|
+
/** Sends a signal, SIGTERM by default. */
|
|
128
|
+
async kill(signal = "SIGTERM", _opts = {}) {
|
|
129
|
+
if (!this.init.process)
|
|
130
|
+
return;
|
|
131
|
+
const name = typeof signal === "number" ? SIGNAL_NUMBERS[signal] : signal;
|
|
132
|
+
if (!name)
|
|
133
|
+
throw new RangeError(`Signal ${signal} has no name Runtime knows; use SIGTERM, SIGKILL, SIGINT, SIGHUP, SIGQUIT, SIGUSR1 or SIGUSR2.`);
|
|
134
|
+
await guard(() => this.init.process.kill(name), this.init.sandboxName);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** A command that has ended; `exitCode` is set. */
|
|
138
|
+
export class CommandFinished extends Command {
|
|
139
|
+
constructor(init, exitCode, durationMs) {
|
|
140
|
+
super(init);
|
|
141
|
+
this.exitCode = exitCode;
|
|
142
|
+
if (durationMs !== undefined)
|
|
143
|
+
this.durationMs = durationMs;
|
|
144
|
+
}
|
|
145
|
+
wait() {
|
|
146
|
+
return Promise.resolve(this);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
interface Options<ErrorData> {
|
|
2
|
+
message?: string;
|
|
3
|
+
json?: ErrorData;
|
|
4
|
+
text?: string;
|
|
5
|
+
sandboxName?: string;
|
|
6
|
+
sessionId?: string;
|
|
7
|
+
}
|
|
8
|
+
/** An error answer from the API. `response.status` is the HTTP status, and
|
|
9
|
+
* `json` is `{ error: { code, message } }` as Vercel's is. */
|
|
10
|
+
export declare class APIError<ErrorData = unknown> extends Error {
|
|
11
|
+
response: Response;
|
|
12
|
+
json?: ErrorData;
|
|
13
|
+
text?: string;
|
|
14
|
+
sandboxName?: string;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
code?: string;
|
|
17
|
+
hint?: string;
|
|
18
|
+
requestId?: string;
|
|
19
|
+
constructor(response: Response, options?: Options<ErrorData>);
|
|
20
|
+
}
|
|
21
|
+
/** A command's output stream failed, as Vercel's StreamError. */
|
|
22
|
+
export declare class StreamError extends Error {
|
|
23
|
+
code: string;
|
|
24
|
+
sessionId: string;
|
|
25
|
+
constructor(code: string, message: string, sessionId: string);
|
|
26
|
+
}
|
|
27
|
+
/** A Vercel token was given where a Runtime key is needed. */
|
|
28
|
+
export declare class AuthenticationError extends Error {
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
/** A call that Vercel Sandbox supports and Runtime does not, or not in the
|
|
32
|
+
* same way. Thrown before anything is done, never after doing something
|
|
33
|
+
* different. `feature` names what was asked for; `alternative` says what to
|
|
34
|
+
* use on Runtime instead. */
|
|
35
|
+
export declare class NotSupportedError extends Error {
|
|
36
|
+
readonly code = "not_supported";
|
|
37
|
+
readonly feature: string;
|
|
38
|
+
readonly alternative: string;
|
|
39
|
+
constructor(feature: string, alternative: string, message?: string);
|
|
40
|
+
}
|
|
41
|
+
/** A Runtime SDK error as Vercel's APIError, or NotSupportedError for a
|
|
42
|
+
* product Runtime has switched off. Anything else passes through unchanged. */
|
|
43
|
+
export declare function translate(error: unknown, sandboxName?: string): unknown;
|
|
44
|
+
/** Runs `work`, turning any Runtime error into Vercel's. */
|
|
45
|
+
export declare function guard<T>(work: () => Promise<T>, sandboxName?: string): Promise<T>;
|
|
46
|
+
/** A node:fs-style error, as Vercel's `sandbox.fs` throws. */
|
|
47
|
+
export declare function fsError(code: "ENOENT" | "EEXIST" | "EISDIR" | "ENOTDIR", syscall: string, path: string): Error & {
|
|
48
|
+
code: "ENOENT" | "EEXIST" | "EISDIR" | "ENOTDIR";
|
|
49
|
+
errno: number;
|
|
50
|
+
syscall: string;
|
|
51
|
+
path: string;
|
|
52
|
+
};
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
2
|
+
/** An error answer from the API. `response.status` is the HTTP status, and
|
|
3
|
+
* `json` is `{ error: { code, message } }` as Vercel's is. */
|
|
4
|
+
export class APIError extends Error {
|
|
5
|
+
response;
|
|
6
|
+
json;
|
|
7
|
+
text;
|
|
8
|
+
sandboxName;
|
|
9
|
+
sessionId;
|
|
10
|
+
code;
|
|
11
|
+
hint;
|
|
12
|
+
requestId;
|
|
13
|
+
constructor(response, options = {}) {
|
|
14
|
+
super(options.message ?? `Status code ${response.status} is not ok`);
|
|
15
|
+
this.name = new.target.name;
|
|
16
|
+
this.response = response;
|
|
17
|
+
if (options.json !== undefined)
|
|
18
|
+
this.json = options.json;
|
|
19
|
+
if (options.text !== undefined)
|
|
20
|
+
this.text = options.text;
|
|
21
|
+
if (options.sandboxName !== undefined)
|
|
22
|
+
this.sandboxName = options.sandboxName;
|
|
23
|
+
if (options.sessionId !== undefined)
|
|
24
|
+
this.sessionId = options.sessionId;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** A command's output stream failed, as Vercel's StreamError. */
|
|
28
|
+
export class StreamError extends Error {
|
|
29
|
+
code;
|
|
30
|
+
sessionId;
|
|
31
|
+
constructor(code, message, sessionId) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = new.target.name;
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.sessionId = sessionId;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** A Vercel token was given where a Runtime key is needed. */
|
|
39
|
+
export class AuthenticationError extends Error {
|
|
40
|
+
constructor(message) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.name = new.target.name;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** A call that Vercel Sandbox supports and Runtime does not, or not in the
|
|
46
|
+
* same way. Thrown before anything is done, never after doing something
|
|
47
|
+
* different. `feature` names what was asked for; `alternative` says what to
|
|
48
|
+
* use on Runtime instead. */
|
|
49
|
+
export class NotSupportedError extends Error {
|
|
50
|
+
code = "not_supported";
|
|
51
|
+
feature;
|
|
52
|
+
alternative;
|
|
53
|
+
constructor(feature, alternative, message) {
|
|
54
|
+
super(message ?? `${feature} is not supported on Runtime. ${alternative}`);
|
|
55
|
+
this.name = new.target.name;
|
|
56
|
+
this.feature = feature;
|
|
57
|
+
this.alternative = alternative;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** A Runtime SDK error as Vercel's APIError, or NotSupportedError for a
|
|
61
|
+
* product Runtime has switched off. Anything else passes through unchanged. */
|
|
62
|
+
export function translate(error, sandboxName) {
|
|
63
|
+
if (!(error instanceof RuntimeError))
|
|
64
|
+
return error;
|
|
65
|
+
const message = [
|
|
66
|
+
error.message,
|
|
67
|
+
error.hint ? `Hint: ${error.hint}` : "",
|
|
68
|
+
error.requestId ? `Request: ${error.requestId}` : "",
|
|
69
|
+
]
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.join("\n");
|
|
72
|
+
if (error.status === 503 && error.code.endsWith("_unavailable"))
|
|
73
|
+
return new NotSupportedError(error.code.replace(/_unavailable$/, ""), error.hint ?? "", message);
|
|
74
|
+
if (error.status < 200 || error.status > 599)
|
|
75
|
+
return error;
|
|
76
|
+
const json = { error: { code: error.code, message: error.message } };
|
|
77
|
+
const out = new APIError(new Response(JSON.stringify(json), {
|
|
78
|
+
status: error.status,
|
|
79
|
+
headers: { "content-type": "application/json" },
|
|
80
|
+
}), { message, json, text: JSON.stringify(json), ...(sandboxName ? { sandboxName } : {}) });
|
|
81
|
+
out.code = error.code;
|
|
82
|
+
if (error.hint)
|
|
83
|
+
out.hint = error.hint;
|
|
84
|
+
if (error.requestId)
|
|
85
|
+
out.requestId = error.requestId;
|
|
86
|
+
out.cause = error;
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
/** Runs `work`, turning any Runtime error into Vercel's. */
|
|
90
|
+
export async function guard(work, sandboxName) {
|
|
91
|
+
try {
|
|
92
|
+
return await work();
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw translate(error, sandboxName);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** A node:fs-style error, as Vercel's `sandbox.fs` throws. */
|
|
99
|
+
export function fsError(code, syscall, path) {
|
|
100
|
+
const text = {
|
|
101
|
+
ENOENT: "no such file or directory",
|
|
102
|
+
EEXIST: "file already exists",
|
|
103
|
+
EISDIR: "illegal operation on a directory",
|
|
104
|
+
ENOTDIR: "not a directory",
|
|
105
|
+
}[code];
|
|
106
|
+
const errno = { ENOENT: -2, EEXIST: -17, EISDIR: -21, ENOTDIR: -20 }[code];
|
|
107
|
+
return Object.assign(new Error(`${code}: ${text}, ${syscall} '${path}'`), {
|
|
108
|
+
code,
|
|
109
|
+
errno,
|
|
110
|
+
syscall,
|
|
111
|
+
path,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { Files } from "../sandbox.js";
|
|
2
|
+
import type { FileEntry } from "../types.js";
|
|
3
|
+
/** What `sandbox.fs` needs from its sandbox. */
|
|
4
|
+
export interface FsContext {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
files(): Promise<Files>;
|
|
7
|
+
/** Runs argv without a shell; resolves with the exit code and output. */
|
|
8
|
+
run(argv: string[]): Promise<{
|
|
9
|
+
exitCode: number | null;
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
}>;
|
|
13
|
+
resolve(path: string, cwd?: string): string;
|
|
14
|
+
}
|
|
15
|
+
type WriteFileData = string | Uint8Array;
|
|
16
|
+
type Encoding = "utf8" | "utf-8" | "ascii" | "latin1" | "base64" | "hex" | "binary";
|
|
17
|
+
/** Node's Stats, as far as a sandbox file can answer. uid, gid, ino and the
|
|
18
|
+
* other inode fields are 0. */
|
|
19
|
+
export declare class Stats {
|
|
20
|
+
#private;
|
|
21
|
+
readonly size: number;
|
|
22
|
+
readonly mode: number;
|
|
23
|
+
readonly mtime: Date;
|
|
24
|
+
readonly mtimeMs: number;
|
|
25
|
+
readonly atime: Date;
|
|
26
|
+
readonly atimeMs: number;
|
|
27
|
+
readonly ctime: Date;
|
|
28
|
+
readonly ctimeMs: number;
|
|
29
|
+
readonly birthtime: Date;
|
|
30
|
+
readonly birthtimeMs: number;
|
|
31
|
+
readonly uid = 0;
|
|
32
|
+
readonly gid = 0;
|
|
33
|
+
readonly dev = 0;
|
|
34
|
+
readonly ino = 0;
|
|
35
|
+
readonly nlink = 1;
|
|
36
|
+
readonly rdev = 0;
|
|
37
|
+
readonly blksize = 4096;
|
|
38
|
+
readonly blocks: number;
|
|
39
|
+
constructor(entry: FileEntry);
|
|
40
|
+
isFile(): boolean;
|
|
41
|
+
isDirectory(): boolean;
|
|
42
|
+
isSymbolicLink(): boolean;
|
|
43
|
+
isBlockDevice(): boolean;
|
|
44
|
+
isCharacterDevice(): boolean;
|
|
45
|
+
isFIFO(): boolean;
|
|
46
|
+
isSocket(): boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Node's Dirent, from a sandbox listing. */
|
|
49
|
+
export declare class Dirent {
|
|
50
|
+
#private;
|
|
51
|
+
readonly name: string;
|
|
52
|
+
readonly parentPath: string;
|
|
53
|
+
readonly path: string;
|
|
54
|
+
constructor(entry: FileEntry, parent: string);
|
|
55
|
+
isFile(): boolean;
|
|
56
|
+
isDirectory(): boolean;
|
|
57
|
+
isSymbolicLink(): boolean;
|
|
58
|
+
isBlockDevice(): boolean;
|
|
59
|
+
isCharacterDevice(): boolean;
|
|
60
|
+
isFIFO(): boolean;
|
|
61
|
+
isSocket(): boolean;
|
|
62
|
+
}
|
|
63
|
+
/** `sandbox.fs`: node:fs/promises over Runtime's files API and a few
|
|
64
|
+
* commands. Relative paths resolve against the sandbox's working directory,
|
|
65
|
+
* `/vercel/sandbox`, which is `/workspace` on Runtime. Errors carry Node's
|
|
66
|
+
* codes: `ENOENT` for a missing path. */
|
|
67
|
+
export declare class FileSystem {
|
|
68
|
+
#private;
|
|
69
|
+
constructor(ctx: FsContext);
|
|
70
|
+
readFile(path: string, options?: {
|
|
71
|
+
encoding?: null;
|
|
72
|
+
signal?: AbortSignal;
|
|
73
|
+
} | null): Promise<Buffer>;
|
|
74
|
+
readFile(path: string, options: {
|
|
75
|
+
encoding: Encoding;
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
} | Encoding): Promise<string>;
|
|
78
|
+
writeFile(path: string, data: WriteFileData, options?: {
|
|
79
|
+
encoding?: Encoding;
|
|
80
|
+
signal?: AbortSignal;
|
|
81
|
+
} | Encoding): Promise<void>;
|
|
82
|
+
appendFile(path: string, data: WriteFileData, options?: {
|
|
83
|
+
encoding?: Encoding;
|
|
84
|
+
signal?: AbortSignal;
|
|
85
|
+
} | Encoding): Promise<void>;
|
|
86
|
+
mkdir(path: string, options?: {
|
|
87
|
+
recursive?: boolean;
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
} | number): Promise<string | undefined>;
|
|
90
|
+
readdir(path: string, options?: {
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
withFileTypes?: false;
|
|
93
|
+
}): Promise<string[]>;
|
|
94
|
+
readdir(path: string, options: {
|
|
95
|
+
signal?: AbortSignal;
|
|
96
|
+
withFileTypes: true;
|
|
97
|
+
}): Promise<Dirent[]>;
|
|
98
|
+
lstat(path: string, _options?: {
|
|
99
|
+
signal?: AbortSignal;
|
|
100
|
+
}): Promise<Stats>;
|
|
101
|
+
/** Follows symbolic links. */
|
|
102
|
+
stat(path: string, options?: {
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
}): Promise<Stats>;
|
|
105
|
+
unlink(path: string, _options?: {
|
|
106
|
+
signal?: AbortSignal;
|
|
107
|
+
}): Promise<void>;
|
|
108
|
+
rm(path: string, options?: {
|
|
109
|
+
recursive?: boolean;
|
|
110
|
+
force?: boolean;
|
|
111
|
+
signal?: AbortSignal;
|
|
112
|
+
}): Promise<void>;
|
|
113
|
+
rmdir(path: string, _options?: {
|
|
114
|
+
signal?: AbortSignal;
|
|
115
|
+
}): Promise<void>;
|
|
116
|
+
rename(oldPath: string, newPath: string, _options?: {
|
|
117
|
+
signal?: AbortSignal;
|
|
118
|
+
}): Promise<void>;
|
|
119
|
+
copyFile(src: string, dest: string, _options?: {
|
|
120
|
+
signal?: AbortSignal;
|
|
121
|
+
}): Promise<void>;
|
|
122
|
+
access(path: string, _options?: {
|
|
123
|
+
signal?: AbortSignal;
|
|
124
|
+
}): Promise<void>;
|
|
125
|
+
exists(path: string, _options?: {
|
|
126
|
+
signal?: AbortSignal;
|
|
127
|
+
}): Promise<boolean>;
|
|
128
|
+
chmod(path: string, mode: number | string, _options?: {
|
|
129
|
+
signal?: AbortSignal;
|
|
130
|
+
}): Promise<void>;
|
|
131
|
+
chown(path: string, uid: number, gid: number, _options?: {
|
|
132
|
+
signal?: AbortSignal;
|
|
133
|
+
}): Promise<void>;
|
|
134
|
+
symlink(target: string, path: string, _options?: {
|
|
135
|
+
signal?: AbortSignal;
|
|
136
|
+
}): Promise<void>;
|
|
137
|
+
readlink(path: string, _options?: {
|
|
138
|
+
signal?: AbortSignal;
|
|
139
|
+
}): Promise<string>;
|
|
140
|
+
realpath(path: string, _options?: {
|
|
141
|
+
signal?: AbortSignal;
|
|
142
|
+
}): Promise<string>;
|
|
143
|
+
truncate(path: string, len?: number, _options?: {
|
|
144
|
+
signal?: AbortSignal;
|
|
145
|
+
}): Promise<void>;
|
|
146
|
+
mkdtemp(prefix: string, _options?: {
|
|
147
|
+
signal?: AbortSignal;
|
|
148
|
+
}): Promise<string>;
|
|
149
|
+
}
|
|
150
|
+
export {};
|