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,248 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
2
|
+
import { fsError, translate } from "./errors.js";
|
|
3
|
+
/** Node's Stats, as far as a sandbox file can answer. uid, gid, ino and the
|
|
4
|
+
* other inode fields are 0. */
|
|
5
|
+
export class Stats {
|
|
6
|
+
size;
|
|
7
|
+
mode;
|
|
8
|
+
mtime;
|
|
9
|
+
mtimeMs;
|
|
10
|
+
atime;
|
|
11
|
+
atimeMs;
|
|
12
|
+
ctime;
|
|
13
|
+
ctimeMs;
|
|
14
|
+
birthtime;
|
|
15
|
+
birthtimeMs;
|
|
16
|
+
uid = 0;
|
|
17
|
+
gid = 0;
|
|
18
|
+
dev = 0;
|
|
19
|
+
ino = 0;
|
|
20
|
+
nlink = 1;
|
|
21
|
+
rdev = 0;
|
|
22
|
+
blksize = 4096;
|
|
23
|
+
blocks;
|
|
24
|
+
#type;
|
|
25
|
+
constructor(entry) {
|
|
26
|
+
this.#type = entry.type;
|
|
27
|
+
this.size = entry.size;
|
|
28
|
+
const typeBits = entry.type === "directory" ? 0o040000 : entry.type === "symlink" ? 0o120000 : 0o100000;
|
|
29
|
+
this.mode = typeBits | ((parseInt(entry.mode, 8) || 0) & 0o7777);
|
|
30
|
+
this.mtime = this.atime = this.ctime = this.birthtime = new Date(entry.modifiedAt);
|
|
31
|
+
this.mtimeMs = this.atimeMs = this.ctimeMs = this.birthtimeMs = this.mtime.getTime();
|
|
32
|
+
this.blocks = Math.ceil(entry.size / 512);
|
|
33
|
+
}
|
|
34
|
+
isFile() {
|
|
35
|
+
return this.#type === "file";
|
|
36
|
+
}
|
|
37
|
+
isDirectory() {
|
|
38
|
+
return this.#type === "directory";
|
|
39
|
+
}
|
|
40
|
+
isSymbolicLink() {
|
|
41
|
+
return this.#type === "symlink";
|
|
42
|
+
}
|
|
43
|
+
isBlockDevice() {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
isCharacterDevice() {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
isFIFO() {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
isSocket() {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Node's Dirent, from a sandbox listing. */
|
|
57
|
+
export class Dirent {
|
|
58
|
+
name;
|
|
59
|
+
parentPath;
|
|
60
|
+
path;
|
|
61
|
+
#type;
|
|
62
|
+
constructor(entry, parent) {
|
|
63
|
+
this.name = entry.name;
|
|
64
|
+
this.parentPath = this.path = parent;
|
|
65
|
+
this.#type = entry.type;
|
|
66
|
+
}
|
|
67
|
+
isFile() {
|
|
68
|
+
return this.#type === "file";
|
|
69
|
+
}
|
|
70
|
+
isDirectory() {
|
|
71
|
+
return this.#type === "directory";
|
|
72
|
+
}
|
|
73
|
+
isSymbolicLink() {
|
|
74
|
+
return this.#type === "symlink";
|
|
75
|
+
}
|
|
76
|
+
isBlockDevice() {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
isCharacterDevice() {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
isFIFO() {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
isSocket() {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const encodingOf = (options) => typeof options === "string" ? options : (options?.encoding ?? null);
|
|
90
|
+
const bytesOf = (data, encoding) => typeof data === "string" ? Buffer.from(data, encoding ?? "utf8") : Buffer.from(data);
|
|
91
|
+
function missing(error) {
|
|
92
|
+
return error instanceof RuntimeError && (error.code === "file_not_found" || error.status === 404);
|
|
93
|
+
}
|
|
94
|
+
/** `sandbox.fs`: node:fs/promises over Runtime's files API and a few
|
|
95
|
+
* commands. Relative paths resolve against the sandbox's working directory,
|
|
96
|
+
* `/vercel/sandbox`, which is `/workspace` on Runtime. Errors carry Node's
|
|
97
|
+
* codes: `ENOENT` for a missing path. */
|
|
98
|
+
export class FileSystem {
|
|
99
|
+
#ctx;
|
|
100
|
+
constructor(ctx) {
|
|
101
|
+
this.#ctx = ctx;
|
|
102
|
+
}
|
|
103
|
+
async #call(syscall, path, work) {
|
|
104
|
+
try {
|
|
105
|
+
return await work();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (missing(error))
|
|
109
|
+
throw fsError("ENOENT", syscall, path);
|
|
110
|
+
throw translate(error, this.#ctx.name);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Runs a coreutils command; a failure is a Node-style error. */
|
|
114
|
+
async #run(syscall, path, argv) {
|
|
115
|
+
const result = await this.#call(syscall, path, () => this.#ctx.run(argv));
|
|
116
|
+
if (result.exitCode === 0)
|
|
117
|
+
return result.stdout;
|
|
118
|
+
if (/No such file or directory/.test(result.stderr))
|
|
119
|
+
throw fsError("ENOENT", syscall, path);
|
|
120
|
+
if (/File exists/.test(result.stderr))
|
|
121
|
+
throw fsError("EEXIST", syscall, path);
|
|
122
|
+
if (/Is a directory/.test(result.stderr))
|
|
123
|
+
throw fsError("EISDIR", syscall, path);
|
|
124
|
+
if (/Not a directory/.test(result.stderr))
|
|
125
|
+
throw fsError("ENOTDIR", syscall, path);
|
|
126
|
+
throw Object.assign(new Error(`${syscall} '${path}' failed: ${result.stderr.trim()}`), {
|
|
127
|
+
code: "EIO",
|
|
128
|
+
syscall,
|
|
129
|
+
path,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async readFile(path, options) {
|
|
133
|
+
const target = this.#ctx.resolve(path);
|
|
134
|
+
const files = await this.#ctx.files();
|
|
135
|
+
const bytes = await this.#call("open", target, () => files.read(target, typeof options === "object" && options?.signal ? { signal: options.signal } : {}));
|
|
136
|
+
const encoding = encodingOf(options);
|
|
137
|
+
const buffer = Buffer.from(bytes);
|
|
138
|
+
return encoding ? buffer.toString(encoding) : buffer;
|
|
139
|
+
}
|
|
140
|
+
async writeFile(path, data, options) {
|
|
141
|
+
const target = this.#ctx.resolve(path);
|
|
142
|
+
const files = await this.#ctx.files();
|
|
143
|
+
await this.#call("open", target, () => files.write(target, bytesOf(data, encodingOf(options))));
|
|
144
|
+
}
|
|
145
|
+
async appendFile(path, data, options) {
|
|
146
|
+
const target = this.#ctx.resolve(path);
|
|
147
|
+
const files = await this.#ctx.files();
|
|
148
|
+
const before = await files.read(target).catch((error) => {
|
|
149
|
+
if (missing(error))
|
|
150
|
+
return new Uint8Array();
|
|
151
|
+
throw translate(error, this.#ctx.name);
|
|
152
|
+
});
|
|
153
|
+
await this.#call("open", target, () => files.write(target, Buffer.concat([before, bytesOf(data, encodingOf(options))])));
|
|
154
|
+
}
|
|
155
|
+
async mkdir(path, options) {
|
|
156
|
+
const target = this.#ctx.resolve(path);
|
|
157
|
+
const recursive = typeof options === "object" && options.recursive === true;
|
|
158
|
+
await this.#run("mkdir", target, recursive ? ["mkdir", "-p", target] : ["mkdir", target]);
|
|
159
|
+
return recursive ? target : undefined;
|
|
160
|
+
}
|
|
161
|
+
async readdir(path, options = {}) {
|
|
162
|
+
const target = this.#ctx.resolve(path);
|
|
163
|
+
const files = await this.#ctx.files();
|
|
164
|
+
const entries = await this.#call("scandir", target, () => files.list(target, { depth: 1, hidden: true }));
|
|
165
|
+
return options.withFileTypes
|
|
166
|
+
? entries.map((entry) => new Dirent(entry, target))
|
|
167
|
+
: entries.map((entry) => entry.name);
|
|
168
|
+
}
|
|
169
|
+
async lstat(path, _options = {}) {
|
|
170
|
+
const target = this.#ctx.resolve(path);
|
|
171
|
+
const files = await this.#ctx.files();
|
|
172
|
+
const found = await this.#call("lstat", target, () => files.stat(target));
|
|
173
|
+
if (!found.exists)
|
|
174
|
+
throw fsError("ENOENT", "lstat", target);
|
|
175
|
+
return new Stats(found);
|
|
176
|
+
}
|
|
177
|
+
/** Follows symbolic links. */
|
|
178
|
+
async stat(path, options = {}) {
|
|
179
|
+
const target = this.#ctx.resolve(path);
|
|
180
|
+
const first = await this.lstat(target, options);
|
|
181
|
+
if (!first.isSymbolicLink())
|
|
182
|
+
return first;
|
|
183
|
+
return this.lstat(await this.realpath(target), options);
|
|
184
|
+
}
|
|
185
|
+
async unlink(path, _options = {}) {
|
|
186
|
+
const target = this.#ctx.resolve(path);
|
|
187
|
+
await this.#run("unlink", target, ["rm", "--", target]);
|
|
188
|
+
}
|
|
189
|
+
async rm(path, options = {}) {
|
|
190
|
+
const target = this.#ctx.resolve(path);
|
|
191
|
+
const flags = `${options.recursive ? "r" : ""}${options.force ? "f" : ""}`;
|
|
192
|
+
await this.#run("rm", target, flags ? ["rm", `-${flags}`, "--", target] : ["rm", "--", target]);
|
|
193
|
+
}
|
|
194
|
+
async rmdir(path, _options = {}) {
|
|
195
|
+
const target = this.#ctx.resolve(path);
|
|
196
|
+
await this.#run("rmdir", target, ["rmdir", "--", target]);
|
|
197
|
+
}
|
|
198
|
+
async rename(oldPath, newPath, _options = {}) {
|
|
199
|
+
const from = this.#ctx.resolve(oldPath);
|
|
200
|
+
const to = this.#ctx.resolve(newPath);
|
|
201
|
+
const files = await this.#ctx.files();
|
|
202
|
+
await this.#call("rename", from, () => files.rename(from, to, { overwrite: true }));
|
|
203
|
+
}
|
|
204
|
+
async copyFile(src, dest, _options = {}) {
|
|
205
|
+
const from = this.#ctx.resolve(src);
|
|
206
|
+
const to = this.#ctx.resolve(dest);
|
|
207
|
+
await this.#run("copyfile", from, ["cp", "--", from, to]);
|
|
208
|
+
}
|
|
209
|
+
async access(path, _options = {}) {
|
|
210
|
+
const target = this.#ctx.resolve(path);
|
|
211
|
+
if (!(await this.exists(target)))
|
|
212
|
+
throw fsError("ENOENT", "access", target);
|
|
213
|
+
}
|
|
214
|
+
async exists(path, _options = {}) {
|
|
215
|
+
const target = this.#ctx.resolve(path);
|
|
216
|
+
const files = await this.#ctx.files();
|
|
217
|
+
return this.#call("access", target, () => files.exists(target));
|
|
218
|
+
}
|
|
219
|
+
async chmod(path, mode, _options = {}) {
|
|
220
|
+
const target = this.#ctx.resolve(path);
|
|
221
|
+
const octal = typeof mode === "number" ? mode.toString(8) : mode;
|
|
222
|
+
await this.#run("chmod", target, ["chmod", octal, "--", target]);
|
|
223
|
+
}
|
|
224
|
+
async chown(path, uid, gid, _options = {}) {
|
|
225
|
+
const target = this.#ctx.resolve(path);
|
|
226
|
+
await this.#run("chown", target, ["sudo", "chown", `${uid}:${gid}`, "--", target]);
|
|
227
|
+
}
|
|
228
|
+
async symlink(target, path, _options = {}) {
|
|
229
|
+
const link = this.#ctx.resolve(path);
|
|
230
|
+
await this.#run("symlink", link, ["ln", "-s", "--", target, link]);
|
|
231
|
+
}
|
|
232
|
+
async readlink(path, _options = {}) {
|
|
233
|
+
const target = this.#ctx.resolve(path);
|
|
234
|
+
return (await this.#run("readlink", target, ["readlink", "--", target])).replace(/\n$/, "");
|
|
235
|
+
}
|
|
236
|
+
async realpath(path, _options = {}) {
|
|
237
|
+
const target = this.#ctx.resolve(path);
|
|
238
|
+
return (await this.#run("realpath", target, ["realpath", "-e", "--", target])).replace(/\n$/, "");
|
|
239
|
+
}
|
|
240
|
+
async truncate(path, len = 0, _options = {}) {
|
|
241
|
+
const target = this.#ctx.resolve(path);
|
|
242
|
+
await this.#run("open", target, ["truncate", "-s", String(len), "--", target]);
|
|
243
|
+
}
|
|
244
|
+
async mkdtemp(prefix, _options = {}) {
|
|
245
|
+
const base = this.#ctx.resolve(prefix);
|
|
246
|
+
return (await this.#run("mkdtemp", base, ["mktemp", "-d", `${base}XXXXXX`])).replace(/\n$/, "");
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { Sandbox, DEFAULT_TIMEOUT_MS, DEFAULT_VCPUS, MEMORY_MIB_PER_VCPU, networkRules, toRuntimePath, type CreateSandboxParams, type RunCommandParams, type NetworkPolicy, type SandboxRoute, } from "./sandbox.js";
|
|
2
|
+
export { Command, CommandFinished, type CommandOutput, type LogOutputLine, type Signal, } from "./command.js";
|
|
3
|
+
export { FileSystem, Stats, Dirent } from "./filesystem.js";
|
|
4
|
+
export { Snapshot } from "./snapshot.js";
|
|
5
|
+
export { APIError, StreamError, AuthenticationError, NotSupportedError } from "./errors.js";
|
|
6
|
+
export type { Credentials, WithRuntime } from "./client.js";
|
|
7
|
+
/** Vercel's default region; Runtime runs in one US region. */
|
|
8
|
+
export declare const DEFAULT_SANDBOX_REGION = "iad1";
|
|
9
|
+
export declare const Drive: {
|
|
10
|
+
(...args: unknown[]): never;
|
|
11
|
+
new (...args: unknown[]): never;
|
|
12
|
+
readonly [key: string]: (...args: unknown[]) => never;
|
|
13
|
+
};
|
|
14
|
+
export declare const Session: {
|
|
15
|
+
(...args: unknown[]): never;
|
|
16
|
+
new (...args: unknown[]): never;
|
|
17
|
+
readonly [key: string]: (...args: unknown[]) => never;
|
|
18
|
+
};
|
|
19
|
+
export declare const SandboxUser: {
|
|
20
|
+
(...args: unknown[]): never;
|
|
21
|
+
new (...args: unknown[]): never;
|
|
22
|
+
readonly [key: string]: (...args: unknown[]) => never;
|
|
23
|
+
};
|
|
24
|
+
export declare class SandboxUserAlreadyExistsError extends Error {
|
|
25
|
+
}
|
|
26
|
+
export declare const defineSandboxProxy: {
|
|
27
|
+
(...args: unknown[]): never;
|
|
28
|
+
new (...args: unknown[]): never;
|
|
29
|
+
readonly [key: string]: (...args: unknown[]) => never;
|
|
30
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Code written for Vercel Sandbox's SDK, on Runtime Cloud. Change the import:
|
|
2
|
+
*
|
|
3
|
+
* import { Sandbox } from "withruntime/vercel"; // was: from "@vercel/sandbox"
|
|
4
|
+
*
|
|
5
|
+
* and set RUNTIME_API_KEY, or run `npx withruntime login` once. A Vercel token
|
|
6
|
+
* is never sent anywhere. What Runtime cannot do the way Vercel does throws
|
|
7
|
+
* NotSupportedError, naming what to use. */
|
|
8
|
+
import { NotSupportedError } from "./errors.js";
|
|
9
|
+
export { Sandbox, DEFAULT_TIMEOUT_MS, DEFAULT_VCPUS, MEMORY_MIB_PER_VCPU, networkRules, toRuntimePath, } from "./sandbox.js";
|
|
10
|
+
export { Command, CommandFinished, } from "./command.js";
|
|
11
|
+
export { FileSystem, Stats, Dirent } from "./filesystem.js";
|
|
12
|
+
export { Snapshot } from "./snapshot.js";
|
|
13
|
+
export { APIError, StreamError, AuthenticationError, NotSupportedError } from "./errors.js";
|
|
14
|
+
/** Vercel's default region; Runtime runs in one US region. */
|
|
15
|
+
export const DEFAULT_SANDBOX_REGION = "iad1";
|
|
16
|
+
/** A stand-in for a Vercel export Runtime has no counterpart for. Importing it
|
|
17
|
+
* works, so a module that only mentions it still loads; calling it, building it
|
|
18
|
+
* or reading anything from it throws NotSupportedError naming the alternative. */
|
|
19
|
+
function unsupportedExport(name, alternative) {
|
|
20
|
+
const fail = () => {
|
|
21
|
+
throw new NotSupportedError(`Vercel's ${name}`, alternative);
|
|
22
|
+
};
|
|
23
|
+
return new Proxy(function unsupported() { }, {
|
|
24
|
+
apply: fail,
|
|
25
|
+
construct: fail,
|
|
26
|
+
get: (_target, property) => {
|
|
27
|
+
if (typeof property === "symbol" || property === "then" || property === "prototype")
|
|
28
|
+
return undefined;
|
|
29
|
+
return fail();
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export const Drive = unsupportedExport("Drive", "Use a Runtime volume (runtime.volumes) and mount it with withruntime: { create: { volumes: [{ volumeId, path }] } }.");
|
|
34
|
+
export const Session = unsupportedExport("Session", "A Runtime sandbox is its own session: call the methods on the sandbox.");
|
|
35
|
+
export const SandboxUser = unsupportedExport("SandboxUser", "Commands run as the sandbox owner with passwordless sudo; create users with `sudo useradd` in runCommand.");
|
|
36
|
+
export class SandboxUserAlreadyExistsError extends Error {
|
|
37
|
+
}
|
|
38
|
+
export const defineSandboxProxy = unsupportedExport("sandbox proxy (defineSandboxProxy)", "Share a port with sandbox.withruntime.previews.create(port) instead.");
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import type { Writable } from "node:stream";
|
|
2
|
+
import type { Runtime } from "../client.js";
|
|
3
|
+
import { type Credentials, type RuntimeCreate, type RuntimeSandbox, type WithRuntime } from "./client.js";
|
|
4
|
+
import { Command, CommandFinished } from "./command.js";
|
|
5
|
+
import { FileSystem } from "./filesystem.js";
|
|
6
|
+
import { Snapshot } from "./snapshot.js";
|
|
7
|
+
/** Vercel's default machine: 2 vCPUs with 2048 MB each (checked 23 September
|
|
8
|
+
* 2026). Runtime gives 2 vCPU and 4096 MiB. */
|
|
9
|
+
export declare const DEFAULT_VCPUS = 2;
|
|
10
|
+
export declare const MEMORY_MIB_PER_VCPU = 2048;
|
|
11
|
+
/** Vercel's default timeout, 5 minutes. */
|
|
12
|
+
export declare const DEFAULT_TIMEOUT_MS = 300000;
|
|
13
|
+
/** Vercel's working directory; `/workspace` on Runtime. */
|
|
14
|
+
export declare const HOME = "/vercel/sandbox";
|
|
15
|
+
export type NetworkPolicy = "allow-all" | "deny-all" | {
|
|
16
|
+
allow?: string[] | Record<string, unknown[]>;
|
|
17
|
+
subnets?: {
|
|
18
|
+
allow?: string[];
|
|
19
|
+
deny?: string[];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
type Source = {
|
|
23
|
+
type: "git";
|
|
24
|
+
url: string;
|
|
25
|
+
depth?: number;
|
|
26
|
+
revision?: string;
|
|
27
|
+
username?: string;
|
|
28
|
+
password?: string;
|
|
29
|
+
} | {
|
|
30
|
+
type: "tarball";
|
|
31
|
+
url: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: "snapshot";
|
|
34
|
+
snapshotId: string;
|
|
35
|
+
};
|
|
36
|
+
export interface CreateSandboxParams extends Credentials {
|
|
37
|
+
name?: string;
|
|
38
|
+
source?: Source;
|
|
39
|
+
/** Shared at public HTTPS addresses (Runtime previews); `domain(port)`
|
|
40
|
+
* answers from them. */
|
|
41
|
+
ports?: number[];
|
|
42
|
+
/** Milliseconds. Default 300 000; 60 s to 1 hour on Runtime. */
|
|
43
|
+
timeout?: number;
|
|
44
|
+
resources?: {
|
|
45
|
+
vcpus: number;
|
|
46
|
+
};
|
|
47
|
+
networkPolicy?: NetworkPolicy;
|
|
48
|
+
networkId?: string;
|
|
49
|
+
/** Given to every command run through this object. */
|
|
50
|
+
env?: Record<string, string>;
|
|
51
|
+
/** Stored as Runtime labels. */
|
|
52
|
+
tags?: Record<string, string>;
|
|
53
|
+
region?: string;
|
|
54
|
+
failoverRegions?: string[];
|
|
55
|
+
mounts?: Record<string, unknown>;
|
|
56
|
+
signal?: AbortSignal;
|
|
57
|
+
/** Default true: `stop()` pauses the sandbox, keeping its files (and its
|
|
58
|
+
* memory), and `Sandbox.get({ name })` wakes it. false: `stop()` ends it. */
|
|
59
|
+
persistent?: boolean;
|
|
60
|
+
/** Milliseconds a stopped persistent sandbox is kept, as Runtime's
|
|
61
|
+
* retention (whole days, 1 to 365; 0 is 365). */
|
|
62
|
+
snapshotExpiration?: number;
|
|
63
|
+
/** Accepted: a paused Runtime sandbox keeps exactly its latest state. */
|
|
64
|
+
keepLastSnapshots?: {
|
|
65
|
+
count: number;
|
|
66
|
+
expiration?: number;
|
|
67
|
+
deleteEvicted?: boolean;
|
|
68
|
+
};
|
|
69
|
+
onResume?: (sandbox: Sandbox) => Promise<void>;
|
|
70
|
+
/** A legacy Vercel runtime (node22, node24, node26, python3.13): Runtime's
|
|
71
|
+
* stock image, which has Node.js 24 and Python 3.12. */
|
|
72
|
+
runtime?: string;
|
|
73
|
+
/** A Vercel managed image (Runtime's stock image) or the name of a ready
|
|
74
|
+
* Runtime image. */
|
|
75
|
+
image?: string;
|
|
76
|
+
/** Runtime-only: an explicit client, or fields for the create. */
|
|
77
|
+
withruntime?: WithRuntime;
|
|
78
|
+
}
|
|
79
|
+
export interface RunCommandParams {
|
|
80
|
+
cmd: string;
|
|
81
|
+
args?: string[];
|
|
82
|
+
cwd?: string;
|
|
83
|
+
env?: Record<string, string>;
|
|
84
|
+
/** Runs the command under `sudo`, which needs no password. */
|
|
85
|
+
sudo?: boolean;
|
|
86
|
+
detached?: boolean;
|
|
87
|
+
stdout?: Writable;
|
|
88
|
+
stderr?: Writable;
|
|
89
|
+
signal?: AbortSignal;
|
|
90
|
+
timeoutMs?: number;
|
|
91
|
+
}
|
|
92
|
+
export interface SandboxRoute {
|
|
93
|
+
port: number;
|
|
94
|
+
subdomain: string;
|
|
95
|
+
url: string;
|
|
96
|
+
}
|
|
97
|
+
/** Vercel's network policy as Runtime's rules. Header injection and
|
|
98
|
+
* forwarding rules have no Runtime counterpart and are refused. */
|
|
99
|
+
export declare function networkRules(policy: NetworkPolicy): NonNullable<RuntimeCreate["network"]>;
|
|
100
|
+
/** Runtime's `/workspace` stands for Vercel's `/vercel/sandbox`: relative
|
|
101
|
+
* paths resolve against it, and paths under /vercel/sandbox are rewritten. */
|
|
102
|
+
export declare function toRuntimePath(path: string, cwd?: string): string;
|
|
103
|
+
type Resolved = {
|
|
104
|
+
runtime: RuntimeSandbox;
|
|
105
|
+
client: Runtime;
|
|
106
|
+
params: CreateSandboxParams;
|
|
107
|
+
};
|
|
108
|
+
/** A sandbox with Vercel's methods. `sandbox.withruntime` is the Runtime
|
|
109
|
+
* sandbox underneath, for anything Vercel has no name for. */
|
|
110
|
+
export declare class Sandbox {
|
|
111
|
+
#private;
|
|
112
|
+
readonly fs: FileSystem;
|
|
113
|
+
/** Use Sandbox.create, Sandbox.get or Sandbox.getOrCreate. */
|
|
114
|
+
constructor(resolved: Resolved);
|
|
115
|
+
/** The Runtime sandbox underneath: previews, network, snapshots, desktop,
|
|
116
|
+
* interpreter, processes and the rest of Runtime's SDK. */
|
|
117
|
+
get withruntime(): RuntimeSandbox;
|
|
118
|
+
/** The sandbox's name, or its Runtime id when it was made without one. */
|
|
119
|
+
get name(): string;
|
|
120
|
+
get routes(): SandboxRoute[];
|
|
121
|
+
get persistent(): boolean;
|
|
122
|
+
get region(): string;
|
|
123
|
+
get failoverRegions(): string[];
|
|
124
|
+
get networkId(): string | undefined;
|
|
125
|
+
get vcpus(): number;
|
|
126
|
+
/** Megabytes. */
|
|
127
|
+
get memory(): number;
|
|
128
|
+
get runtime(): string | undefined;
|
|
129
|
+
get image(): string | undefined;
|
|
130
|
+
get createdAt(): Date;
|
|
131
|
+
get updatedAt(): Date;
|
|
132
|
+
get cwd(): string;
|
|
133
|
+
get status(): "pending" | "running" | "stopping" | "stopped";
|
|
134
|
+
/** Milliseconds. */
|
|
135
|
+
get timeout(): number;
|
|
136
|
+
get expiresAt(): Date;
|
|
137
|
+
get tags(): Record<string, string>;
|
|
138
|
+
get sourceSnapshotId(): string | undefined;
|
|
139
|
+
/** Creates a sandbox and waits until it runs. Vercel's defaults: 2 vCPUs,
|
|
140
|
+
* 2048 MiB per vCPU, a 5-minute timeout, persistent. Funding is left to
|
|
141
|
+
* Runtime: the free trial while the account has trial time, then prepaid
|
|
142
|
+
* credit, exactly as withruntime's own create. */
|
|
143
|
+
static create(params?: CreateSandboxParams): Promise<Sandbox & AsyncDisposable>;
|
|
144
|
+
/** A sandbox by name (or Runtime id), woken if it is paused unless
|
|
145
|
+
* `resume: false`. */
|
|
146
|
+
static get(params: {
|
|
147
|
+
name: string;
|
|
148
|
+
resume?: boolean;
|
|
149
|
+
signal?: AbortSignal;
|
|
150
|
+
onResume?: (sandbox: Sandbox) => Promise<void>;
|
|
151
|
+
} & Credentials & {
|
|
152
|
+
withruntime?: WithRuntime;
|
|
153
|
+
}): Promise<Sandbox>;
|
|
154
|
+
/** The named sandbox, or a new one with that name when there is none. */
|
|
155
|
+
static getOrCreate(params?: CreateSandboxParams & {
|
|
156
|
+
resume?: boolean;
|
|
157
|
+
onCreate?: (sandbox: Sandbox) => Promise<void>;
|
|
158
|
+
}): Promise<Sandbox>;
|
|
159
|
+
/** A new sandbox copied from a running one, memory and all (a Runtime
|
|
160
|
+
* fork). `sourceSandbox` is its name. */
|
|
161
|
+
static fork(params: Omit<CreateSandboxParams, "source"> & {
|
|
162
|
+
sourceSandbox: string;
|
|
163
|
+
}): Promise<Sandbox & AsyncDisposable>;
|
|
164
|
+
/** Running and stopped (paused) sandboxes, oldest first, with Vercel's
|
|
165
|
+
* paginator: `for await (const s of await Sandbox.list())`. */
|
|
166
|
+
static list(params?: {
|
|
167
|
+
tags?: Record<string, string>;
|
|
168
|
+
limit?: number;
|
|
169
|
+
signal?: AbortSignal;
|
|
170
|
+
} & Credentials & {
|
|
171
|
+
withruntime?: WithRuntime;
|
|
172
|
+
} & Record<string, unknown>): Promise<{
|
|
173
|
+
sandboxes: ListItem[];
|
|
174
|
+
pagination: {
|
|
175
|
+
count: number;
|
|
176
|
+
next: string | null;
|
|
177
|
+
};
|
|
178
|
+
} & {
|
|
179
|
+
pages(): AsyncGenerator<{
|
|
180
|
+
sandboxes: ListItem[];
|
|
181
|
+
pagination: {
|
|
182
|
+
count: number;
|
|
183
|
+
next: string | null;
|
|
184
|
+
};
|
|
185
|
+
}, void, unknown>;
|
|
186
|
+
[Symbol.asyncIterator](): AsyncGenerator<ListItem, void, unknown>;
|
|
187
|
+
toArray(): Promise<ListItem[]>;
|
|
188
|
+
}>;
|
|
189
|
+
/** Runs a command. It waits and resolves with a CommandFinished (a
|
|
190
|
+
* non-zero exit is not an error), or with `detached: true` resolves at once
|
|
191
|
+
* with a Command. */
|
|
192
|
+
runCommand(command: string, args?: string[], opts?: {
|
|
193
|
+
signal?: AbortSignal;
|
|
194
|
+
timeoutMs?: number;
|
|
195
|
+
}): Promise<CommandFinished>;
|
|
196
|
+
runCommand(params: RunCommandParams & {
|
|
197
|
+
detached: true;
|
|
198
|
+
}): Promise<Command>;
|
|
199
|
+
runCommand(params: RunCommandParams): Promise<CommandFinished>;
|
|
200
|
+
/** A command started earlier, by its cmdId. */
|
|
201
|
+
getCommand(cmdId: string, _opts?: {
|
|
202
|
+
signal?: AbortSignal;
|
|
203
|
+
}): Promise<Command>;
|
|
204
|
+
mkDir(path: string, _opts?: {
|
|
205
|
+
signal?: AbortSignal;
|
|
206
|
+
}): Promise<void>;
|
|
207
|
+
/** The file's bytes as a Node stream, or null when there is no file. */
|
|
208
|
+
readFile(file: {
|
|
209
|
+
path: string;
|
|
210
|
+
cwd?: string;
|
|
211
|
+
}, opts?: {
|
|
212
|
+
signal?: AbortSignal;
|
|
213
|
+
}): Promise<NodeJS.ReadableStream | null>;
|
|
214
|
+
/** The file as a Buffer, or null when there is no file. */
|
|
215
|
+
readFileToBuffer(file: {
|
|
216
|
+
path: string;
|
|
217
|
+
cwd?: string;
|
|
218
|
+
}, opts?: {
|
|
219
|
+
signal?: AbortSignal;
|
|
220
|
+
}): Promise<Buffer | null>;
|
|
221
|
+
/** Copies a sandbox file to the local disk; null when there is no file. */
|
|
222
|
+
downloadFile(src: {
|
|
223
|
+
path: string;
|
|
224
|
+
cwd?: string;
|
|
225
|
+
}, dst: {
|
|
226
|
+
path: string;
|
|
227
|
+
cwd?: string;
|
|
228
|
+
}, opts?: {
|
|
229
|
+
mkdirRecursive?: boolean;
|
|
230
|
+
signal?: AbortSignal;
|
|
231
|
+
}): Promise<string | null>;
|
|
232
|
+
/** Writes files, making their directories. Relative paths land in the
|
|
233
|
+
* working directory; `mode` sets permissions. */
|
|
234
|
+
writeFiles(files: {
|
|
235
|
+
path: string;
|
|
236
|
+
content: string | Uint8Array;
|
|
237
|
+
mode?: number;
|
|
238
|
+
}[], _opts?: {
|
|
239
|
+
signal?: AbortSignal;
|
|
240
|
+
}): Promise<void>;
|
|
241
|
+
/** The public address of a port listed in `ports`, such as
|
|
242
|
+
* `https://3000-<id>.runtimehost.com`. A browser sees a one-time page
|
|
243
|
+
* naming Runtime before the site. */
|
|
244
|
+
domain(port: number): string;
|
|
245
|
+
/** Ends the session. A persistent sandbox is paused, keeping its files and
|
|
246
|
+
* memory, and wakes on the next call or Sandbox.get; any other ends. */
|
|
247
|
+
stop(opts?: {
|
|
248
|
+
signal?: AbortSignal;
|
|
249
|
+
}): Promise<{
|
|
250
|
+
name: string;
|
|
251
|
+
status: string;
|
|
252
|
+
}>;
|
|
253
|
+
/** Ends the sandbox for good. */
|
|
254
|
+
delete(opts?: {
|
|
255
|
+
deleteOrphanSnapshots?: boolean;
|
|
256
|
+
signal?: AbortSignal;
|
|
257
|
+
}): Promise<void>;
|
|
258
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
259
|
+
/** Moves the end `duration` milliseconds later (at most an hour ahead of
|
|
260
|
+
* now on Runtime). */
|
|
261
|
+
extendTimeout(duration: number, opts?: {
|
|
262
|
+
signal?: AbortSignal;
|
|
263
|
+
}): Promise<void>;
|
|
264
|
+
/** Replaces the network rules; returns the policy given. */
|
|
265
|
+
updateNetworkPolicy(networkPolicy: NetworkPolicy, _opts?: {
|
|
266
|
+
signal?: AbortSignal;
|
|
267
|
+
}): Promise<NetworkPolicy>;
|
|
268
|
+
/** Changes what Runtime can change on a sandbox: `timeout`, `ports`,
|
|
269
|
+
* `networkPolicy` and `snapshotExpiration`. Anything else is refused before
|
|
270
|
+
* anything changes. */
|
|
271
|
+
update(params: {
|
|
272
|
+
timeout?: number;
|
|
273
|
+
ports?: number[];
|
|
274
|
+
networkPolicy?: NetworkPolicy;
|
|
275
|
+
snapshotExpiration?: number;
|
|
276
|
+
} & Record<string, unknown>, _opts?: {
|
|
277
|
+
signal?: AbortSignal;
|
|
278
|
+
}): Promise<void>;
|
|
279
|
+
/** Keeps the sandbox's whole machine as a Runtime snapshot (files, memory
|
|
280
|
+
* and running processes), then stops the sandbox, as Vercel does. Start
|
|
281
|
+
* from it with `Sandbox.create({ source: { type: "snapshot", snapshotId } })`. */
|
|
282
|
+
snapshot(opts?: {
|
|
283
|
+
expiration?: number;
|
|
284
|
+
signal?: AbortSignal;
|
|
285
|
+
}): Promise<Snapshot>;
|
|
286
|
+
openInteractive(): Promise<never>;
|
|
287
|
+
getDefaultUser(): Promise<{
|
|
288
|
+
username: string;
|
|
289
|
+
group: string;
|
|
290
|
+
}>;
|
|
291
|
+
createUser(): Promise<never>;
|
|
292
|
+
asUser(): never;
|
|
293
|
+
createGroup(): Promise<never>;
|
|
294
|
+
addUserToGroup(): Promise<never>;
|
|
295
|
+
removeUserFromGroup(): Promise<never>;
|
|
296
|
+
currentSession(): never;
|
|
297
|
+
listSessions(): Promise<never>;
|
|
298
|
+
listSnapshots(): Promise<never>;
|
|
299
|
+
}
|
|
300
|
+
/** Milliseconds as whole days for Runtime's retention: 1 to 365, and 0 (no
|
|
301
|
+
* expiration) as 365. */
|
|
302
|
+
export declare function retentionDays(ms: number): number;
|
|
303
|
+
type ListItem = {
|
|
304
|
+
name: string;
|
|
305
|
+
persistent: boolean;
|
|
306
|
+
createdAt: number;
|
|
307
|
+
updatedAt: number;
|
|
308
|
+
currentSessionId: string;
|
|
309
|
+
status: "pending" | "running" | "stopping" | "stopped";
|
|
310
|
+
region: string;
|
|
311
|
+
vcpus: number;
|
|
312
|
+
memory: number;
|
|
313
|
+
timeout: number;
|
|
314
|
+
expiresAt: number;
|
|
315
|
+
tags: Record<string, string>;
|
|
316
|
+
};
|
|
317
|
+
export {};
|