@vercel/sandbox 1.9.0 → 1.9.1
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/README.md +8 -0
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/api-client/api-client.cjs +375 -0
- package/dist/api-client/api-client.cjs.map +1 -0
- package/dist/api-client/api-client.d.cts +403 -0
- package/dist/api-client/api-client.d.ts +397 -392
- package/dist/api-client/api-client.js +365 -405
- package/dist/api-client/api-client.js.map +1 -1
- package/dist/api-client/api-error.cjs +31 -0
- package/dist/api-client/api-error.cjs.map +1 -0
- package/dist/api-client/api-error.d.cts +27 -0
- package/dist/api-client/api-error.d.ts +19 -16
- package/dist/api-client/api-error.js +27 -32
- package/dist/api-client/api-error.js.map +1 -1
- package/dist/api-client/base-client.cjs +113 -0
- package/dist/api-client/base-client.cjs.map +1 -0
- package/dist/api-client/base-client.d.cts +38 -0
- package/dist/api-client/base-client.d.ts +31 -36
- package/dist/api-client/base-client.js +101 -118
- package/dist/api-client/base-client.js.map +1 -1
- package/dist/api-client/file-writer.cjs +62 -0
- package/dist/api-client/file-writer.cjs.map +1 -0
- package/dist/api-client/file-writer.d.cts +66 -0
- package/dist/api-client/file-writer.d.ts +56 -52
- package/dist/api-client/file-writer.js +57 -61
- package/dist/api-client/file-writer.js.map +1 -1
- package/dist/api-client/index.cjs +2 -0
- package/dist/api-client/index.d.ts +2 -2
- package/dist/api-client/index.js +4 -21
- package/dist/api-client/validators.cjs +149 -0
- package/dist/api-client/validators.cjs.map +1 -0
- package/dist/api-client/validators.d.cts +1677 -0
- package/dist/api-client/validators.d.ts +1501 -2412
- package/dist/api-client/validators.js +124 -154
- package/dist/api-client/validators.js.map +1 -1
- package/dist/api-client/with-retry.cjs +89 -0
- package/dist/api-client/with-retry.cjs.map +1 -0
- package/dist/api-client/with-retry.d.cts +10 -0
- package/dist/api-client/with-retry.d.ts +9 -13
- package/dist/api-client/with-retry.js +81 -102
- package/dist/api-client/with-retry.js.map +1 -1
- package/dist/auth/api.cjs +29 -0
- package/dist/auth/api.cjs.map +1 -0
- package/dist/auth/api.js +26 -25
- package/dist/auth/api.js.map +1 -1
- package/dist/auth/error.cjs +13 -0
- package/dist/auth/error.cjs.map +1 -0
- package/dist/auth/error.js +11 -11
- package/dist/auth/error.js.map +1 -1
- package/dist/auth/file.cjs +64 -0
- package/dist/auth/file.cjs.map +1 -0
- package/dist/auth/file.d.cts +26 -0
- package/dist/auth/file.d.ts +19 -15
- package/dist/auth/file.js +49 -64
- package/dist/auth/file.js.map +1 -1
- package/dist/auth/index.cjs +12 -0
- package/dist/auth/index.d.cts +5 -0
- package/dist/auth/index.d.ts +5 -6
- package/dist/auth/index.js +6 -27
- package/dist/auth/linked-project.cjs +38 -0
- package/dist/auth/linked-project.cjs.map +1 -0
- package/dist/auth/linked-project.js +30 -64
- package/dist/auth/linked-project.js.map +1 -1
- package/dist/auth/oauth.cjs +205 -0
- package/dist/auth/oauth.cjs.map +1 -0
- package/dist/auth/oauth.d.cts +135 -0
- package/dist/auth/oauth.d.ts +113 -109
- package/dist/auth/oauth.js +185 -252
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/poll-for-token.cjs +82 -0
- package/dist/auth/poll-for-token.cjs.map +1 -0
- package/dist/auth/poll-for-token.d.cts +28 -0
- package/dist/auth/poll-for-token.d.ts +23 -15
- package/dist/auth/poll-for-token.js +79 -64
- package/dist/auth/poll-for-token.js.map +1 -1
- package/dist/auth/project.cjs +80 -0
- package/dist/auth/project.cjs.map +1 -0
- package/dist/auth/project.d.cts +44 -0
- package/dist/auth/project.d.ts +12 -8
- package/dist/auth/project.js +70 -72
- package/dist/auth/project.js.map +1 -1
- package/dist/auth/zod.cjs +22 -0
- package/dist/auth/zod.cjs.map +1 -0
- package/dist/auth/zod.js +18 -17
- package/dist/auth/zod.js.map +1 -1
- package/dist/command.cjs +326 -0
- package/dist/command.cjs.map +1 -0
- package/dist/command.d.cts +289 -0
- package/dist/command.d.ts +265 -171
- package/dist/command.js +321 -226
- package/dist/command.js.map +1 -1
- package/dist/constants.d.cts +5 -0
- package/dist/constants.d.ts +5 -1
- package/dist/index.cjs +11 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +6 -15
- package/dist/network-policy.d.cts +100 -0
- package/dist/network-policy.d.ts +32 -28
- package/dist/sandbox.cjs +543 -0
- package/dist/sandbox.cjs.map +1 -0
- package/dist/sandbox.d.cts +538 -0
- package/dist/sandbox.d.ts +521 -479
- package/dist/sandbox.js +539 -512
- package/dist/sandbox.js.map +1 -1
- package/dist/snapshot.cjs +116 -0
- package/dist/snapshot.cjs.map +1 -0
- package/dist/snapshot.d.cts +109 -0
- package/dist/snapshot.d.ts +100 -92
- package/dist/snapshot.js +114 -114
- package/dist/snapshot.js.map +1 -1
- package/dist/utils/array.cjs +17 -0
- package/dist/utils/array.cjs.map +1 -0
- package/dist/utils/array.js +12 -15
- package/dist/utils/array.js.map +1 -1
- package/dist/utils/consume-readable.cjs +18 -0
- package/dist/utils/consume-readable.cjs.map +1 -0
- package/dist/utils/consume-readable.js +13 -12
- package/dist/utils/consume-readable.js.map +1 -1
- package/dist/utils/decode-base64-url.cjs +15 -0
- package/dist/utils/decode-base64-url.cjs.map +1 -0
- package/dist/utils/decode-base64-url.js +10 -9
- package/dist/utils/decode-base64-url.js.map +1 -1
- package/dist/utils/dev-credentials.cjs +142 -0
- package/dist/utils/dev-credentials.cjs.map +1 -0
- package/dist/utils/dev-credentials.js +126 -184
- package/dist/utils/dev-credentials.js.map +1 -1
- package/dist/utils/get-credentials.cjs +123 -0
- package/dist/utils/get-credentials.cjs.map +1 -0
- package/dist/utils/get-credentials.d.cts +21 -0
- package/dist/utils/get-credentials.d.ts +19 -61
- package/dist/utils/get-credentials.js +106 -140
- package/dist/utils/get-credentials.js.map +1 -1
- package/dist/utils/log.cjs +25 -0
- package/dist/utils/log.cjs.map +1 -0
- package/dist/utils/log.js +15 -17
- package/dist/utils/log.js.map +1 -1
- package/dist/utils/network-policy.cjs +65 -0
- package/dist/utils/network-policy.cjs.map +1 -0
- package/dist/utils/network-policy.js +58 -77
- package/dist/utils/network-policy.js.map +1 -1
- package/dist/utils/normalizePath.cjs +27 -0
- package/dist/utils/normalizePath.cjs.map +1 -0
- package/dist/utils/normalizePath.js +21 -28
- package/dist/utils/normalizePath.js.map +1 -1
- package/dist/utils/resolveSignal.cjs +20 -0
- package/dist/utils/resolveSignal.cjs.map +1 -0
- package/dist/utils/resolveSignal.d.cts +15 -0
- package/dist/utils/resolveSignal.d.ts +12 -10
- package/dist/utils/resolveSignal.js +14 -17
- package/dist/utils/resolveSignal.js.map +1 -1
- package/dist/utils/sandbox-snapshot.cjs +14 -0
- package/dist/utils/sandbox-snapshot.cjs.map +1 -0
- package/dist/utils/sandbox-snapshot.d.cts +10 -0
- package/dist/utils/sandbox-snapshot.d.ts +11 -0
- package/dist/utils/sandbox-snapshot.js +14 -0
- package/dist/utils/sandbox-snapshot.js.map +1 -0
- package/dist/utils/types.cjs +13 -0
- package/dist/utils/types.cjs.map +1 -0
- package/dist/utils/types.d.cts +11 -0
- package/dist/utils/types.d.ts +5 -7
- package/dist/utils/types.js +8 -8
- package/dist/utils/types.js.map +1 -1
- package/dist/version.cjs +7 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.js +5 -5
- package/dist/version.js.map +1 -1
- package/package.json +23 -3
- package/dist/api-client/index.js.map +0 -1
- package/dist/auth/api.d.ts +0 -6
- package/dist/auth/error.d.ts +0 -11
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/linked-project.d.ts +0 -10
- package/dist/auth/zod.d.ts +0 -5
- package/dist/constants.js +0 -3
- package/dist/constants.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/network-policy.js +0 -3
- package/dist/network-policy.js.map +0 -1
- package/dist/utils/array.d.ts +0 -9
- package/dist/utils/consume-readable.d.ts +0 -5
- package/dist/utils/convert-sandbox.d.ts +0 -6
- package/dist/utils/convert-sandbox.js +0 -14
- package/dist/utils/convert-sandbox.js.map +0 -1
- package/dist/utils/decode-base64-url.d.ts +0 -7
- package/dist/utils/dev-credentials.d.ts +0 -37
- package/dist/utils/log.d.ts +0 -2
- package/dist/utils/network-policy.d.ts +0 -7
- package/dist/utils/normalizePath.d.ts +0 -17
- package/dist/version.d.ts +0 -1
package/dist/sandbox.cjs
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_consume_readable = require('./utils/consume-readable.cjs');
|
|
3
|
+
const require_types = require('./utils/types.cjs');
|
|
4
|
+
const require_api_client = require('./api-client/api-client.cjs');
|
|
5
|
+
require('./api-client/index.cjs');
|
|
6
|
+
const require_get_credentials = require('./utils/get-credentials.cjs');
|
|
7
|
+
const require_command = require('./command.cjs');
|
|
8
|
+
const require_snapshot = require('./snapshot.cjs');
|
|
9
|
+
const require_sandbox_snapshot = require('./utils/sandbox-snapshot.cjs');
|
|
10
|
+
let __workflow_serde = require("@workflow/serde");
|
|
11
|
+
let fs = require("fs");
|
|
12
|
+
let fs_promises = require("fs/promises");
|
|
13
|
+
let path = require("path");
|
|
14
|
+
let stream_promises = require("stream/promises");
|
|
15
|
+
|
|
16
|
+
//#region src/sandbox.ts
|
|
17
|
+
/**
|
|
18
|
+
* A Sandbox is an isolated Linux MicroVM to run commands in.
|
|
19
|
+
*
|
|
20
|
+
* Use {@link Sandbox.create} or {@link Sandbox.get} to construct.
|
|
21
|
+
* @hideconstructor
|
|
22
|
+
*/
|
|
23
|
+
var Sandbox = class Sandbox {
|
|
24
|
+
/**
|
|
25
|
+
* Lazily resolve credentials and construct an API client.
|
|
26
|
+
* This is used in step contexts where the Sandbox was deserialized
|
|
27
|
+
* without a client (e.g. when crossing workflow/step boundaries).
|
|
28
|
+
* Uses getCredentials() which resolves from OIDC or env vars.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
async ensureClient() {
|
|
32
|
+
"use step";
|
|
33
|
+
if (this._client) return this._client;
|
|
34
|
+
const credentials = await require_get_credentials.getCredentials();
|
|
35
|
+
this._client = new require_api_client.APIClient({
|
|
36
|
+
teamId: credentials.teamId,
|
|
37
|
+
token: credentials.token
|
|
38
|
+
});
|
|
39
|
+
return this._client;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Unique ID of this sandbox.
|
|
43
|
+
*/
|
|
44
|
+
get sandboxId() {
|
|
45
|
+
return this.sandbox.id;
|
|
46
|
+
}
|
|
47
|
+
get interactivePort() {
|
|
48
|
+
return this.sandbox.interactivePort ?? void 0;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The status of the sandbox.
|
|
52
|
+
*/
|
|
53
|
+
get status() {
|
|
54
|
+
return this.sandbox.status;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The creation date of the sandbox.
|
|
58
|
+
*/
|
|
59
|
+
get createdAt() {
|
|
60
|
+
return new Date(this.sandbox.createdAt);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The timeout of the sandbox in milliseconds.
|
|
64
|
+
*/
|
|
65
|
+
get timeout() {
|
|
66
|
+
return this.sandbox.timeout;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The network policy of the sandbox.
|
|
70
|
+
*/
|
|
71
|
+
get networkPolicy() {
|
|
72
|
+
return this.sandbox.networkPolicy;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* If the sandbox was created from a snapshot, the ID of that snapshot.
|
|
76
|
+
*/
|
|
77
|
+
get sourceSnapshotId() {
|
|
78
|
+
return this.sandbox.sourceSnapshotId;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The amount of CPU used by the sandbox. Only reported once the VM is stopped.
|
|
82
|
+
*/
|
|
83
|
+
get activeCpuUsageMs() {
|
|
84
|
+
return this.sandbox.activeCpuDurationMs;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The amount of network data used by the sandbox. Only reported once the VM is stopped.
|
|
88
|
+
*/
|
|
89
|
+
get networkTransfer() {
|
|
90
|
+
return this.sandbox.networkTransfer;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Allow to get a list of sandboxes for a team narrowed to the given params.
|
|
94
|
+
* It returns both the sandboxes and the pagination metadata to allow getting
|
|
95
|
+
* the next page of results.
|
|
96
|
+
*/
|
|
97
|
+
static async list(params) {
|
|
98
|
+
"use step";
|
|
99
|
+
const credentials = await require_get_credentials.getCredentials(params);
|
|
100
|
+
return new require_api_client.APIClient({
|
|
101
|
+
teamId: credentials.teamId,
|
|
102
|
+
token: credentials.token,
|
|
103
|
+
fetch: params?.fetch
|
|
104
|
+
}).listSandboxes({
|
|
105
|
+
...credentials,
|
|
106
|
+
...params
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Serialize a Sandbox instance to plain data for @workflow/serde.
|
|
111
|
+
*
|
|
112
|
+
* @param instance - The Sandbox instance to serialize
|
|
113
|
+
* @returns A plain object containing sandbox metadata and routes
|
|
114
|
+
*/
|
|
115
|
+
static [__workflow_serde.WORKFLOW_SERIALIZE](instance) {
|
|
116
|
+
return {
|
|
117
|
+
metadata: instance.sandbox,
|
|
118
|
+
routes: instance.routes
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Deserialize a Sandbox from serialized snapshot data.
|
|
123
|
+
*
|
|
124
|
+
* The deserialized instance uses the serialized metadata synchronously and
|
|
125
|
+
* lazily creates an API client only when methods perform API requests.
|
|
126
|
+
*
|
|
127
|
+
* @param data - The serialized sandbox data
|
|
128
|
+
* @returns The reconstructed Sandbox instance
|
|
129
|
+
*/
|
|
130
|
+
static [__workflow_serde.WORKFLOW_DESERIALIZE](data) {
|
|
131
|
+
return new Sandbox({
|
|
132
|
+
sandbox: data.metadata,
|
|
133
|
+
routes: data.routes
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Create a new sandbox.
|
|
138
|
+
*
|
|
139
|
+
* @param params - Creation parameters and optional credentials.
|
|
140
|
+
* @returns A promise resolving to the created {@link Sandbox}.
|
|
141
|
+
* @example
|
|
142
|
+
* <caption>Create a sandbox and drop it in the end of the block</caption>
|
|
143
|
+
* async function fn() {
|
|
144
|
+
* await using const sandbox = await Sandbox.create();
|
|
145
|
+
* // Sandbox automatically stopped at the end of the lexical scope
|
|
146
|
+
* }
|
|
147
|
+
*/
|
|
148
|
+
static async create(params) {
|
|
149
|
+
"use step";
|
|
150
|
+
const credentials = await require_get_credentials.getCredentials(params);
|
|
151
|
+
const client = new require_api_client.APIClient({
|
|
152
|
+
teamId: credentials.teamId,
|
|
153
|
+
token: credentials.token,
|
|
154
|
+
fetch: params?.fetch
|
|
155
|
+
});
|
|
156
|
+
const privateParams = require_types.getPrivateParams(params);
|
|
157
|
+
const sandbox = await client.createSandbox({
|
|
158
|
+
source: params?.source,
|
|
159
|
+
projectId: credentials.projectId,
|
|
160
|
+
ports: params?.ports ?? [],
|
|
161
|
+
timeout: params?.timeout,
|
|
162
|
+
resources: params?.resources,
|
|
163
|
+
runtime: params && "runtime" in params ? params?.runtime : void 0,
|
|
164
|
+
networkPolicy: params?.networkPolicy,
|
|
165
|
+
env: params?.env,
|
|
166
|
+
signal: params?.signal,
|
|
167
|
+
...privateParams
|
|
168
|
+
});
|
|
169
|
+
return new DisposableSandbox({
|
|
170
|
+
client,
|
|
171
|
+
sandbox: require_sandbox_snapshot.toSandboxSnapshot(sandbox.json.sandbox),
|
|
172
|
+
routes: sandbox.json.routes
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Retrieve an existing sandbox.
|
|
177
|
+
*
|
|
178
|
+
* @param params - Get parameters and optional credentials.
|
|
179
|
+
* @returns A promise resolving to the {@link Sandbox}.
|
|
180
|
+
*/
|
|
181
|
+
static async get(params) {
|
|
182
|
+
"use step";
|
|
183
|
+
const credentials = await require_get_credentials.getCredentials(params);
|
|
184
|
+
const client = new require_api_client.APIClient({
|
|
185
|
+
teamId: credentials.teamId,
|
|
186
|
+
token: credentials.token,
|
|
187
|
+
fetch: params.fetch
|
|
188
|
+
});
|
|
189
|
+
const privateParams = require_types.getPrivateParams(params);
|
|
190
|
+
const sandbox = await client.getSandbox({
|
|
191
|
+
sandboxId: params.sandboxId,
|
|
192
|
+
signal: params.signal,
|
|
193
|
+
...privateParams
|
|
194
|
+
});
|
|
195
|
+
return new Sandbox({
|
|
196
|
+
client,
|
|
197
|
+
sandbox: require_sandbox_snapshot.toSandboxSnapshot(sandbox.json.sandbox),
|
|
198
|
+
routes: sandbox.json.routes
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Create a new Sandbox instance.
|
|
203
|
+
*
|
|
204
|
+
* @param params.client - Optional API client. If not provided, will be lazily created using global credentials.
|
|
205
|
+
* @param params.routes - Port-to-subdomain mappings for exposed ports
|
|
206
|
+
* @param params.sandbox - Sandbox snapshot metadata
|
|
207
|
+
*/
|
|
208
|
+
constructor({ client, routes, sandbox }) {
|
|
209
|
+
this._client = null;
|
|
210
|
+
this._client = client ?? null;
|
|
211
|
+
this.routes = routes;
|
|
212
|
+
this.sandbox = sandbox;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get a previously run command by its ID.
|
|
216
|
+
*
|
|
217
|
+
* @param cmdId - ID of the command to retrieve
|
|
218
|
+
* @param opts - Optional parameters.
|
|
219
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
220
|
+
* @returns A {@link Command} instance representing the command
|
|
221
|
+
*/
|
|
222
|
+
async getCommand(cmdId, opts) {
|
|
223
|
+
"use step";
|
|
224
|
+
const client = await this.ensureClient();
|
|
225
|
+
const command = await client.getCommand({
|
|
226
|
+
sandboxId: this.sandbox.id,
|
|
227
|
+
cmdId,
|
|
228
|
+
signal: opts?.signal
|
|
229
|
+
});
|
|
230
|
+
return new require_command.Command({
|
|
231
|
+
client,
|
|
232
|
+
sandboxId: this.sandbox.id,
|
|
233
|
+
cmd: command.json.command
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
async runCommand(commandOrParams, args, opts) {
|
|
237
|
+
"use step";
|
|
238
|
+
const client = await this.ensureClient();
|
|
239
|
+
const params = typeof commandOrParams === "string" ? {
|
|
240
|
+
cmd: commandOrParams,
|
|
241
|
+
args,
|
|
242
|
+
signal: opts?.signal
|
|
243
|
+
} : commandOrParams;
|
|
244
|
+
const wait = params.detached ? false : true;
|
|
245
|
+
const pipeLogs = async (command$1) => {
|
|
246
|
+
if (!params.stdout && !params.stderr) return;
|
|
247
|
+
try {
|
|
248
|
+
for await (const log of command$1.logs({ signal: params.signal })) if (log.stream === "stdout") params.stdout?.write(log.data);
|
|
249
|
+
else if (log.stream === "stderr") params.stderr?.write(log.data);
|
|
250
|
+
} catch (err) {
|
|
251
|
+
if (params.signal?.aborted) return;
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
if (wait) {
|
|
256
|
+
const commandStream = await client.runCommand({
|
|
257
|
+
sandboxId: this.sandbox.id,
|
|
258
|
+
command: params.cmd,
|
|
259
|
+
args: params.args ?? [],
|
|
260
|
+
cwd: params.cwd,
|
|
261
|
+
env: params.env ?? {},
|
|
262
|
+
sudo: params.sudo ?? false,
|
|
263
|
+
wait: true,
|
|
264
|
+
signal: params.signal
|
|
265
|
+
});
|
|
266
|
+
const command$1 = new require_command.Command({
|
|
267
|
+
client,
|
|
268
|
+
sandboxId: this.sandbox.id,
|
|
269
|
+
cmd: commandStream.command
|
|
270
|
+
});
|
|
271
|
+
const [finished] = await Promise.all([commandStream.finished, pipeLogs(command$1)]);
|
|
272
|
+
return new require_command.CommandFinished({
|
|
273
|
+
client,
|
|
274
|
+
sandboxId: this.sandbox.id,
|
|
275
|
+
cmd: finished,
|
|
276
|
+
exitCode: finished.exitCode ?? 0
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const commandResponse = await client.runCommand({
|
|
280
|
+
sandboxId: this.sandbox.id,
|
|
281
|
+
command: params.cmd,
|
|
282
|
+
args: params.args ?? [],
|
|
283
|
+
cwd: params.cwd,
|
|
284
|
+
env: params.env ?? {},
|
|
285
|
+
sudo: params.sudo ?? false,
|
|
286
|
+
signal: params.signal
|
|
287
|
+
});
|
|
288
|
+
const command = new require_command.Command({
|
|
289
|
+
client,
|
|
290
|
+
sandboxId: this.sandbox.id,
|
|
291
|
+
cmd: commandResponse.json.command
|
|
292
|
+
});
|
|
293
|
+
pipeLogs(command).catch((err) => {
|
|
294
|
+
if (params.signal?.aborted) return;
|
|
295
|
+
(params.stderr ?? params.stdout)?.emit("error", err);
|
|
296
|
+
});
|
|
297
|
+
return command;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Create a directory in the filesystem of this sandbox.
|
|
301
|
+
*
|
|
302
|
+
* @param path - Path of the directory to create
|
|
303
|
+
* @param opts - Optional parameters.
|
|
304
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
305
|
+
*/
|
|
306
|
+
async mkDir(path$1, opts) {
|
|
307
|
+
"use step";
|
|
308
|
+
await (await this.ensureClient()).mkDir({
|
|
309
|
+
sandboxId: this.sandbox.id,
|
|
310
|
+
path: path$1,
|
|
311
|
+
signal: opts?.signal
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Read a file from the filesystem of this sandbox as a stream.
|
|
316
|
+
*
|
|
317
|
+
* @param file - File to read, with path and optional cwd
|
|
318
|
+
* @param opts - Optional parameters.
|
|
319
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
320
|
+
* @returns A promise that resolves to a ReadableStream containing the file contents, or null if file not found
|
|
321
|
+
*/
|
|
322
|
+
async readFile(file, opts) {
|
|
323
|
+
"use step";
|
|
324
|
+
return (await this.ensureClient()).readFile({
|
|
325
|
+
sandboxId: this.sandbox.id,
|
|
326
|
+
path: file.path,
|
|
327
|
+
cwd: file.cwd,
|
|
328
|
+
signal: opts?.signal
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Read a file from the filesystem of this sandbox as a Buffer.
|
|
333
|
+
*
|
|
334
|
+
* @param file - File to read, with path and optional cwd
|
|
335
|
+
* @param opts - Optional parameters.
|
|
336
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
337
|
+
* @returns A promise that resolves to the file contents as a Buffer, or null if file not found
|
|
338
|
+
*/
|
|
339
|
+
async readFileToBuffer(file, opts) {
|
|
340
|
+
"use step";
|
|
341
|
+
const stream = await (await this.ensureClient()).readFile({
|
|
342
|
+
sandboxId: this.sandbox.id,
|
|
343
|
+
path: file.path,
|
|
344
|
+
cwd: file.cwd,
|
|
345
|
+
signal: opts?.signal
|
|
346
|
+
});
|
|
347
|
+
if (stream === null) return null;
|
|
348
|
+
return require_consume_readable.consumeReadable(stream);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Download a file from the sandbox to the local filesystem.
|
|
352
|
+
*
|
|
353
|
+
* @param src - Source file on the sandbox, with path and optional cwd
|
|
354
|
+
* @param dst - Destination file on the local machine, with path and optional cwd
|
|
355
|
+
* @param opts - Optional parameters.
|
|
356
|
+
* @param opts.mkdirRecursive - If true, create parent directories for the destination if they don't exist.
|
|
357
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
358
|
+
* @returns The absolute path to the written file, or null if the source file was not found
|
|
359
|
+
*/
|
|
360
|
+
async downloadFile(src, dst, opts) {
|
|
361
|
+
"use step";
|
|
362
|
+
const client = await this.ensureClient();
|
|
363
|
+
if (!src?.path) throw new Error("downloadFile: source path is required");
|
|
364
|
+
if (!dst?.path) throw new Error("downloadFile: destination path is required");
|
|
365
|
+
const stream = await client.readFile({
|
|
366
|
+
sandboxId: this.sandbox.id,
|
|
367
|
+
path: src.path,
|
|
368
|
+
cwd: src.cwd,
|
|
369
|
+
signal: opts?.signal
|
|
370
|
+
});
|
|
371
|
+
if (stream === null) return null;
|
|
372
|
+
try {
|
|
373
|
+
const dstPath = (0, path.resolve)(dst.cwd ?? "", dst.path);
|
|
374
|
+
if (opts?.mkdirRecursive) await (0, fs_promises.mkdir)((0, path.dirname)(dstPath), { recursive: true });
|
|
375
|
+
await (0, stream_promises.pipeline)(stream, (0, fs.createWriteStream)(dstPath), { signal: opts?.signal });
|
|
376
|
+
return dstPath;
|
|
377
|
+
} finally {
|
|
378
|
+
stream.destroy();
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Write files to the filesystem of this sandbox.
|
|
383
|
+
* Defaults to writing to /vercel/sandbox unless an absolute path is specified.
|
|
384
|
+
* Writes files using the `vercel-sandbox` user.
|
|
385
|
+
*
|
|
386
|
+
* @param files - Array of files with path, content, and optional mode (permissions)
|
|
387
|
+
* @param opts - Optional parameters.
|
|
388
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
389
|
+
* @returns A promise that resolves when the files are written
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* // Write an executable script
|
|
393
|
+
* await sandbox.writeFiles([
|
|
394
|
+
* { path: "/usr/local/bin/myscript", content: "#!/bin/bash\necho hello", mode: 0o755 }
|
|
395
|
+
* ]);
|
|
396
|
+
*/
|
|
397
|
+
async writeFiles(files, opts) {
|
|
398
|
+
"use step";
|
|
399
|
+
return (await this.ensureClient()).writeFiles({
|
|
400
|
+
sandboxId: this.sandbox.id,
|
|
401
|
+
cwd: this.sandbox.cwd,
|
|
402
|
+
extractDir: "/",
|
|
403
|
+
files,
|
|
404
|
+
signal: opts?.signal
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get the public domain of a port of this sandbox.
|
|
409
|
+
*
|
|
410
|
+
* @param p - Port number to resolve
|
|
411
|
+
* @returns A full domain (e.g. `https://subdomain.vercel.run`)
|
|
412
|
+
* @throws If the port has no associated route
|
|
413
|
+
*/
|
|
414
|
+
domain(p) {
|
|
415
|
+
const route = this.routes.find(({ port }) => port == p);
|
|
416
|
+
if (route) return `https://${route.subdomain}.vercel.run`;
|
|
417
|
+
else throw new Error(`No route for port ${p}`);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Stop the sandbox.
|
|
421
|
+
*
|
|
422
|
+
* @param opts - Optional parameters.
|
|
423
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
424
|
+
* @param opts.blocking - If true, poll until the sandbox has fully stopped and return the final state.
|
|
425
|
+
* @returns The sandbox metadata at the time the stop was acknowledged, or after fully stopped if `blocking` is true.
|
|
426
|
+
*/
|
|
427
|
+
async stop(opts) {
|
|
428
|
+
"use step";
|
|
429
|
+
this.sandbox = require_sandbox_snapshot.toSandboxSnapshot((await (await this.ensureClient()).stopSandbox({
|
|
430
|
+
sandboxId: this.sandbox.id,
|
|
431
|
+
signal: opts?.signal,
|
|
432
|
+
blocking: opts?.blocking
|
|
433
|
+
})).json.sandbox);
|
|
434
|
+
return this.sandbox;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Update the network policy for this sandbox.
|
|
438
|
+
*
|
|
439
|
+
* @param networkPolicy - The new network policy to apply.
|
|
440
|
+
* @param opts - Optional parameters.
|
|
441
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
442
|
+
* @returns A promise that resolves when the network policy is updated.
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* // Restrict to specific domains
|
|
446
|
+
* await sandbox.updateNetworkPolicy({
|
|
447
|
+
* allow: ["*.npmjs.org", "github.com"],
|
|
448
|
+
* });
|
|
449
|
+
*
|
|
450
|
+
* @example
|
|
451
|
+
* // Inject credentials with per-domain transformers
|
|
452
|
+
* await sandbox.updateNetworkPolicy({
|
|
453
|
+
* allow: {
|
|
454
|
+
* "ai-gateway.vercel.sh": [{
|
|
455
|
+
* transform: [{
|
|
456
|
+
* headers: { authorization: "Bearer ..." }
|
|
457
|
+
* }]
|
|
458
|
+
* }],
|
|
459
|
+
* "*": []
|
|
460
|
+
* }
|
|
461
|
+
* });
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* // Deny all network access
|
|
465
|
+
* await sandbox.updateNetworkPolicy("deny-all");
|
|
466
|
+
*/
|
|
467
|
+
async updateNetworkPolicy(networkPolicy, opts) {
|
|
468
|
+
"use step";
|
|
469
|
+
this.sandbox = require_sandbox_snapshot.toSandboxSnapshot((await (await this.ensureClient()).updateNetworkPolicy({
|
|
470
|
+
sandboxId: this.sandbox.id,
|
|
471
|
+
networkPolicy,
|
|
472
|
+
signal: opts?.signal
|
|
473
|
+
})).json.sandbox);
|
|
474
|
+
return this.sandbox.networkPolicy;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Extend the timeout of the sandbox by the specified duration.
|
|
478
|
+
*
|
|
479
|
+
* This allows you to extend the lifetime of a sandbox up until the maximum
|
|
480
|
+
* execution timeout for your plan.
|
|
481
|
+
*
|
|
482
|
+
* @param duration - The duration in milliseconds to extend the timeout by
|
|
483
|
+
* @param opts - Optional parameters.
|
|
484
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
485
|
+
* @returns A promise that resolves when the timeout is extended
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* const sandbox = await Sandbox.create({ timeout: ms('10m') });
|
|
489
|
+
* // Extends timeout by 5 minutes, to a total of 15 minutes.
|
|
490
|
+
* await sandbox.extendTimeout(ms('5m'));
|
|
491
|
+
*/
|
|
492
|
+
async extendTimeout(duration, opts) {
|
|
493
|
+
"use step";
|
|
494
|
+
this.sandbox = require_sandbox_snapshot.toSandboxSnapshot((await (await this.ensureClient()).extendTimeout({
|
|
495
|
+
sandboxId: this.sandbox.id,
|
|
496
|
+
duration,
|
|
497
|
+
signal: opts?.signal
|
|
498
|
+
})).json.sandbox);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Create a snapshot from this currently running sandbox. New sandboxes can
|
|
502
|
+
* then be created from this snapshot using {@link Sandbox.createFromSnapshot}.
|
|
503
|
+
*
|
|
504
|
+
* Note: this sandbox will be stopped as part of the snapshot creation process.
|
|
505
|
+
*
|
|
506
|
+
* @param opts - Optional parameters.
|
|
507
|
+
* @param opts.expiration - Optional expiration time in milliseconds. Use 0 for no expiration at all.
|
|
508
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
509
|
+
* @returns A promise that resolves to the Snapshot instance
|
|
510
|
+
*/
|
|
511
|
+
async snapshot(opts) {
|
|
512
|
+
"use step";
|
|
513
|
+
const client = await this.ensureClient();
|
|
514
|
+
const response = await client.createSnapshot({
|
|
515
|
+
sandboxId: this.sandbox.id,
|
|
516
|
+
expiration: opts?.expiration,
|
|
517
|
+
signal: opts?.signal
|
|
518
|
+
});
|
|
519
|
+
this.sandbox = require_sandbox_snapshot.toSandboxSnapshot(response.json.sandbox);
|
|
520
|
+
return new require_snapshot.Snapshot({
|
|
521
|
+
client,
|
|
522
|
+
snapshot: response.json.snapshot
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
/**
|
|
527
|
+
* A {@link Sandbox} that can automatically be disposed using a `await using` statement.
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* {
|
|
531
|
+
* await using const sandbox = await Sandbox.create();
|
|
532
|
+
* }
|
|
533
|
+
* // Sandbox is automatically stopped here
|
|
534
|
+
*/
|
|
535
|
+
var DisposableSandbox = class extends Sandbox {
|
|
536
|
+
async [Symbol.asyncDispose]() {
|
|
537
|
+
await this.stop();
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
//#endregion
|
|
542
|
+
exports.Sandbox = Sandbox;
|
|
543
|
+
//# sourceMappingURL=sandbox.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.cjs","names":["getCredentials","APIClient","WORKFLOW_SERIALIZE","WORKFLOW_DESERIALIZE","getPrivateParams","toSandboxSnapshot","Command","params: RunCommandParams","command","CommandFinished","path","consumeReadable","Snapshot"],"sources":["../src/sandbox.ts"],"sourcesContent":["import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from \"@workflow/serde\";\nimport { createWriteStream } from \"fs\";\nimport { mkdir } from \"fs/promises\";\nimport { dirname, resolve } from \"path\";\nimport type { Writable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport type { WithFetchOptions } from \"./api-client/api-client.js\";\nimport type { SandboxMetaData, SandboxRouteData } from \"./api-client/index.js\";\nimport { APIClient } from \"./api-client/index.js\";\nimport { Command, CommandFinished } from \"./command.js\";\nimport type { RUNTIMES } from \"./constants.js\";\nimport type {\n NetworkPolicy,\n NetworkPolicyRule,\n NetworkTransformer,\n} from \"./network-policy.js\";\nimport { Snapshot } from \"./snapshot.js\";\nimport { consumeReadable } from \"./utils/consume-readable.js\";\nimport { type Credentials, getCredentials } from \"./utils/get-credentials.js\";\nimport {\n type SandboxSnapshot,\n toSandboxSnapshot,\n} from \"./utils/sandbox-snapshot.js\";\nimport { getPrivateParams, type WithPrivate } from \"./utils/types.js\";\n\nexport type { NetworkPolicy, NetworkPolicyRule, NetworkTransformer };\n\n/** @inline */\nexport interface BaseCreateSandboxParams {\n /**\n * The source of the sandbox.\n *\n * Omit this parameter start a sandbox without a source.\n *\n * For git sources:\n * - `depth`: Creates shallow clones with limited commit history (minimum: 1)\n * - `revision`: Clones and checks out a specific commit, branch, or tag\n */\n source?:\n | {\n type: \"git\";\n url: string;\n depth?: number;\n revision?: string;\n }\n | {\n type: \"git\";\n url: string;\n username: string;\n password: string;\n depth?: number;\n revision?: string;\n }\n | { type: \"tarball\"; url: string };\n /**\n * Array of port numbers to expose from the sandbox. Sandboxes can\n * expose up to 4 ports.\n */\n ports?: number[];\n /**\n * Timeout in milliseconds before the sandbox auto-terminates.\n */\n timeout?: number;\n /**\n * Resources to allocate to the sandbox.\n *\n * Your sandbox will get the amount of vCPUs you specify here and\n * 2048 MB of memory per vCPU.\n */\n resources?: { vcpus: number };\n\n /**\n * The runtime of the sandbox, currently only `node24`, `node22` and `python3.13` are supported.\n * If not specified, the default runtime `node24` will be used.\n */\n runtime?: RUNTIMES | (string & {});\n\n /**\n * Network policy to define network restrictions for the sandbox.\n * Defaults to full internet access if not specified.\n */\n networkPolicy?: NetworkPolicy;\n\n /**\n * Default environment variables for the sandbox.\n * These are inherited by all commands unless overridden with\n * the `env` option in `runCommand`.\n *\n * @example\n * const sandbox = await Sandbox.create({\n * env: { NODE_ENV: \"production\", API_KEY: \"secret\" },\n * });\n * // All commands will have NODE_ENV and API_KEY set\n * await sandbox.runCommand(\"node\", [\"app.js\"]);\n */\n env?: Record<string, string>;\n\n /**\n * An AbortSignal to cancel sandbox creation.\n */\n signal?: AbortSignal;\n}\n\nexport type CreateSandboxParams =\n | BaseCreateSandboxParams\n | (Omit<BaseCreateSandboxParams, \"runtime\" | \"source\"> & {\n source: { type: \"snapshot\"; snapshotId: string };\n });\n\n/** @inline */\ninterface GetSandboxParams {\n /**\n * Unique identifier of the sandbox.\n */\n sandboxId: string;\n /**\n * An AbortSignal to cancel the operation.\n */\n signal?: AbortSignal;\n}\n\n/**\n * Serialized representation of a Sandbox for @workflow/serde.\n */\nexport interface SerializedSandbox {\n metadata: SandboxSnapshot;\n routes: SandboxRouteData[];\n}\n\n/** @inline */\ninterface RunCommandParams {\n /**\n * The command to execute\n */\n cmd: string;\n /**\n * Arguments to pass to the command\n */\n args?: string[];\n /**\n * Working directory to execute the command in\n */\n cwd?: string;\n /**\n * Environment variables to set for this command\n */\n env?: Record<string, string>;\n /**\n * If true, execute this command with root privileges. Defaults to false.\n */\n sudo?: boolean;\n /**\n * If true, the command will return without waiting for `exitCode`\n */\n detached?: boolean;\n /**\n * A `Writable` stream where `stdout` from the command will be piped\n */\n stdout?: Writable;\n /**\n * A `Writable` stream where `stderr` from the command will be piped\n */\n stderr?: Writable;\n /**\n * An AbortSignal to cancel the command execution\n */\n signal?: AbortSignal;\n}\n\n// ============================================================================\n// Sandbox class\n// ============================================================================\n\n/**\n * A Sandbox is an isolated Linux MicroVM to run commands in.\n *\n * Use {@link Sandbox.create} or {@link Sandbox.get} to construct.\n * @hideconstructor\n */\nexport class Sandbox {\n private _client: APIClient | null = null;\n\n /**\n * Lazily resolve credentials and construct an API client.\n * This is used in step contexts where the Sandbox was deserialized\n * without a client (e.g. when crossing workflow/step boundaries).\n * Uses getCredentials() which resolves from OIDC or env vars.\n * @internal\n */\n private async ensureClient(): Promise<APIClient> {\n \"use step\";\n if (this._client) return this._client;\n const credentials = await getCredentials();\n this._client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n });\n return this._client;\n }\n\n /**\n * Routes from ports to subdomains.\n /* @hidden\n */\n public readonly routes: SandboxRouteData[];\n\n /**\n * Unique ID of this sandbox.\n */\n public get sandboxId(): string {\n return this.sandbox.id;\n }\n\n public get interactivePort(): number | undefined {\n return this.sandbox.interactivePort ?? undefined;\n }\n\n /**\n * The status of the sandbox.\n */\n public get status(): SandboxMetaData[\"status\"] {\n return this.sandbox.status;\n }\n\n /**\n * The creation date of the sandbox.\n */\n public get createdAt(): Date {\n return new Date(this.sandbox.createdAt);\n }\n\n /**\n * The timeout of the sandbox in milliseconds.\n */\n public get timeout(): number {\n return this.sandbox.timeout;\n }\n\n /**\n * The network policy of the sandbox.\n */\n public get networkPolicy(): NetworkPolicy | undefined {\n return this.sandbox.networkPolicy;\n }\n\n /**\n * If the sandbox was created from a snapshot, the ID of that snapshot.\n */\n public get sourceSnapshotId(): string | undefined {\n return this.sandbox.sourceSnapshotId;\n }\n\n /**\n * The amount of CPU used by the sandbox. Only reported once the VM is stopped.\n */\n public get activeCpuUsageMs(): number | undefined {\n return this.sandbox.activeCpuDurationMs;\n }\n\n /**\n * The amount of network data used by the sandbox. Only reported once the VM is stopped.\n */\n public get networkTransfer():\n | { ingress: number; egress: number }\n | undefined {\n return this.sandbox.networkTransfer;\n }\n\n /**\n * Internal metadata about this sandbox.\n */\n private sandbox: SandboxSnapshot;\n\n /**\n * Allow to get a list of sandboxes for a team narrowed to the given params.\n * It returns both the sandboxes and the pagination metadata to allow getting\n * the next page of results.\n */\n static async list(\n params?: Partial<Parameters<APIClient[\"listSandboxes\"]>[0]> &\n Partial<Credentials> &\n WithFetchOptions,\n ) {\n \"use step\";\n const credentials = await getCredentials(params);\n const client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n fetch: params?.fetch,\n });\n return client.listSandboxes({\n ...credentials,\n ...params,\n });\n }\n\n /**\n * Serialize a Sandbox instance to plain data for @workflow/serde.\n *\n * @param instance - The Sandbox instance to serialize\n * @returns A plain object containing sandbox metadata and routes\n */\n static [WORKFLOW_SERIALIZE](instance: Sandbox): SerializedSandbox {\n return {\n metadata: instance.sandbox,\n routes: instance.routes,\n };\n }\n\n /**\n * Deserialize a Sandbox from serialized snapshot data.\n *\n * The deserialized instance uses the serialized metadata synchronously and\n * lazily creates an API client only when methods perform API requests.\n *\n * @param data - The serialized sandbox data\n * @returns The reconstructed Sandbox instance\n */\n static [WORKFLOW_DESERIALIZE](data: SerializedSandbox): Sandbox {\n return new Sandbox({\n sandbox: data.metadata,\n routes: data.routes,\n });\n }\n\n /**\n * Create a new sandbox.\n *\n * @param params - Creation parameters and optional credentials.\n * @returns A promise resolving to the created {@link Sandbox}.\n * @example\n * <caption>Create a sandbox and drop it in the end of the block</caption>\n * async function fn() {\n * await using const sandbox = await Sandbox.create();\n * // Sandbox automatically stopped at the end of the lexical scope\n * }\n */\n static async create(\n params?: WithPrivate<\n CreateSandboxParams | (CreateSandboxParams & Credentials)\n > &\n WithFetchOptions,\n ): Promise<Sandbox & AsyncDisposable> {\n \"use step\";\n const credentials = await getCredentials(params);\n const client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n fetch: params?.fetch,\n });\n\n const privateParams = getPrivateParams(params);\n const sandbox = await client.createSandbox({\n source: params?.source,\n projectId: credentials.projectId,\n ports: params?.ports ?? [],\n timeout: params?.timeout,\n resources: params?.resources,\n runtime: params && \"runtime\" in params ? params?.runtime : undefined,\n networkPolicy: params?.networkPolicy,\n env: params?.env,\n signal: params?.signal,\n ...privateParams,\n });\n\n return new DisposableSandbox({\n client,\n sandbox: toSandboxSnapshot(sandbox.json.sandbox),\n routes: sandbox.json.routes,\n });\n }\n\n /**\n * Retrieve an existing sandbox.\n *\n * @param params - Get parameters and optional credentials.\n * @returns A promise resolving to the {@link Sandbox}.\n */\n static async get(\n params: WithPrivate<GetSandboxParams | (GetSandboxParams & Credentials)> &\n WithFetchOptions,\n ): Promise<Sandbox> {\n \"use step\";\n const credentials = await getCredentials(params);\n const client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n fetch: params.fetch,\n });\n\n const privateParams = getPrivateParams(params);\n const sandbox = await client.getSandbox({\n sandboxId: params.sandboxId,\n signal: params.signal,\n ...privateParams,\n });\n\n return new Sandbox({\n client,\n sandbox: toSandboxSnapshot(sandbox.json.sandbox),\n routes: sandbox.json.routes,\n });\n }\n\n /**\n * Create a new Sandbox instance.\n *\n * @param params.client - Optional API client. If not provided, will be lazily created using global credentials.\n * @param params.routes - Port-to-subdomain mappings for exposed ports\n * @param params.sandbox - Sandbox snapshot metadata\n */\n constructor({\n client,\n routes,\n sandbox,\n }: {\n client?: APIClient;\n routes: SandboxRouteData[];\n sandbox: SandboxSnapshot;\n }) {\n this._client = client ?? null;\n this.routes = routes;\n this.sandbox = sandbox;\n }\n\n /**\n * Get a previously run command by its ID.\n *\n * @param cmdId - ID of the command to retrieve\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A {@link Command} instance representing the command\n */\n async getCommand(\n cmdId: string,\n opts?: { signal?: AbortSignal },\n ): Promise<Command> {\n \"use step\";\n const client = await this.ensureClient();\n const command = await client.getCommand({\n sandboxId: this.sandbox.id,\n cmdId,\n signal: opts?.signal,\n });\n\n return new Command({\n client,\n sandboxId: this.sandbox.id,\n cmd: command.json.command,\n });\n }\n\n /**\n * Start executing a command in this sandbox.\n *\n * @param command - The command to execute.\n * @param args - Arguments to pass to the command.\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the command execution.\n * @returns A {@link CommandFinished} result once execution is done.\n */\n async runCommand(\n command: string,\n args?: string[],\n opts?: { signal?: AbortSignal },\n ): Promise<CommandFinished>;\n\n /**\n * Start executing a command in detached mode.\n *\n * @param params - The command parameters.\n * @returns A {@link Command} instance for the running command.\n */\n async runCommand(\n params: RunCommandParams & { detached: true },\n ): Promise<Command>;\n\n /**\n * Start executing a command in this sandbox.\n *\n * @param params - The command parameters.\n * @returns A {@link CommandFinished} result once execution is done.\n */\n async runCommand(params: RunCommandParams): Promise<CommandFinished>;\n\n async runCommand(\n commandOrParams: string | RunCommandParams,\n args?: string[],\n opts?: { signal?: AbortSignal },\n ): Promise<Command | CommandFinished> {\n \"use step\";\n const client = await this.ensureClient();\n const params: RunCommandParams =\n typeof commandOrParams === \"string\"\n ? { cmd: commandOrParams, args, signal: opts?.signal }\n : commandOrParams;\n\n const wait = params.detached ? false : true;\n const pipeLogs = async (command: Command): Promise<void> => {\n if (!params.stdout && !params.stderr) {\n return;\n }\n\n try {\n for await (const log of command.logs({ signal: params.signal })) {\n if (log.stream === \"stdout\") {\n params.stdout?.write(log.data);\n } else if (log.stream === \"stderr\") {\n params.stderr?.write(log.data);\n }\n }\n } catch (err) {\n if (params.signal?.aborted) {\n return;\n }\n throw err;\n }\n };\n\n if (wait) {\n const commandStream = await client.runCommand({\n sandboxId: this.sandbox.id,\n command: params.cmd,\n args: params.args ?? [],\n cwd: params.cwd,\n env: params.env ?? {},\n sudo: params.sudo ?? false,\n wait: true,\n signal: params.signal,\n });\n\n const command = new Command({\n client,\n sandboxId: this.sandbox.id,\n cmd: commandStream.command,\n });\n\n const [finished] = await Promise.all([\n commandStream.finished,\n pipeLogs(command),\n ]);\n return new CommandFinished({\n client,\n sandboxId: this.sandbox.id,\n cmd: finished,\n exitCode: finished.exitCode ?? 0,\n });\n }\n\n const commandResponse = await client.runCommand({\n sandboxId: this.sandbox.id,\n command: params.cmd,\n args: params.args ?? [],\n cwd: params.cwd,\n env: params.env ?? {},\n sudo: params.sudo ?? false,\n signal: params.signal,\n });\n\n const command = new Command({\n client,\n sandboxId: this.sandbox.id,\n cmd: commandResponse.json.command,\n });\n\n void pipeLogs(command).catch((err) => {\n if (params.signal?.aborted) {\n return;\n }\n (params.stderr ?? params.stdout)?.emit(\"error\", err);\n });\n\n return command;\n }\n\n /**\n * Create a directory in the filesystem of this sandbox.\n *\n * @param path - Path of the directory to create\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n */\n async mkDir(path: string, opts?: { signal?: AbortSignal }): Promise<void> {\n \"use step\";\n const client = await this.ensureClient();\n await client.mkDir({\n sandboxId: this.sandbox.id,\n path: path,\n signal: opts?.signal,\n });\n }\n\n /**\n * Read a file from the filesystem of this sandbox as a stream.\n *\n * @param file - File to read, with path and optional cwd\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves to a ReadableStream containing the file contents, or null if file not found\n */\n async readFile(\n file: { path: string; cwd?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<NodeJS.ReadableStream | null> {\n \"use step\";\n const client = await this.ensureClient();\n return client.readFile({\n sandboxId: this.sandbox.id,\n path: file.path,\n cwd: file.cwd,\n signal: opts?.signal,\n });\n }\n\n /**\n * Read a file from the filesystem of this sandbox as a Buffer.\n *\n * @param file - File to read, with path and optional cwd\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves to the file contents as a Buffer, or null if file not found\n */\n async readFileToBuffer(\n file: { path: string; cwd?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<Buffer | null> {\n \"use step\";\n const client = await this.ensureClient();\n const stream = await client.readFile({\n sandboxId: this.sandbox.id,\n path: file.path,\n cwd: file.cwd,\n signal: opts?.signal,\n });\n\n if (stream === null) {\n return null;\n }\n\n return consumeReadable(stream);\n }\n\n /**\n * Download a file from the sandbox to the local filesystem.\n *\n * @param src - Source file on the sandbox, with path and optional cwd\n * @param dst - Destination file on the local machine, with path and optional cwd\n * @param opts - Optional parameters.\n * @param opts.mkdirRecursive - If true, create parent directories for the destination if they don't exist.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns The absolute path to the written file, or null if the source file was not found\n */\n async downloadFile(\n src: { path: string; cwd?: string },\n dst: { path: string; cwd?: string },\n opts?: { mkdirRecursive?: boolean; signal?: AbortSignal },\n ): Promise<string | null> {\n \"use step\";\n const client = await this.ensureClient();\n if (!src?.path) {\n throw new Error(\"downloadFile: source path is required\");\n }\n\n if (!dst?.path) {\n throw new Error(\"downloadFile: destination path is required\");\n }\n\n const stream = await client.readFile({\n sandboxId: this.sandbox.id,\n path: src.path,\n cwd: src.cwd,\n signal: opts?.signal,\n });\n\n if (stream === null) {\n return null;\n }\n\n try {\n const dstPath = resolve(dst.cwd ?? \"\", dst.path);\n if (opts?.mkdirRecursive) {\n await mkdir(dirname(dstPath), { recursive: true });\n }\n await pipeline(stream, createWriteStream(dstPath), {\n signal: opts?.signal,\n });\n return dstPath;\n } finally {\n stream.destroy();\n }\n }\n\n /**\n * Write files to the filesystem of this sandbox.\n * Defaults to writing to /vercel/sandbox unless an absolute path is specified.\n * Writes files using the `vercel-sandbox` user.\n *\n * @param files - Array of files with path, content, and optional mode (permissions)\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves when the files are written\n *\n * @example\n * // Write an executable script\n * await sandbox.writeFiles([\n * { path: \"/usr/local/bin/myscript\", content: \"#!/bin/bash\\necho hello\", mode: 0o755 }\n * ]);\n */\n async writeFiles(\n files: {\n path: string;\n content: string | Uint8Array;\n mode?: number;\n }[],\n opts?: { signal?: AbortSignal },\n ) {\n \"use step\";\n const client = await this.ensureClient();\n return client.writeFiles({\n sandboxId: this.sandbox.id,\n cwd: this.sandbox.cwd,\n extractDir: \"/\",\n files: files,\n signal: opts?.signal,\n });\n }\n\n /**\n * Get the public domain of a port of this sandbox.\n *\n * @param p - Port number to resolve\n * @returns A full domain (e.g. `https://subdomain.vercel.run`)\n * @throws If the port has no associated route\n */\n domain(p: number): string {\n const route = this.routes.find(({ port }) => port == p);\n if (route) {\n return `https://${route.subdomain}.vercel.run`;\n } else {\n throw new Error(`No route for port ${p}`);\n }\n }\n\n /**\n * Stop the sandbox.\n *\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @param opts.blocking - If true, poll until the sandbox has fully stopped and return the final state.\n * @returns The sandbox metadata at the time the stop was acknowledged, or after fully stopped if `blocking` is true.\n */\n async stop(opts?: {\n signal?: AbortSignal;\n blocking?: boolean;\n }): Promise<SandboxSnapshot> {\n \"use step\";\n const client = await this.ensureClient();\n const response = await client.stopSandbox({\n sandboxId: this.sandbox.id,\n signal: opts?.signal,\n blocking: opts?.blocking,\n });\n this.sandbox = toSandboxSnapshot(response.json.sandbox);\n return this.sandbox;\n }\n\n /**\n * Update the network policy for this sandbox.\n *\n * @param networkPolicy - The new network policy to apply.\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves when the network policy is updated.\n *\n * @example\n * // Restrict to specific domains\n * await sandbox.updateNetworkPolicy({\n * allow: [\"*.npmjs.org\", \"github.com\"],\n * });\n *\n * @example\n * // Inject credentials with per-domain transformers\n * await sandbox.updateNetworkPolicy({\n * allow: {\n * \"ai-gateway.vercel.sh\": [{\n * transform: [{\n * headers: { authorization: \"Bearer ...\" }\n * }]\n * }],\n * \"*\": []\n * }\n * });\n *\n * @example\n * // Deny all network access\n * await sandbox.updateNetworkPolicy(\"deny-all\");\n */\n async updateNetworkPolicy(\n networkPolicy: NetworkPolicy,\n opts?: { signal?: AbortSignal },\n ): Promise<NetworkPolicy> {\n \"use step\";\n const client = await this.ensureClient();\n const response = await client.updateNetworkPolicy({\n sandboxId: this.sandbox.id,\n networkPolicy: networkPolicy,\n signal: opts?.signal,\n });\n\n // Update the internal sandbox metadata with the new timeout value\n this.sandbox = toSandboxSnapshot(response.json.sandbox);\n return this.sandbox.networkPolicy!;\n }\n\n /**\n * Extend the timeout of the sandbox by the specified duration.\n *\n * This allows you to extend the lifetime of a sandbox up until the maximum\n * execution timeout for your plan.\n *\n * @param duration - The duration in milliseconds to extend the timeout by\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves when the timeout is extended\n *\n * @example\n * const sandbox = await Sandbox.create({ timeout: ms('10m') });\n * // Extends timeout by 5 minutes, to a total of 15 minutes.\n * await sandbox.extendTimeout(ms('5m'));\n */\n async extendTimeout(\n duration: number,\n opts?: { signal?: AbortSignal },\n ): Promise<void> {\n \"use step\";\n const client = await this.ensureClient();\n const response = await client.extendTimeout({\n sandboxId: this.sandbox.id,\n duration,\n signal: opts?.signal,\n });\n\n // Update the internal sandbox metadata with the new timeout value\n this.sandbox = toSandboxSnapshot(response.json.sandbox);\n }\n\n /**\n * Create a snapshot from this currently running sandbox. New sandboxes can\n * then be created from this snapshot using {@link Sandbox.createFromSnapshot}.\n *\n * Note: this sandbox will be stopped as part of the snapshot creation process.\n *\n * @param opts - Optional parameters.\n * @param opts.expiration - Optional expiration time in milliseconds. Use 0 for no expiration at all.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves to the Snapshot instance\n */\n async snapshot(opts?: {\n expiration?: number;\n signal?: AbortSignal;\n }): Promise<Snapshot> {\n \"use step\";\n const client = await this.ensureClient();\n const response = await client.createSnapshot({\n sandboxId: this.sandbox.id,\n expiration: opts?.expiration,\n signal: opts?.signal,\n });\n\n this.sandbox = toSandboxSnapshot(response.json.sandbox);\n\n return new Snapshot({\n client,\n snapshot: response.json.snapshot,\n });\n }\n}\n\n/**\n * A {@link Sandbox} that can automatically be disposed using a `await using` statement.\n *\n * @example\n * {\n * await using const sandbox = await Sandbox.create();\n * }\n * // Sandbox is automatically stopped here\n */\nclass DisposableSandbox extends Sandbox implements AsyncDisposable {\n async [Symbol.asyncDispose]() {\n await this.stop();\n }\n}\n"],"mappings":"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"}
|