@vercel/sandbox 0.0.7 → 0.0.9
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-typecheck.log +1 -1
- package/CHANGELOG.md +15 -0
- package/dist/api-client/api-client.d.ts +81 -8
- package/dist/api-client/api-client.js +34 -14
- package/dist/api-client/file-writer.d.ts +52 -0
- package/dist/api-client/file-writer.js +62 -0
- package/dist/api-client/index.d.ts +1 -0
- package/dist/api-client/index.js +15 -0
- package/dist/api-client/validators.d.ts +343 -50
- package/dist/api-client/validators.js +37 -16
- package/dist/command.d.ts +18 -5
- package/dist/command.js +27 -6
- package/dist/sandbox.d.ts +25 -15
- package/dist/sandbox.js +28 -14
- package/dist/utils/resolveSignal.d.ts +13 -0
- package/dist/utils/resolveSignal.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -1
- package/src/api-client/api-client.ts +63 -29
- package/src/api-client/file-writer.ts +90 -0
- package/src/api-client/index.ts +1 -0
- package/src/api-client/validators.ts +45 -15
- package/src/command.test.ts +39 -16
- package/src/command.ts +33 -10
- package/src/sandbox.ts +53 -23
- package/src/utils/resolveSignal.ts +24 -0
- package/src/version.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @vercel/sandbox
|
|
2
2
|
|
|
3
|
+
## 0.0.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add `cmd.kill()` to stop/signal commands ([#48](https://github.com/vercel/sandbox-sdk/pull/48))
|
|
8
|
+
- Update SDK to use the new API ([#51](https://github.com/vercel/sandbox-sdk/pull/51))
|
|
9
|
+
|
|
10
|
+
## 0.0.8
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Write files using a single compressed stream ([#44](https://github.com/vercel/sandbox-sdk/pull/44))
|
|
15
|
+
- Expose `runtime` parameter ([#46](https://github.com/vercel/sandbox-sdk/pull/46))
|
|
16
|
+
- Add git depth and revision options to sandbox source ([#47](https://github.com/vercel/sandbox-sdk/pull/47))
|
|
17
|
+
|
|
3
18
|
## 0.0.7
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseClient, type Parsed, type RequestParams } from "./base-client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { SandboxResponse, CommandResponse, CommandFinishedResponse, LogLine } from "./validators";
|
|
3
|
+
import { FileWriter } from "./file-writer";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
export declare class APIClient extends BaseClient {
|
|
6
6
|
private teamId;
|
|
@@ -10,12 +10,39 @@ export declare class APIClient extends BaseClient {
|
|
|
10
10
|
token: string;
|
|
11
11
|
});
|
|
12
12
|
protected request(path: string, params?: RequestParams): Promise<import("node-fetch").Response>;
|
|
13
|
+
getSandbox(params: {
|
|
14
|
+
sandboxId: string;
|
|
15
|
+
}): Promise<Parsed<{
|
|
16
|
+
sandbox: {
|
|
17
|
+
region: string;
|
|
18
|
+
timeout: number;
|
|
19
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
20
|
+
id: string;
|
|
21
|
+
memory: number;
|
|
22
|
+
vcpus: number;
|
|
23
|
+
runtime: string;
|
|
24
|
+
requestedAt: number;
|
|
25
|
+
createdAt: number;
|
|
26
|
+
updatedAt: number;
|
|
27
|
+
duration?: number | undefined;
|
|
28
|
+
startedAt?: number | undefined;
|
|
29
|
+
requestedStopAt?: number | undefined;
|
|
30
|
+
stoppedAt?: number | undefined;
|
|
31
|
+
};
|
|
32
|
+
routes: {
|
|
33
|
+
port: number;
|
|
34
|
+
url: string;
|
|
35
|
+
subdomain: string;
|
|
36
|
+
}[];
|
|
37
|
+
}>>;
|
|
13
38
|
createSandbox(params: {
|
|
14
39
|
ports?: number[];
|
|
15
40
|
projectId: string;
|
|
16
41
|
source?: {
|
|
17
42
|
type: "git";
|
|
18
43
|
url: string;
|
|
44
|
+
depth?: number;
|
|
45
|
+
revision?: string;
|
|
19
46
|
} | {
|
|
20
47
|
type: "tarball";
|
|
21
48
|
url: string;
|
|
@@ -24,10 +51,27 @@ export declare class APIClient extends BaseClient {
|
|
|
24
51
|
resources?: {
|
|
25
52
|
vcpus: number;
|
|
26
53
|
};
|
|
54
|
+
runtime?: "node22" | "python3.13";
|
|
27
55
|
}): Promise<Parsed<{
|
|
28
|
-
|
|
56
|
+
sandbox: {
|
|
57
|
+
region: string;
|
|
58
|
+
timeout: number;
|
|
59
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
60
|
+
id: string;
|
|
61
|
+
memory: number;
|
|
62
|
+
vcpus: number;
|
|
63
|
+
runtime: string;
|
|
64
|
+
requestedAt: number;
|
|
65
|
+
createdAt: number;
|
|
66
|
+
updatedAt: number;
|
|
67
|
+
duration?: number | undefined;
|
|
68
|
+
startedAt?: number | undefined;
|
|
69
|
+
requestedStopAt?: number | undefined;
|
|
70
|
+
stoppedAt?: number | undefined;
|
|
71
|
+
};
|
|
29
72
|
routes: {
|
|
30
73
|
port: number;
|
|
74
|
+
url: string;
|
|
31
75
|
subdomain: string;
|
|
32
76
|
}[];
|
|
33
77
|
}>>;
|
|
@@ -38,28 +82,42 @@ export declare class APIClient extends BaseClient {
|
|
|
38
82
|
args: string[];
|
|
39
83
|
env: Record<string, string>;
|
|
40
84
|
}): Promise<Parsed<{
|
|
41
|
-
|
|
85
|
+
command: {
|
|
86
|
+
name: string;
|
|
87
|
+
cwd: string;
|
|
88
|
+
args: string[];
|
|
89
|
+
id: string;
|
|
90
|
+
startedAt: number;
|
|
91
|
+
sandboxId: string;
|
|
92
|
+
exitCode: number | null;
|
|
93
|
+
};
|
|
42
94
|
}>>;
|
|
43
95
|
getCommand(params: {
|
|
44
96
|
sandboxId: string;
|
|
45
97
|
cmdId: string;
|
|
46
98
|
wait: true;
|
|
47
|
-
}): Promise<Parsed<z.infer<typeof
|
|
99
|
+
}): Promise<Parsed<z.infer<typeof CommandFinishedResponse>>>;
|
|
48
100
|
getCommand(params: {
|
|
49
101
|
sandboxId: string;
|
|
50
102
|
cmdId: string;
|
|
51
103
|
wait?: boolean;
|
|
52
|
-
}): Promise<Parsed<z.infer<typeof
|
|
104
|
+
}): Promise<Parsed<z.infer<typeof CommandResponse>>>;
|
|
53
105
|
mkDir(params: {
|
|
54
106
|
sandboxId: string;
|
|
55
107
|
path: string;
|
|
56
108
|
cwd?: string;
|
|
57
109
|
}): Promise<Parsed<{}>>;
|
|
110
|
+
getFileWriter(params: {
|
|
111
|
+
sandboxId: string;
|
|
112
|
+
}): {
|
|
113
|
+
response: Promise<import("node-fetch").Response>;
|
|
114
|
+
writer: FileWriter;
|
|
115
|
+
};
|
|
58
116
|
writeFiles(params: {
|
|
59
117
|
sandboxId: string;
|
|
60
118
|
files: {
|
|
61
119
|
path: string;
|
|
62
|
-
stream:
|
|
120
|
+
stream: Buffer;
|
|
63
121
|
}[];
|
|
64
122
|
}): Promise<void>;
|
|
65
123
|
readFile(params: {
|
|
@@ -67,11 +125,26 @@ export declare class APIClient extends BaseClient {
|
|
|
67
125
|
path: string;
|
|
68
126
|
cwd?: string;
|
|
69
127
|
}): Promise<NodeJS.ReadableStream | null>;
|
|
128
|
+
killCommand(params: {
|
|
129
|
+
sandboxId: string;
|
|
130
|
+
commandId: string;
|
|
131
|
+
signal: number;
|
|
132
|
+
}): Promise<Parsed<{
|
|
133
|
+
command: {
|
|
134
|
+
name: string;
|
|
135
|
+
cwd: string;
|
|
136
|
+
args: string[];
|
|
137
|
+
id: string;
|
|
138
|
+
startedAt: number;
|
|
139
|
+
sandboxId: string;
|
|
140
|
+
exitCode: number | null;
|
|
141
|
+
};
|
|
142
|
+
}>>;
|
|
70
143
|
getLogs(params: {
|
|
71
144
|
sandboxId: string;
|
|
72
145
|
cmdId: string;
|
|
73
146
|
}): AsyncIterable<z.infer<typeof LogLine>>;
|
|
74
147
|
stopSandbox(params: {
|
|
75
148
|
sandboxId: string;
|
|
76
|
-
}): Promise<Parsed<z.infer<typeof
|
|
149
|
+
}): Promise<Parsed<z.infer<typeof SandboxResponse>>>;
|
|
77
150
|
}
|
|
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.APIClient = void 0;
|
|
7
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
8
7
|
const base_client_1 = require("./base-client");
|
|
9
8
|
const validators_1 = require("./validators");
|
|
10
9
|
const api_error_1 = require("./api-error");
|
|
10
|
+
const file_writer_1 = require("./file-writer");
|
|
11
11
|
const lru_cache_1 = require("lru-cache");
|
|
12
12
|
const version_1 = require("../version");
|
|
13
13
|
const jsonlines_1 = __importDefault(require("jsonlines"));
|
|
@@ -41,8 +41,11 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
+
async getSandbox(params) {
|
|
45
|
+
return (0, base_client_1.parseOrThrow)(validators_1.SandboxAndRoutesResponse, await this.request(`/v1/sandboxes/${params.sandboxId}`));
|
|
46
|
+
}
|
|
44
47
|
async createSandbox(params) {
|
|
45
|
-
return (0, base_client_1.parseOrThrow)(validators_1.
|
|
48
|
+
return (0, base_client_1.parseOrThrow)(validators_1.SandboxAndRoutesResponse, await this.request("/v1/sandboxes", {
|
|
46
49
|
method: "POST",
|
|
47
50
|
body: JSON.stringify({
|
|
48
51
|
projectId: params.projectId,
|
|
@@ -50,11 +53,12 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
50
53
|
source: params.source,
|
|
51
54
|
timeout: params.timeout,
|
|
52
55
|
resources: params.resources,
|
|
56
|
+
runtime: params.runtime,
|
|
53
57
|
}),
|
|
54
58
|
}));
|
|
55
59
|
}
|
|
56
60
|
async runCommand(params) {
|
|
57
|
-
return (0, base_client_1.parseOrThrow)(validators_1.
|
|
61
|
+
return (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/cmd`, {
|
|
58
62
|
method: "POST",
|
|
59
63
|
body: JSON.stringify({
|
|
60
64
|
command: params.command,
|
|
@@ -66,25 +70,35 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
66
70
|
}
|
|
67
71
|
async getCommand(params) {
|
|
68
72
|
return params.wait
|
|
69
|
-
? (0, base_client_1.parseOrThrow)(validators_1.
|
|
70
|
-
: (0, base_client_1.parseOrThrow)(validators_1.
|
|
73
|
+
? (0, base_client_1.parseOrThrow)(validators_1.CommandFinishedResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`, { query: { wait: "true" } }))
|
|
74
|
+
: (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`));
|
|
71
75
|
}
|
|
72
76
|
async mkDir(params) {
|
|
73
|
-
return (0, base_client_1.parseOrThrow)(validators_1.
|
|
77
|
+
return (0, base_client_1.parseOrThrow)(validators_1.EmptyResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/fs/mkdir`, {
|
|
74
78
|
method: "POST",
|
|
75
79
|
body: JSON.stringify({ path: params.path, cwd: params.cwd }),
|
|
76
80
|
}));
|
|
77
81
|
}
|
|
82
|
+
getFileWriter(params) {
|
|
83
|
+
const writer = new file_writer_1.FileWriter();
|
|
84
|
+
return {
|
|
85
|
+
response: this.request(`/v1/sandboxes/${params.sandboxId}/fs/write`, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: { "content-type": "application/gzip" },
|
|
88
|
+
body: writer.readable,
|
|
89
|
+
}),
|
|
90
|
+
writer,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
78
93
|
async writeFiles(params) {
|
|
79
|
-
const
|
|
94
|
+
const { writer, response } = this.getFileWriter({
|
|
95
|
+
sandboxId: params.sandboxId,
|
|
96
|
+
});
|
|
80
97
|
for (const file of params.files) {
|
|
81
|
-
|
|
98
|
+
await writer.addFile({ name: file.path, content: file.stream });
|
|
82
99
|
}
|
|
83
|
-
await (
|
|
84
|
-
|
|
85
|
-
headers: { ...formData.getHeaders() },
|
|
86
|
-
body: formData,
|
|
87
|
-
}));
|
|
100
|
+
await writer.end();
|
|
101
|
+
await (0, base_client_1.parseOrThrow)(validators_1.EmptyResponse, await response);
|
|
88
102
|
}
|
|
89
103
|
async readFile(params) {
|
|
90
104
|
const response = await this.request(`/v1/sandboxes/${params.sandboxId}/fs/read`, {
|
|
@@ -96,6 +110,12 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
96
110
|
}
|
|
97
111
|
return response.body;
|
|
98
112
|
}
|
|
113
|
+
async killCommand(params) {
|
|
114
|
+
return (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/${params.commandId}/kill`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
body: JSON.stringify({ signal: params.signal }),
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
99
119
|
async *getLogs(params) {
|
|
100
120
|
const url = `/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}/logs`;
|
|
101
121
|
const response = await this.request(url, { method: "GET" });
|
|
@@ -122,7 +142,7 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
122
142
|
}
|
|
123
143
|
async stopSandbox(params) {
|
|
124
144
|
const url = `/v1/sandboxes/${params.sandboxId}/stop`;
|
|
125
|
-
return (0, base_client_1.parseOrThrow)(validators_1.
|
|
145
|
+
return (0, base_client_1.parseOrThrow)(validators_1.SandboxResponse, await this.request(url, { method: "POST" }));
|
|
126
146
|
}
|
|
127
147
|
}
|
|
128
148
|
exports.APIClient = APIClient;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
interface FileBuffer {
|
|
3
|
+
/**
|
|
4
|
+
* The name (path) of the file to write.
|
|
5
|
+
*/
|
|
6
|
+
name: string;
|
|
7
|
+
/**
|
|
8
|
+
* The content of the file as a Buffer.
|
|
9
|
+
*/
|
|
10
|
+
content: Buffer;
|
|
11
|
+
}
|
|
12
|
+
interface FileStream {
|
|
13
|
+
/**
|
|
14
|
+
* The name (path) of the file to write.
|
|
15
|
+
*/
|
|
16
|
+
name: string;
|
|
17
|
+
/**
|
|
18
|
+
* A Readable stream to consume the content of the file.
|
|
19
|
+
*/
|
|
20
|
+
content: Readable;
|
|
21
|
+
/**
|
|
22
|
+
* The expected size of the file. This is required to write
|
|
23
|
+
* the header of the compressed file.
|
|
24
|
+
*/
|
|
25
|
+
size: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Allows to create a Readable stream with methods to write files
|
|
29
|
+
* to it and to finish it. Files written are compressed together
|
|
30
|
+
* and gzipped in the stream.
|
|
31
|
+
*/
|
|
32
|
+
export declare class FileWriter {
|
|
33
|
+
readable: Readable;
|
|
34
|
+
private pack;
|
|
35
|
+
constructor();
|
|
36
|
+
/**
|
|
37
|
+
* Allows to add a file to the stream. Size is required to write
|
|
38
|
+
* the tarball header so when content is a stream it must be
|
|
39
|
+
* provided.
|
|
40
|
+
*
|
|
41
|
+
* Returns a Promise resolved once the file is written in the
|
|
42
|
+
* stream.
|
|
43
|
+
*/
|
|
44
|
+
addFile(file: FileBuffer | FileStream): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Allows to finish the stream returning a Promise that will
|
|
47
|
+
* resolve once the readable is effectively closed or
|
|
48
|
+
* errored.
|
|
49
|
+
*/
|
|
50
|
+
end(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FileWriter = void 0;
|
|
7
|
+
const zlib_1 = __importDefault(require("zlib"));
|
|
8
|
+
const tar_stream_1 = __importDefault(require("tar-stream"));
|
|
9
|
+
const stream_1 = require("stream");
|
|
10
|
+
/**
|
|
11
|
+
* Allows to create a Readable stream with methods to write files
|
|
12
|
+
* to it and to finish it. Files written are compressed together
|
|
13
|
+
* and gzipped in the stream.
|
|
14
|
+
*/
|
|
15
|
+
class FileWriter {
|
|
16
|
+
constructor() {
|
|
17
|
+
const gzip = zlib_1.default.createGzip();
|
|
18
|
+
this.pack = tar_stream_1.default.pack();
|
|
19
|
+
this.readable = this.pack.pipe(gzip);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Allows to add a file to the stream. Size is required to write
|
|
23
|
+
* the tarball header so when content is a stream it must be
|
|
24
|
+
* provided.
|
|
25
|
+
*
|
|
26
|
+
* Returns a Promise resolved once the file is written in the
|
|
27
|
+
* stream.
|
|
28
|
+
*/
|
|
29
|
+
async addFile(file) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const entry = this.pack.entry("size" in file
|
|
32
|
+
? { name: file.name, size: file.size }
|
|
33
|
+
: { name: file.name, size: file.content.length }, (error) => {
|
|
34
|
+
if (error) {
|
|
35
|
+
return reject(error);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
resolve();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if (file.content instanceof stream_1.Readable) {
|
|
42
|
+
file.content.pipe(entry);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
entry.end(file.content);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Allows to finish the stream returning a Promise that will
|
|
51
|
+
* resolve once the readable is effectively closed or
|
|
52
|
+
* errored.
|
|
53
|
+
*/
|
|
54
|
+
async end() {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
this.readable.on("error", reject);
|
|
57
|
+
this.readable.on("end", resolve);
|
|
58
|
+
this.pack.finalize();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.FileWriter = FileWriter;
|
package/dist/api-client/index.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
exports.APIClient = void 0;
|
|
4
18
|
var api_client_1 = require("./api-client");
|
|
5
19
|
Object.defineProperty(exports, "APIClient", { enumerable: true, get: function () { return api_client_1.APIClient; } });
|
|
20
|
+
__exportStar(require("./validators"), exports);
|