@vercel/sandbox 1.1.8 → 1.2.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +14 -14
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +20 -0
- package/dist/api-client/api-client.d.ts +18 -13
- package/dist/api-client/api-client.js +39 -0
- package/dist/api-client/api-client.js.map +1 -1
- package/dist/api-client/validators.d.ts +1 -0
- package/dist/api-client/validators.js.map +1 -1
- package/dist/command.d.ts +0 -1
- package/dist/command.js +5 -10
- package/dist/command.js.map +1 -1
- package/dist/sandbox.d.ts +46 -6
- package/dist/sandbox.js +132 -24
- package/dist/sandbox.js.map +1 -1
- package/dist/utils/get-credentials.js +2 -1
- package/dist/utils/get-credentials.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/api-client/api-client.test.ts +52 -0
- package/src/api-client/api-client.ts +73 -1
- package/src/api-client/validators.ts +2 -0
- package/src/command.ts +6 -13
- package/src/sandbox.test.ts +79 -1
- package/src/sandbox.ts +152 -26
- package/src/utils/get-credentials.ts +2 -1
- package/src/version.ts +1 -1
package/dist/sandbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":";;;AAEA,6CAAyC;AACzC,
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ class LocalOidcContextError extends Error {
|
|
|
17
17
|
"Please link your Vercel project using `npx vercel link`.",
|
|
18
18
|
"Then, pull an initial OIDC token with `npx vercel env pull`",
|
|
19
19
|
"and retry.",
|
|
20
|
+
"╰▶ Make sure you are loading `.env.local` correctly, or passing $VERCEL_OIDC_TOKEN directly."
|
|
20
21
|
].join("\n");
|
|
21
22
|
super(message, { cause });
|
|
22
23
|
this.name = "LocalOidcContextError";
|
|
@@ -32,7 +33,7 @@ class VercelOidcContextError extends Error {
|
|
|
32
33
|
const message = [
|
|
33
34
|
"Could not get credentials from OIDC context.",
|
|
34
35
|
"Please make sure OIDC is set up for your project",
|
|
35
|
-
"
|
|
36
|
+
"╰▶ Docs: https://vercel.com/docs/oidc",
|
|
36
37
|
].join("\n");
|
|
37
38
|
super(message, { cause });
|
|
38
39
|
this.name = "VercelOidcContextError";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-credentials.js","sourceRoot":"","sources":["../../src/utils/get-credentials.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"get-credentials.js","sourceRoot":"","sources":["../../src/utils/get-credentials.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.2.0";
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -173,4 +173,56 @@ describe("APIClient", () => {
|
|
|
173
173
|
}
|
|
174
174
|
});
|
|
175
175
|
});
|
|
176
|
+
|
|
177
|
+
describe("runCommand", () => {
|
|
178
|
+
let client: APIClient;
|
|
179
|
+
let mockFetch: ReturnType<typeof vi.fn>;
|
|
180
|
+
|
|
181
|
+
beforeEach(() => {
|
|
182
|
+
mockFetch = vi.fn();
|
|
183
|
+
client = new APIClient({
|
|
184
|
+
teamId: "team_123",
|
|
185
|
+
token: "1234",
|
|
186
|
+
fetch: mockFetch,
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("streams command data when wait is true", async () => {
|
|
191
|
+
const first = {
|
|
192
|
+
command: {
|
|
193
|
+
id: "cmd_123",
|
|
194
|
+
name: "echo",
|
|
195
|
+
args: ["hello"],
|
|
196
|
+
cwd: "/",
|
|
197
|
+
sandboxId: "sbx_123",
|
|
198
|
+
exitCode: null,
|
|
199
|
+
startedAt: 1,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
const second = {
|
|
203
|
+
command: {
|
|
204
|
+
...first.command,
|
|
205
|
+
exitCode: 0,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
mockFetch.mockResolvedValue(
|
|
210
|
+
new Response(createNdjsonStream([first, second]), {
|
|
211
|
+
headers: { "content-type": "application/x-ndjson" },
|
|
212
|
+
}),
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const result = await client.runCommand({
|
|
216
|
+
sandboxId: "sbx_123",
|
|
217
|
+
command: "echo",
|
|
218
|
+
args: ["hello"],
|
|
219
|
+
env: {},
|
|
220
|
+
sudo: false,
|
|
221
|
+
wait: true,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
expect(result.command.exitCode).toBeNull();
|
|
225
|
+
await expect(result.finished).resolves.toMatchObject({ exitCode: 0 });
|
|
226
|
+
});
|
|
227
|
+
});
|
|
176
228
|
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type RequestParams,
|
|
6
6
|
} from "./base-client";
|
|
7
7
|
import {
|
|
8
|
+
CommandFinishedData,
|
|
8
9
|
SandboxAndRoutesResponse,
|
|
9
10
|
SandboxResponse,
|
|
10
11
|
CommandResponse,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
ExtendTimeoutResponse,
|
|
18
19
|
SnapshotResponse,
|
|
19
20
|
CreateSnapshotResponse,
|
|
21
|
+
type CommandData,
|
|
20
22
|
} from "./validators";
|
|
21
23
|
import { APIError, StreamError } from "./api-error";
|
|
22
24
|
import { FileWriter } from "./file-writer";
|
|
@@ -148,8 +150,78 @@ export class APIClient extends BaseClient {
|
|
|
148
150
|
args: string[];
|
|
149
151
|
env: Record<string, string>;
|
|
150
152
|
sudo: boolean;
|
|
153
|
+
wait: true;
|
|
154
|
+
signal?: AbortSignal;
|
|
155
|
+
}): Promise<{ command: CommandData; finished: Promise<CommandFinishedData> }>;
|
|
156
|
+
async runCommand(params: {
|
|
157
|
+
sandboxId: string;
|
|
158
|
+
cwd?: string;
|
|
159
|
+
command: string;
|
|
160
|
+
args: string[];
|
|
161
|
+
env: Record<string, string>;
|
|
162
|
+
sudo: boolean;
|
|
163
|
+
wait?: false;
|
|
164
|
+
signal?: AbortSignal;
|
|
165
|
+
}): Promise<Parsed<z.infer<typeof CommandResponse>>>;
|
|
166
|
+
async runCommand(params: {
|
|
167
|
+
sandboxId: string;
|
|
168
|
+
cwd?: string;
|
|
169
|
+
command: string;
|
|
170
|
+
args: string[];
|
|
171
|
+
env: Record<string, string>;
|
|
172
|
+
sudo: boolean;
|
|
173
|
+
wait?: boolean;
|
|
151
174
|
signal?: AbortSignal;
|
|
152
175
|
}) {
|
|
176
|
+
if (params.wait) {
|
|
177
|
+
const response = await this.request(
|
|
178
|
+
`/v1/sandboxes/${params.sandboxId}/cmd`,
|
|
179
|
+
{
|
|
180
|
+
method: "POST",
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
command: params.command,
|
|
183
|
+
args: params.args,
|
|
184
|
+
cwd: params.cwd,
|
|
185
|
+
env: params.env,
|
|
186
|
+
sudo: params.sudo,
|
|
187
|
+
wait: true,
|
|
188
|
+
}),
|
|
189
|
+
signal: params.signal,
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
if (response.headers.get("content-type") !== "application/x-ndjson") {
|
|
194
|
+
throw new APIError(response, {
|
|
195
|
+
message: "Expected a stream of command data",
|
|
196
|
+
sandboxId: params.sandboxId,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (response.body === null) {
|
|
201
|
+
throw new APIError(response, {
|
|
202
|
+
message: "No response body",
|
|
203
|
+
sandboxId: params.sandboxId,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const jsonlinesStream = jsonlines.parse();
|
|
208
|
+
pipe(response.body, jsonlinesStream).catch((err) => {
|
|
209
|
+
console.error("Error piping command stream:", err);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const iterator = jsonlinesStream[Symbol.asyncIterator]();
|
|
213
|
+
const commandChunk = await iterator.next();
|
|
214
|
+
const { command } = CommandResponse.parse(commandChunk.value);
|
|
215
|
+
|
|
216
|
+
const finished = (async () => {
|
|
217
|
+
const finishedChunk = await iterator.next();
|
|
218
|
+
const { command } = CommandFinishedResponse.parse(finishedChunk.value);
|
|
219
|
+
return command;
|
|
220
|
+
})();
|
|
221
|
+
|
|
222
|
+
return { command, finished };
|
|
223
|
+
}
|
|
224
|
+
|
|
153
225
|
return parseOrThrow(
|
|
154
226
|
CommandResponse,
|
|
155
227
|
await this.request(`/v1/sandboxes/${params.sandboxId}/cmd`, {
|
|
@@ -316,7 +388,7 @@ export class APIClient extends BaseClient {
|
|
|
316
388
|
path: string;
|
|
317
389
|
cwd?: string;
|
|
318
390
|
signal?: AbortSignal;
|
|
319
|
-
}): Promise<
|
|
391
|
+
}): Promise<Readable | null> {
|
|
320
392
|
const response = await this.request(
|
|
321
393
|
`/v1/sandboxes/${params.sandboxId}/fs/read`,
|
|
322
394
|
{
|
|
@@ -97,6 +97,8 @@ export const CommandResponse = z.object({
|
|
|
97
97
|
command: Command,
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
+
export type CommandFinishedData = z.infer<typeof CommandFinishedResponse>["command"];
|
|
101
|
+
|
|
100
102
|
export const CommandFinishedResponse = z.object({
|
|
101
103
|
command: CommandFinished,
|
|
102
104
|
});
|
package/src/command.ts
CHANGED
|
@@ -33,9 +33,7 @@ export class Command {
|
|
|
33
33
|
|
|
34
34
|
public exitCode: number | null;
|
|
35
35
|
|
|
36
|
-
private outputCache: {
|
|
37
|
-
null;
|
|
38
|
-
private outputCachePromise: Promise<{
|
|
36
|
+
private outputCache: Promise<{
|
|
39
37
|
stdout: string;
|
|
40
38
|
stderr: string;
|
|
41
39
|
both: string;
|
|
@@ -151,12 +149,8 @@ export class Command {
|
|
|
151
149
|
stderr: string;
|
|
152
150
|
both: string;
|
|
153
151
|
}> {
|
|
154
|
-
if (this.outputCache) {
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!this.outputCachePromise) {
|
|
159
|
-
this.outputCachePromise = (async () => {
|
|
152
|
+
if (!this.outputCache) {
|
|
153
|
+
this.outputCache = (async () => {
|
|
160
154
|
try {
|
|
161
155
|
let stdout = "";
|
|
162
156
|
let stderr = "";
|
|
@@ -169,17 +163,16 @@ export class Command {
|
|
|
169
163
|
stderr += log.data;
|
|
170
164
|
}
|
|
171
165
|
}
|
|
172
|
-
|
|
173
|
-
return this.outputCache;
|
|
166
|
+
return { stdout, stderr, both };
|
|
174
167
|
} catch (err) {
|
|
175
168
|
// Clear the promise so future calls can retry
|
|
176
|
-
this.
|
|
169
|
+
this.outputCache = null;
|
|
177
170
|
throw err;
|
|
178
171
|
}
|
|
179
172
|
})();
|
|
180
173
|
}
|
|
181
174
|
|
|
182
|
-
return this.
|
|
175
|
+
return this.outputCache;
|
|
183
176
|
}
|
|
184
177
|
|
|
185
178
|
/**
|
package/src/sandbox.test.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { it, beforeEach, afterEach, expect, describe } from "vitest";
|
|
|
2
2
|
import { consumeReadable } from "./utils/consume-readable";
|
|
3
3
|
import { Sandbox } from "./sandbox";
|
|
4
4
|
import { APIError } from "./api-client/api-error";
|
|
5
|
+
import { mkdtemp, readFile, rm } from "fs/promises";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
import { join, resolve } from "path";
|
|
5
8
|
import ms from "ms";
|
|
6
9
|
|
|
7
10
|
describe.skipIf(process.env.RUN_INTEGRATION_TESTS !== "1")("Sandbox", () => {
|
|
@@ -16,7 +19,7 @@ describe.skipIf(process.env.RUN_INTEGRATION_TESTS !== "1")("Sandbox", () => {
|
|
|
16
19
|
await sandbox.stop();
|
|
17
20
|
});
|
|
18
21
|
|
|
19
|
-
it("allows to write files and then read them", async () => {
|
|
22
|
+
it("allows to write files and then read them as a stream", async () => {
|
|
20
23
|
await sandbox.writeFiles([
|
|
21
24
|
{ path: "hello1.txt", content: Buffer.from("Hello 1") },
|
|
22
25
|
{ path: "hello2.txt", content: Buffer.from("Hello 2") },
|
|
@@ -28,6 +31,81 @@ describe.skipIf(process.env.RUN_INTEGRATION_TESTS !== "1")("Sandbox", () => {
|
|
|
28
31
|
expect((await consumeReadable(content2!)).toString()).toBe("Hello 2");
|
|
29
32
|
});
|
|
30
33
|
|
|
34
|
+
it("allows to write files and then read them to a buffer", async () => {
|
|
35
|
+
await sandbox.writeFiles([
|
|
36
|
+
{ path: "hello1.txt", content: Buffer.from("Hello 1") },
|
|
37
|
+
{ path: "hello2.txt", content: Buffer.from("Hello 2") },
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
const content1 = await sandbox.readFileToBuffer({ path: "hello1.txt" });
|
|
41
|
+
const content2 = await sandbox.readFileToBuffer({ path: "hello2.txt" });
|
|
42
|
+
expect(content1?.toString()).toBe("Hello 1");
|
|
43
|
+
expect(content2?.toString()).toBe("Hello 2");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns null when reading a non-existent file to buffer", async () => {
|
|
47
|
+
const content = await sandbox.readFileToBuffer({
|
|
48
|
+
path: "non-existent.txt",
|
|
49
|
+
});
|
|
50
|
+
expect(content).toBeNull();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("allows downloading a file from the sandbox", async () => {
|
|
54
|
+
const fileContent = "Hello from sandbox";
|
|
55
|
+
await sandbox.writeFiles([
|
|
56
|
+
{ path: "download-test.txt", content: Buffer.from(fileContent) },
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const tmpDir = await mkdtemp(join(tmpdir(), "sandbox-test-"));
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const result = await sandbox.downloadFile(
|
|
63
|
+
{ path: "download-test.txt" },
|
|
64
|
+
{ path: "downloaded.txt", cwd: tmpDir },
|
|
65
|
+
);
|
|
66
|
+
expect(result).toBe(resolve(tmpDir, "downloaded.txt"));
|
|
67
|
+
expect(await readFile(result!, "utf-8")).toBe(fileContent);
|
|
68
|
+
} finally {
|
|
69
|
+
await rm(tmpDir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("returns null when downloading a non-existent file", async () => {
|
|
74
|
+
const tmpDir = await mkdtemp(join(tmpdir(), "sandbox-test-"));
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const result = await sandbox.downloadFile(
|
|
78
|
+
{ path: "non-existent.txt" },
|
|
79
|
+
{ path: "should-not-exist.txt", cwd: tmpDir },
|
|
80
|
+
);
|
|
81
|
+
expect(result).toBeNull();
|
|
82
|
+
} finally {
|
|
83
|
+
await rm(tmpDir, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("creates parent directories when mkdirRecursive is true", async () => {
|
|
88
|
+
const fileContent = "Hello from sandbox";
|
|
89
|
+
await sandbox.writeFiles([
|
|
90
|
+
{ path: "download-test.txt", content: Buffer.from(fileContent) },
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
const tmpDir = await mkdtemp(join(tmpdir(), "sandbox-test-"));
|
|
94
|
+
const nestedPath = join(tmpDir, "nested", "dir", "downloaded.txt");
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const result = await sandbox.downloadFile(
|
|
98
|
+
{ path: "download-test.txt" },
|
|
99
|
+
{ path: nestedPath },
|
|
100
|
+
{ mkdirRecursive: true },
|
|
101
|
+
);
|
|
102
|
+
expect(result).toBe(nestedPath);
|
|
103
|
+
expect(await readFile(result!, "utf-8")).toBe(fileContent);
|
|
104
|
+
} finally {
|
|
105
|
+
await rm(tmpDir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
31
109
|
it("verifies port forwarding works correctly", async () => {
|
|
32
110
|
const serverScript = `
|
|
33
111
|
const http = require('http');
|
package/src/sandbox.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { SandboxMetaData, SandboxRouteData } from "./api-client";
|
|
2
|
-
import type
|
|
2
|
+
import { type Writable } from "stream";
|
|
3
|
+
import { pipeline } from "stream/promises";
|
|
4
|
+
import { createWriteStream } from "fs";
|
|
5
|
+
import { mkdir } from "fs/promises";
|
|
6
|
+
import { dirname, join, resolve } from "path";
|
|
3
7
|
import { APIClient } from "./api-client";
|
|
4
|
-
import { Command,
|
|
8
|
+
import { Command, CommandFinished } from "./command";
|
|
5
9
|
import { type Credentials, getCredentials } from "./utils/get-credentials";
|
|
6
10
|
import { getPrivateParams, WithPrivate } from "./utils/types";
|
|
7
11
|
import { WithFetchOptions } from "./api-client/api-client";
|
|
8
12
|
import { RUNTIMES } from "./constants";
|
|
9
13
|
import { Snapshot } from "./snapshot";
|
|
14
|
+
import { consumeReadable } from "./utils/consume-readable";
|
|
10
15
|
|
|
11
16
|
/** @inline */
|
|
12
17
|
export interface BaseCreateSandboxParams {
|
|
@@ -208,13 +213,19 @@ export class Sandbox {
|
|
|
208
213
|
*
|
|
209
214
|
* @param params - Creation parameters and optional credentials.
|
|
210
215
|
* @returns A promise resolving to the created {@link Sandbox}.
|
|
216
|
+
* @example
|
|
217
|
+
* <caption>Create a sandbox and drop it in the end of the block</caption>
|
|
218
|
+
* async function fn() {
|
|
219
|
+
* await using const sandbox = await Sandbox.create();
|
|
220
|
+
* // Sandbox automatically stopped at the end of the lexical scope
|
|
221
|
+
* }
|
|
211
222
|
*/
|
|
212
223
|
static async create(
|
|
213
224
|
params?: WithPrivate<
|
|
214
225
|
CreateSandboxParams | (CreateSandboxParams & Credentials)
|
|
215
226
|
> &
|
|
216
227
|
WithFetchOptions,
|
|
217
|
-
): Promise<Sandbox> {
|
|
228
|
+
): Promise<Sandbox & AsyncDisposable> {
|
|
218
229
|
const credentials = await getCredentials(params);
|
|
219
230
|
const client = new APIClient({
|
|
220
231
|
teamId: credentials.teamId,
|
|
@@ -234,7 +245,7 @@ export class Sandbox {
|
|
|
234
245
|
...privateParams,
|
|
235
246
|
});
|
|
236
247
|
|
|
237
|
-
return new
|
|
248
|
+
return new DisposableSandbox({
|
|
238
249
|
client,
|
|
239
250
|
sandbox: sandbox.json.sandbox,
|
|
240
251
|
routes: sandbox.json.routes,
|
|
@@ -369,6 +380,57 @@ export class Sandbox {
|
|
|
369
380
|
* @internal
|
|
370
381
|
*/
|
|
371
382
|
async _runCommand(params: RunCommandParams) {
|
|
383
|
+
const wait = params.detached ? false : true;
|
|
384
|
+
const getLogs = (command: Command) => {
|
|
385
|
+
if (params.stdout || params.stderr) {
|
|
386
|
+
(async () => {
|
|
387
|
+
try {
|
|
388
|
+
for await (const log of command.logs({ signal: params.signal })) {
|
|
389
|
+
if (log.stream === "stdout") {
|
|
390
|
+
params.stdout?.write(log.data);
|
|
391
|
+
} else if (log.stream === "stderr") {
|
|
392
|
+
params.stderr?.write(log.data);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
} catch (err) {
|
|
396
|
+
if (params.signal?.aborted) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
})();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (wait) {
|
|
406
|
+
const commandStream = await this.client.runCommand({
|
|
407
|
+
sandboxId: this.sandbox.id,
|
|
408
|
+
command: params.cmd,
|
|
409
|
+
args: params.args ?? [],
|
|
410
|
+
cwd: params.cwd,
|
|
411
|
+
env: params.env ?? {},
|
|
412
|
+
sudo: params.sudo ?? false,
|
|
413
|
+
wait: true,
|
|
414
|
+
signal: params.signal,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
const command = new Command({
|
|
418
|
+
client: this.client,
|
|
419
|
+
sandboxId: this.sandbox.id,
|
|
420
|
+
cmd: commandStream.command,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
getLogs(command);
|
|
424
|
+
|
|
425
|
+
const finished = await commandStream.finished;
|
|
426
|
+
return new CommandFinished({
|
|
427
|
+
client: this.client,
|
|
428
|
+
sandboxId: this.sandbox.id,
|
|
429
|
+
cmd: finished,
|
|
430
|
+
exitCode: finished.exitCode ?? 0,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
372
434
|
const commandResponse = await this.client.runCommand({
|
|
373
435
|
sandboxId: this.sandbox.id,
|
|
374
436
|
command: params.cmd,
|
|
@@ -385,26 +447,9 @@ export class Sandbox {
|
|
|
385
447
|
cmd: commandResponse.json.command,
|
|
386
448
|
});
|
|
387
449
|
|
|
388
|
-
|
|
389
|
-
(async () => {
|
|
390
|
-
try {
|
|
391
|
-
for await (const log of command.logs({ signal: params.signal })) {
|
|
392
|
-
if (log.stream === "stdout") {
|
|
393
|
-
params.stdout?.write(log.data);
|
|
394
|
-
} else if (log.stream === "stderr") {
|
|
395
|
-
params.stderr?.write(log.data);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
} catch (err) {
|
|
399
|
-
if (params.signal?.aborted) {
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
throw err;
|
|
403
|
-
}
|
|
404
|
-
})();
|
|
405
|
-
}
|
|
450
|
+
getLogs(command);
|
|
406
451
|
|
|
407
|
-
return
|
|
452
|
+
return command;
|
|
408
453
|
}
|
|
409
454
|
|
|
410
455
|
/**
|
|
@@ -423,17 +468,17 @@ export class Sandbox {
|
|
|
423
468
|
}
|
|
424
469
|
|
|
425
470
|
/**
|
|
426
|
-
* Read a file from the filesystem of this sandbox.
|
|
471
|
+
* Read a file from the filesystem of this sandbox as a stream.
|
|
427
472
|
*
|
|
428
473
|
* @param file - File to read, with path and optional cwd
|
|
429
474
|
* @param opts - Optional parameters.
|
|
430
475
|
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
431
|
-
* @returns A promise that resolves to a ReadableStream containing the file contents
|
|
476
|
+
* @returns A promise that resolves to a ReadableStream containing the file contents, or null if file not found
|
|
432
477
|
*/
|
|
433
478
|
async readFile(
|
|
434
479
|
file: { path: string; cwd?: string },
|
|
435
480
|
opts?: { signal?: AbortSignal },
|
|
436
|
-
) {
|
|
481
|
+
): Promise<NodeJS.ReadableStream | null> {
|
|
437
482
|
return this.client.readFile({
|
|
438
483
|
sandboxId: this.sandbox.id,
|
|
439
484
|
path: file.path,
|
|
@@ -442,6 +487,72 @@ export class Sandbox {
|
|
|
442
487
|
});
|
|
443
488
|
}
|
|
444
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Read a file from the filesystem of this sandbox as a Buffer.
|
|
492
|
+
*
|
|
493
|
+
* @param file - File to read, with path and optional cwd
|
|
494
|
+
* @param opts - Optional parameters.
|
|
495
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
496
|
+
* @returns A promise that resolves to the file contents as a Buffer, or null if file not found
|
|
497
|
+
*/
|
|
498
|
+
async readFileToBuffer(
|
|
499
|
+
file: { path: string; cwd?: string },
|
|
500
|
+
opts?: { signal?: AbortSignal },
|
|
501
|
+
): Promise<Buffer | null> {
|
|
502
|
+
const stream = await this.client.readFile({
|
|
503
|
+
sandboxId: this.sandbox.id,
|
|
504
|
+
path: file.path,
|
|
505
|
+
cwd: file.cwd,
|
|
506
|
+
signal: opts?.signal,
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
if (stream === null) {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return consumeReadable(stream);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Download a file from the sandbox to the local filesystem.
|
|
518
|
+
*
|
|
519
|
+
* @param src - Source file on the sandbox, with path and optional cwd
|
|
520
|
+
* @param dst - Destination file on the local machine, with path and optional cwd
|
|
521
|
+
* @param opts - Optional parameters.
|
|
522
|
+
* @param opts.mkdirRecursive - If true, create parent directories for the destination if they don't exist.
|
|
523
|
+
* @param opts.signal - An AbortSignal to cancel the operation.
|
|
524
|
+
* @returns The absolute path to the written file, or null if the source file was not found
|
|
525
|
+
*/
|
|
526
|
+
async downloadFile(
|
|
527
|
+
src: { path: string; cwd?: string },
|
|
528
|
+
dst: { path: string; cwd?: string },
|
|
529
|
+
opts?: { mkdirRecursive?: boolean; signal?: AbortSignal },
|
|
530
|
+
): Promise<string | null> {
|
|
531
|
+
const stream = await this.client.readFile({
|
|
532
|
+
sandboxId: this.sandbox.id,
|
|
533
|
+
path: src.path,
|
|
534
|
+
cwd: src.cwd,
|
|
535
|
+
signal: opts?.signal,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
if (stream === null) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
const dstPath = resolve(dst.cwd ?? "", dst.path);
|
|
544
|
+
if (opts?.mkdirRecursive) {
|
|
545
|
+
await mkdir(dirname(dstPath), { recursive: true });
|
|
546
|
+
}
|
|
547
|
+
await pipeline(stream, createWriteStream(dstPath), {
|
|
548
|
+
signal: opts?.signal,
|
|
549
|
+
});
|
|
550
|
+
return dstPath;
|
|
551
|
+
} finally {
|
|
552
|
+
stream.destroy()
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
445
556
|
/**
|
|
446
557
|
* Write files to the filesystem of this sandbox.
|
|
447
558
|
* Defaults to writing to /vercel/sandbox unless an absolute path is specified.
|
|
@@ -549,3 +660,18 @@ export class Sandbox {
|
|
|
549
660
|
});
|
|
550
661
|
}
|
|
551
662
|
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* A {@link Sandbox} that can automatically be disposed using a `await using` statement.
|
|
666
|
+
*
|
|
667
|
+
* @example
|
|
668
|
+
* {
|
|
669
|
+
* await using const sandbox = await Sandbox.create();
|
|
670
|
+
* }
|
|
671
|
+
* // Sandbox is automatically stopped here
|
|
672
|
+
*/
|
|
673
|
+
class DisposableSandbox extends Sandbox implements AsyncDisposable {
|
|
674
|
+
async [Symbol.asyncDispose]() {
|
|
675
|
+
await this.stop();
|
|
676
|
+
}
|
|
677
|
+
}
|