@vercel/sandbox 0.0.14 → 0.0.16
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 +14 -0
- package/dist/api-client/api-client.d.ts +9 -9
- package/dist/api-client/api-client.js +10 -23
- package/dist/api-client/api-error.d.ts +0 -1
- package/dist/api-client/base-client.d.ts +1 -2
- package/dist/api-client/base-client.js +1 -5
- package/dist/api-client/validators.d.ts +29 -29
- package/dist/api-client/with-retry.d.ts +0 -1
- package/dist/command.d.ts +1 -1
- package/dist/sandbox.d.ts +8 -4
- package/dist/sandbox.js +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -5
- package/src/api-client/api-client.ts +14 -27
- package/src/api-client/api-error.ts +0 -2
- package/src/api-client/base-client.ts +1 -2
- package/src/api-client/validators.ts +1 -1
- package/src/api-client/with-retry.ts +0 -1
- package/src/command.test.ts +9 -12
- package/src/sandbox.ts +12 -5
- package/src/version.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @vercel/sandbox
|
|
2
2
|
|
|
3
|
+
## 0.0.16
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add sandbox.status property ([#95](https://github.com/vercel/sandbox-sdk/pull/95))
|
|
8
|
+
|
|
9
|
+
## 0.0.15
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Remove warning when consuming logs more than once ([#91](https://github.com/vercel/sandbox-sdk/pull/91))
|
|
14
|
+
|
|
15
|
+
- Improve future compatibility of runtime parameter ([#88](https://github.com/vercel/sandbox-sdk/pull/88))
|
|
16
|
+
|
|
3
17
|
## 0.0.14
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -9,18 +9,18 @@ export declare class APIClient extends BaseClient {
|
|
|
9
9
|
teamId: string;
|
|
10
10
|
token: string;
|
|
11
11
|
});
|
|
12
|
-
protected request(path: string, params?: RequestParams): Promise<
|
|
12
|
+
protected request(path: string, params?: RequestParams): Promise<Response>;
|
|
13
13
|
getSandbox(params: {
|
|
14
14
|
sandboxId: string;
|
|
15
15
|
}): Promise<Parsed<{
|
|
16
16
|
sandbox: {
|
|
17
17
|
region: string;
|
|
18
|
-
timeout: number;
|
|
19
18
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
20
19
|
id: string;
|
|
21
20
|
memory: number;
|
|
22
21
|
vcpus: number;
|
|
23
22
|
runtime: string;
|
|
23
|
+
timeout: number;
|
|
24
24
|
requestedAt: number;
|
|
25
25
|
createdAt: number;
|
|
26
26
|
updatedAt: number;
|
|
@@ -30,9 +30,9 @@ export declare class APIClient extends BaseClient {
|
|
|
30
30
|
stoppedAt?: number | undefined;
|
|
31
31
|
};
|
|
32
32
|
routes: {
|
|
33
|
-
port: number;
|
|
34
33
|
url: string;
|
|
35
34
|
subdomain: string;
|
|
35
|
+
port: number;
|
|
36
36
|
}[];
|
|
37
37
|
}>>;
|
|
38
38
|
createSandbox(params: {
|
|
@@ -53,16 +53,16 @@ export declare class APIClient extends BaseClient {
|
|
|
53
53
|
resources?: {
|
|
54
54
|
vcpus: number;
|
|
55
55
|
};
|
|
56
|
-
runtime?: "node22" | "python3.13";
|
|
56
|
+
runtime?: "node22" | "python3.13" | (string & {});
|
|
57
57
|
}): Promise<Parsed<{
|
|
58
58
|
sandbox: {
|
|
59
59
|
region: string;
|
|
60
|
-
timeout: number;
|
|
61
60
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
62
61
|
id: string;
|
|
63
62
|
memory: number;
|
|
64
63
|
vcpus: number;
|
|
65
64
|
runtime: string;
|
|
65
|
+
timeout: number;
|
|
66
66
|
requestedAt: number;
|
|
67
67
|
createdAt: number;
|
|
68
68
|
updatedAt: number;
|
|
@@ -72,9 +72,9 @@ export declare class APIClient extends BaseClient {
|
|
|
72
72
|
stoppedAt?: number | undefined;
|
|
73
73
|
};
|
|
74
74
|
routes: {
|
|
75
|
-
port: number;
|
|
76
75
|
url: string;
|
|
77
76
|
subdomain: string;
|
|
77
|
+
port: number;
|
|
78
78
|
}[];
|
|
79
79
|
}>>;
|
|
80
80
|
runCommand(params: {
|
|
@@ -87,10 +87,10 @@ export declare class APIClient extends BaseClient {
|
|
|
87
87
|
}): Promise<Parsed<{
|
|
88
88
|
command: {
|
|
89
89
|
name: string;
|
|
90
|
-
cwd: string;
|
|
91
90
|
args: string[];
|
|
92
91
|
id: string;
|
|
93
92
|
startedAt: number;
|
|
93
|
+
cwd: string;
|
|
94
94
|
sandboxId: string;
|
|
95
95
|
exitCode: number | null;
|
|
96
96
|
};
|
|
@@ -113,7 +113,7 @@ export declare class APIClient extends BaseClient {
|
|
|
113
113
|
getFileWriter(params: {
|
|
114
114
|
sandboxId: string;
|
|
115
115
|
}): {
|
|
116
|
-
response: Promise<
|
|
116
|
+
response: Promise<Response>;
|
|
117
117
|
writer: FileWriter;
|
|
118
118
|
};
|
|
119
119
|
writeFiles(params: {
|
|
@@ -135,10 +135,10 @@ export declare class APIClient extends BaseClient {
|
|
|
135
135
|
}): Promise<Parsed<{
|
|
136
136
|
command: {
|
|
137
137
|
name: string;
|
|
138
|
-
cwd: string;
|
|
139
138
|
args: string[];
|
|
140
139
|
id: string;
|
|
141
140
|
startedAt: number;
|
|
141
|
+
cwd: string;
|
|
142
142
|
sandboxId: string;
|
|
143
143
|
exitCode: number | null;
|
|
144
144
|
};
|
|
@@ -8,20 +8,11 @@ const base_client_1 = require("./base-client");
|
|
|
8
8
|
const validators_1 = require("./validators");
|
|
9
9
|
const api_error_1 = require("./api-error");
|
|
10
10
|
const file_writer_1 = require("./file-writer");
|
|
11
|
-
const lru_cache_1 = require("lru-cache");
|
|
12
11
|
const version_1 = require("../version");
|
|
13
12
|
const consume_readable_1 = require("../utils/consume-readable");
|
|
14
13
|
const jsonlines_1 = __importDefault(require("jsonlines"));
|
|
15
14
|
const os_1 = __importDefault(require("os"));
|
|
16
|
-
const
|
|
17
|
-
/**
|
|
18
|
-
* Allows to track the logs hits for a command un a to maximum of items and
|
|
19
|
-
* TTL so that we don't incur in memory leaks in a log running process.
|
|
20
|
-
*/
|
|
21
|
-
const logHits = new lru_cache_1.LRUCache({
|
|
22
|
-
ttl: (0, ms_1.default)("45m"),
|
|
23
|
-
max: 1000,
|
|
24
|
-
});
|
|
15
|
+
const stream_1 = require("stream");
|
|
25
16
|
class APIClient extends base_client_1.BaseClient {
|
|
26
17
|
constructor(params) {
|
|
27
18
|
super({
|
|
@@ -112,7 +103,10 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
112
103
|
if (response.status === 404) {
|
|
113
104
|
return null;
|
|
114
105
|
}
|
|
115
|
-
|
|
106
|
+
if (response.body === null) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
return stream_1.Readable.fromWeb(response.body);
|
|
116
110
|
}
|
|
117
111
|
async killCommand(params) {
|
|
118
112
|
return (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/${params.commandId}/kill`, {
|
|
@@ -128,19 +122,12 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
128
122
|
message: "Expected a stream of logs",
|
|
129
123
|
});
|
|
130
124
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
*
|
|
136
|
-
* This is a temporary solution, we should be able to handle this in
|
|
137
|
-
* the backend in the future.
|
|
138
|
-
*/
|
|
139
|
-
if (logHits.get(url)) {
|
|
140
|
-
console.warn(`Multiple consumers for logs of command \`${params.cmdId}\`. This may lead to unexpected behavior.`);
|
|
125
|
+
if (response.body === null) {
|
|
126
|
+
throw new api_error_1.APIError(response, {
|
|
127
|
+
message: "No response body",
|
|
128
|
+
});
|
|
141
129
|
}
|
|
142
|
-
|
|
143
|
-
for await (const chunk of response.body.pipe(jsonlines_1.default.parse())) {
|
|
130
|
+
for await (const chunk of stream_1.Readable.fromWeb(response.body).pipe(jsonlines_1.default.parse())) {
|
|
144
131
|
yield validators_1.LogLine.parse(chunk);
|
|
145
132
|
}
|
|
146
133
|
}
|
|
@@ -2,7 +2,6 @@ import type { Options as RetryOptions } from "async-retry";
|
|
|
2
2
|
import { APIError } from "./api-error";
|
|
3
3
|
import { ZodType } from "zod";
|
|
4
4
|
import { type RequestOptions } from "./with-retry";
|
|
5
|
-
import nodeFetch, { type Response, type RequestInit } from "node-fetch";
|
|
6
5
|
export interface RequestParams extends RequestInit {
|
|
7
6
|
headers?: Record<string, string>;
|
|
8
7
|
method?: string;
|
|
@@ -25,7 +24,7 @@ export declare class BaseClient {
|
|
|
25
24
|
host: string;
|
|
26
25
|
token?: string;
|
|
27
26
|
});
|
|
28
|
-
protected request(path: string, opts?: RequestParams): Promise<
|
|
27
|
+
protected request(path: string, opts?: RequestParams): Promise<Response>;
|
|
29
28
|
}
|
|
30
29
|
export interface Parsed<Data> {
|
|
31
30
|
response: Response;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.BaseClient = void 0;
|
|
7
4
|
exports.parse = parse;
|
|
@@ -9,7 +6,6 @@ exports.parseOrThrow = parseOrThrow;
|
|
|
9
6
|
const api_error_1 = require("./api-error");
|
|
10
7
|
const array_1 = require("../utils/array");
|
|
11
8
|
const with_retry_1 = require("./with-retry");
|
|
12
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
13
9
|
/**
|
|
14
10
|
* A base API client that provides a convenience wrapper for fetching where
|
|
15
11
|
* we can pass query parameters as an object, support retries, debugging
|
|
@@ -17,7 +13,7 @@ const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
|
17
13
|
*/
|
|
18
14
|
class BaseClient {
|
|
19
15
|
constructor(params) {
|
|
20
|
-
this.fetch = (0, with_retry_1.withRetry)(
|
|
16
|
+
this.fetch = (0, with_retry_1.withRetry)(globalThis.fetch);
|
|
21
17
|
this.host = params.host;
|
|
22
18
|
this.debug = params.debug ?? process.env.DEBUG_FETCH === "true";
|
|
23
19
|
this.token = params.token;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export type
|
|
2
|
+
export type SandboxMetaData = z.infer<typeof Sandbox>;
|
|
3
3
|
export declare const Sandbox: z.ZodObject<{
|
|
4
4
|
id: z.ZodString;
|
|
5
5
|
memory: z.ZodNumber;
|
|
@@ -17,12 +17,12 @@ export declare const Sandbox: z.ZodObject<{
|
|
|
17
17
|
updatedAt: z.ZodNumber;
|
|
18
18
|
}, "strip", z.ZodTypeAny, {
|
|
19
19
|
region: string;
|
|
20
|
-
timeout: number;
|
|
21
20
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
22
21
|
id: string;
|
|
23
22
|
memory: number;
|
|
24
23
|
vcpus: number;
|
|
25
24
|
runtime: string;
|
|
25
|
+
timeout: number;
|
|
26
26
|
requestedAt: number;
|
|
27
27
|
createdAt: number;
|
|
28
28
|
updatedAt: number;
|
|
@@ -32,12 +32,12 @@ export declare const Sandbox: z.ZodObject<{
|
|
|
32
32
|
stoppedAt?: number | undefined;
|
|
33
33
|
}, {
|
|
34
34
|
region: string;
|
|
35
|
-
timeout: number;
|
|
36
35
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
37
36
|
id: string;
|
|
38
37
|
memory: number;
|
|
39
38
|
vcpus: number;
|
|
40
39
|
runtime: string;
|
|
40
|
+
timeout: number;
|
|
41
41
|
requestedAt: number;
|
|
42
42
|
createdAt: number;
|
|
43
43
|
updatedAt: number;
|
|
@@ -52,13 +52,13 @@ export declare const SandboxRoute: z.ZodObject<{
|
|
|
52
52
|
subdomain: z.ZodString;
|
|
53
53
|
port: z.ZodNumber;
|
|
54
54
|
}, "strip", z.ZodTypeAny, {
|
|
55
|
-
port: number;
|
|
56
55
|
url: string;
|
|
57
56
|
subdomain: string;
|
|
58
|
-
}, {
|
|
59
57
|
port: number;
|
|
58
|
+
}, {
|
|
60
59
|
url: string;
|
|
61
60
|
subdomain: string;
|
|
61
|
+
port: number;
|
|
62
62
|
}>;
|
|
63
63
|
export type CommandData = z.infer<typeof Command>;
|
|
64
64
|
export declare const Command: z.ZodObject<{
|
|
@@ -71,18 +71,18 @@ export declare const Command: z.ZodObject<{
|
|
|
71
71
|
startedAt: z.ZodNumber;
|
|
72
72
|
}, "strip", z.ZodTypeAny, {
|
|
73
73
|
name: string;
|
|
74
|
-
cwd: string;
|
|
75
74
|
args: string[];
|
|
76
75
|
id: string;
|
|
77
76
|
startedAt: number;
|
|
77
|
+
cwd: string;
|
|
78
78
|
sandboxId: string;
|
|
79
79
|
exitCode: number | null;
|
|
80
80
|
}, {
|
|
81
81
|
name: string;
|
|
82
|
-
cwd: string;
|
|
83
82
|
args: string[];
|
|
84
83
|
id: string;
|
|
85
84
|
startedAt: number;
|
|
85
|
+
cwd: string;
|
|
86
86
|
sandboxId: string;
|
|
87
87
|
exitCode: number | null;
|
|
88
88
|
}>;
|
|
@@ -104,12 +104,12 @@ export declare const SandboxResponse: z.ZodObject<{
|
|
|
104
104
|
updatedAt: z.ZodNumber;
|
|
105
105
|
}, "strip", z.ZodTypeAny, {
|
|
106
106
|
region: string;
|
|
107
|
-
timeout: number;
|
|
108
107
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
109
108
|
id: string;
|
|
110
109
|
memory: number;
|
|
111
110
|
vcpus: number;
|
|
112
111
|
runtime: string;
|
|
112
|
+
timeout: number;
|
|
113
113
|
requestedAt: number;
|
|
114
114
|
createdAt: number;
|
|
115
115
|
updatedAt: number;
|
|
@@ -119,12 +119,12 @@ export declare const SandboxResponse: z.ZodObject<{
|
|
|
119
119
|
stoppedAt?: number | undefined;
|
|
120
120
|
}, {
|
|
121
121
|
region: string;
|
|
122
|
-
timeout: number;
|
|
123
122
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
124
123
|
id: string;
|
|
125
124
|
memory: number;
|
|
126
125
|
vcpus: number;
|
|
127
126
|
runtime: string;
|
|
127
|
+
timeout: number;
|
|
128
128
|
requestedAt: number;
|
|
129
129
|
createdAt: number;
|
|
130
130
|
updatedAt: number;
|
|
@@ -136,12 +136,12 @@ export declare const SandboxResponse: z.ZodObject<{
|
|
|
136
136
|
}, "strip", z.ZodTypeAny, {
|
|
137
137
|
sandbox: {
|
|
138
138
|
region: string;
|
|
139
|
-
timeout: number;
|
|
140
139
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
141
140
|
id: string;
|
|
142
141
|
memory: number;
|
|
143
142
|
vcpus: number;
|
|
144
143
|
runtime: string;
|
|
144
|
+
timeout: number;
|
|
145
145
|
requestedAt: number;
|
|
146
146
|
createdAt: number;
|
|
147
147
|
updatedAt: number;
|
|
@@ -153,12 +153,12 @@ export declare const SandboxResponse: z.ZodObject<{
|
|
|
153
153
|
}, {
|
|
154
154
|
sandbox: {
|
|
155
155
|
region: string;
|
|
156
|
-
timeout: number;
|
|
157
156
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
158
157
|
id: string;
|
|
159
158
|
memory: number;
|
|
160
159
|
vcpus: number;
|
|
161
160
|
runtime: string;
|
|
161
|
+
timeout: number;
|
|
162
162
|
requestedAt: number;
|
|
163
163
|
createdAt: number;
|
|
164
164
|
updatedAt: number;
|
|
@@ -186,12 +186,12 @@ export declare const SandboxAndRoutesResponse: z.ZodObject<{
|
|
|
186
186
|
updatedAt: z.ZodNumber;
|
|
187
187
|
}, "strip", z.ZodTypeAny, {
|
|
188
188
|
region: string;
|
|
189
|
-
timeout: number;
|
|
190
189
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
191
190
|
id: string;
|
|
192
191
|
memory: number;
|
|
193
192
|
vcpus: number;
|
|
194
193
|
runtime: string;
|
|
194
|
+
timeout: number;
|
|
195
195
|
requestedAt: number;
|
|
196
196
|
createdAt: number;
|
|
197
197
|
updatedAt: number;
|
|
@@ -201,12 +201,12 @@ export declare const SandboxAndRoutesResponse: z.ZodObject<{
|
|
|
201
201
|
stoppedAt?: number | undefined;
|
|
202
202
|
}, {
|
|
203
203
|
region: string;
|
|
204
|
-
timeout: number;
|
|
205
204
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
206
205
|
id: string;
|
|
207
206
|
memory: number;
|
|
208
207
|
vcpus: number;
|
|
209
208
|
runtime: string;
|
|
209
|
+
timeout: number;
|
|
210
210
|
requestedAt: number;
|
|
211
211
|
createdAt: number;
|
|
212
212
|
updatedAt: number;
|
|
@@ -221,23 +221,23 @@ export declare const SandboxAndRoutesResponse: z.ZodObject<{
|
|
|
221
221
|
subdomain: z.ZodString;
|
|
222
222
|
port: z.ZodNumber;
|
|
223
223
|
}, "strip", z.ZodTypeAny, {
|
|
224
|
-
port: number;
|
|
225
224
|
url: string;
|
|
226
225
|
subdomain: string;
|
|
227
|
-
}, {
|
|
228
226
|
port: number;
|
|
227
|
+
}, {
|
|
229
228
|
url: string;
|
|
230
229
|
subdomain: string;
|
|
230
|
+
port: number;
|
|
231
231
|
}>, "many">;
|
|
232
232
|
}, "strip", z.ZodTypeAny, {
|
|
233
233
|
sandbox: {
|
|
234
234
|
region: string;
|
|
235
|
-
timeout: number;
|
|
236
235
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
237
236
|
id: string;
|
|
238
237
|
memory: number;
|
|
239
238
|
vcpus: number;
|
|
240
239
|
runtime: string;
|
|
240
|
+
timeout: number;
|
|
241
241
|
requestedAt: number;
|
|
242
242
|
createdAt: number;
|
|
243
243
|
updatedAt: number;
|
|
@@ -247,19 +247,19 @@ export declare const SandboxAndRoutesResponse: z.ZodObject<{
|
|
|
247
247
|
stoppedAt?: number | undefined;
|
|
248
248
|
};
|
|
249
249
|
routes: {
|
|
250
|
-
port: number;
|
|
251
250
|
url: string;
|
|
252
251
|
subdomain: string;
|
|
252
|
+
port: number;
|
|
253
253
|
}[];
|
|
254
254
|
}, {
|
|
255
255
|
sandbox: {
|
|
256
256
|
region: string;
|
|
257
|
-
timeout: number;
|
|
258
257
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
259
258
|
id: string;
|
|
260
259
|
memory: number;
|
|
261
260
|
vcpus: number;
|
|
262
261
|
runtime: string;
|
|
262
|
+
timeout: number;
|
|
263
263
|
requestedAt: number;
|
|
264
264
|
createdAt: number;
|
|
265
265
|
updatedAt: number;
|
|
@@ -269,9 +269,9 @@ export declare const SandboxAndRoutesResponse: z.ZodObject<{
|
|
|
269
269
|
stoppedAt?: number | undefined;
|
|
270
270
|
};
|
|
271
271
|
routes: {
|
|
272
|
-
port: number;
|
|
273
272
|
url: string;
|
|
274
273
|
subdomain: string;
|
|
274
|
+
port: number;
|
|
275
275
|
}[];
|
|
276
276
|
}>;
|
|
277
277
|
export declare const CommandResponse: z.ZodObject<{
|
|
@@ -285,38 +285,38 @@ export declare const CommandResponse: z.ZodObject<{
|
|
|
285
285
|
startedAt: z.ZodNumber;
|
|
286
286
|
}, "strip", z.ZodTypeAny, {
|
|
287
287
|
name: string;
|
|
288
|
-
cwd: string;
|
|
289
288
|
args: string[];
|
|
290
289
|
id: string;
|
|
291
290
|
startedAt: number;
|
|
291
|
+
cwd: string;
|
|
292
292
|
sandboxId: string;
|
|
293
293
|
exitCode: number | null;
|
|
294
294
|
}, {
|
|
295
295
|
name: string;
|
|
296
|
-
cwd: string;
|
|
297
296
|
args: string[];
|
|
298
297
|
id: string;
|
|
299
298
|
startedAt: number;
|
|
299
|
+
cwd: string;
|
|
300
300
|
sandboxId: string;
|
|
301
301
|
exitCode: number | null;
|
|
302
302
|
}>;
|
|
303
303
|
}, "strip", z.ZodTypeAny, {
|
|
304
304
|
command: {
|
|
305
305
|
name: string;
|
|
306
|
-
cwd: string;
|
|
307
306
|
args: string[];
|
|
308
307
|
id: string;
|
|
309
308
|
startedAt: number;
|
|
309
|
+
cwd: string;
|
|
310
310
|
sandboxId: string;
|
|
311
311
|
exitCode: number | null;
|
|
312
312
|
};
|
|
313
313
|
}, {
|
|
314
314
|
command: {
|
|
315
315
|
name: string;
|
|
316
|
-
cwd: string;
|
|
317
316
|
args: string[];
|
|
318
317
|
id: string;
|
|
319
318
|
startedAt: number;
|
|
319
|
+
cwd: string;
|
|
320
320
|
sandboxId: string;
|
|
321
321
|
exitCode: number | null;
|
|
322
322
|
};
|
|
@@ -333,38 +333,38 @@ export declare const CommandFinishedResponse: z.ZodObject<{
|
|
|
333
333
|
exitCode: z.ZodNumber;
|
|
334
334
|
}, "strip", z.ZodTypeAny, {
|
|
335
335
|
name: string;
|
|
336
|
-
cwd: string;
|
|
337
336
|
args: string[];
|
|
338
337
|
id: string;
|
|
339
338
|
startedAt: number;
|
|
339
|
+
cwd: string;
|
|
340
340
|
sandboxId: string;
|
|
341
341
|
exitCode: number;
|
|
342
342
|
}, {
|
|
343
343
|
name: string;
|
|
344
|
-
cwd: string;
|
|
345
344
|
args: string[];
|
|
346
345
|
id: string;
|
|
347
346
|
startedAt: number;
|
|
347
|
+
cwd: string;
|
|
348
348
|
sandboxId: string;
|
|
349
349
|
exitCode: number;
|
|
350
350
|
}>;
|
|
351
351
|
}, "strip", z.ZodTypeAny, {
|
|
352
352
|
command: {
|
|
353
353
|
name: string;
|
|
354
|
-
cwd: string;
|
|
355
354
|
args: string[];
|
|
356
355
|
id: string;
|
|
357
356
|
startedAt: number;
|
|
357
|
+
cwd: string;
|
|
358
358
|
sandboxId: string;
|
|
359
359
|
exitCode: number;
|
|
360
360
|
};
|
|
361
361
|
}, {
|
|
362
362
|
command: {
|
|
363
363
|
name: string;
|
|
364
|
-
cwd: string;
|
|
365
364
|
args: string[];
|
|
366
365
|
id: string;
|
|
367
366
|
startedAt: number;
|
|
367
|
+
cwd: string;
|
|
368
368
|
sandboxId: string;
|
|
369
369
|
exitCode: number;
|
|
370
370
|
};
|
|
@@ -374,9 +374,9 @@ export declare const LogLine: z.ZodObject<{
|
|
|
374
374
|
stream: z.ZodEnum<["stdout", "stderr"]>;
|
|
375
375
|
data: z.ZodString;
|
|
376
376
|
}, "strip", z.ZodTypeAny, {
|
|
377
|
-
data: string;
|
|
378
377
|
stream: "stdout" | "stderr";
|
|
379
|
-
}, {
|
|
380
378
|
data: string;
|
|
379
|
+
}, {
|
|
381
380
|
stream: "stdout" | "stderr";
|
|
381
|
+
data: string;
|
|
382
382
|
}>;
|
package/dist/command.d.ts
CHANGED
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SandboxMetaData, SandboxRouteData } from "./api-client";
|
|
2
2
|
import type { Writable } from "stream";
|
|
3
3
|
import { APIClient } from "./api-client";
|
|
4
4
|
import { Command, type CommandFinished } from "./command";
|
|
@@ -51,7 +51,7 @@ export interface CreateSandboxParams {
|
|
|
51
51
|
* The runtime of the sandbox, currently only `node22` and `python3.13` are supported.
|
|
52
52
|
* If not specified, the default runtime `node22` will be used.
|
|
53
53
|
*/
|
|
54
|
-
runtime?: "node22" | "python3.13";
|
|
54
|
+
runtime?: "node22" | "python3.13" | (string & {});
|
|
55
55
|
}
|
|
56
56
|
/** @inline */
|
|
57
57
|
interface GetSandboxParams {
|
|
@@ -113,7 +113,11 @@ export declare class Sandbox {
|
|
|
113
113
|
*/
|
|
114
114
|
get sandboxId(): string;
|
|
115
115
|
/**
|
|
116
|
-
*
|
|
116
|
+
* The status of the sandbox.
|
|
117
|
+
*/
|
|
118
|
+
get status(): SandboxMetaData["status"];
|
|
119
|
+
/**
|
|
120
|
+
* Internal metadata about this sandbox.
|
|
117
121
|
*/
|
|
118
122
|
private readonly sandbox;
|
|
119
123
|
/**
|
|
@@ -140,7 +144,7 @@ export declare class Sandbox {
|
|
|
140
144
|
constructor({ client, routes, sandbox, }: {
|
|
141
145
|
client: APIClient;
|
|
142
146
|
routes: SandboxRouteData[];
|
|
143
|
-
sandbox:
|
|
147
|
+
sandbox: SandboxMetaData;
|
|
144
148
|
});
|
|
145
149
|
/**
|
|
146
150
|
* Get a previously run command by its ID.
|
package/dist/sandbox.js
CHANGED
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.0.
|
|
1
|
+
export declare const VERSION = "0.0.16";
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/sandbox",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,11 +11,8 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@vercel/oidc": "^2.0.0",
|
|
13
13
|
"async-retry": "1.3.3",
|
|
14
|
-
"form-data": "3.0.0",
|
|
15
14
|
"jsonlines": "0.1.1",
|
|
16
|
-
"lru-cache": "11.1.0",
|
|
17
15
|
"ms": "2.1.3",
|
|
18
|
-
"node-fetch": "2.6.11",
|
|
19
16
|
"tar-stream": "3.1.7",
|
|
20
17
|
"zod": "3.24.4"
|
|
21
18
|
},
|
|
@@ -24,7 +21,6 @@
|
|
|
24
21
|
"@types/jsonlines": "0.1.5",
|
|
25
22
|
"@types/ms": "2.1.0",
|
|
26
23
|
"@types/node": "22.15.12",
|
|
27
|
-
"@types/node-fetch": "2.6.12",
|
|
28
24
|
"@types/tar-stream": "3.1.4",
|
|
29
25
|
"dotenv": "16.5.0",
|
|
30
26
|
"typedoc": "0.28.5",
|
|
@@ -14,22 +14,12 @@ import {
|
|
|
14
14
|
} from "./validators";
|
|
15
15
|
import { APIError } from "./api-error";
|
|
16
16
|
import { FileWriter } from "./file-writer";
|
|
17
|
-
import { LRUCache } from "lru-cache";
|
|
18
17
|
import { VERSION } from "../version";
|
|
19
18
|
import { consumeReadable } from "../utils/consume-readable";
|
|
20
19
|
import { z } from "zod";
|
|
21
20
|
import jsonlines from "jsonlines";
|
|
22
21
|
import os from "os";
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Allows to track the logs hits for a command un a to maximum of items and
|
|
27
|
-
* TTL so that we don't incur in memory leaks in a log running process.
|
|
28
|
-
*/
|
|
29
|
-
const logHits = new LRUCache<string, boolean>({
|
|
30
|
-
ttl: ms("45m"),
|
|
31
|
-
max: 1000,
|
|
32
|
-
});
|
|
22
|
+
import { Readable } from "stream";
|
|
33
23
|
|
|
34
24
|
export class APIClient extends BaseClient {
|
|
35
25
|
private teamId: string;
|
|
@@ -78,7 +68,7 @@ export class APIClient extends BaseClient {
|
|
|
78
68
|
| { type: "tarball"; url: string };
|
|
79
69
|
timeout?: number;
|
|
80
70
|
resources?: { vcpus: number };
|
|
81
|
-
runtime?: "node22" | "python3.13";
|
|
71
|
+
runtime?: "node22" | "python3.13" | (string & {});
|
|
82
72
|
}) {
|
|
83
73
|
return parseOrThrow(
|
|
84
74
|
SandboxAndRoutesResponse,
|
|
@@ -207,7 +197,11 @@ export class APIClient extends BaseClient {
|
|
|
207
197
|
return null;
|
|
208
198
|
}
|
|
209
199
|
|
|
210
|
-
|
|
200
|
+
if (response.body === null) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return Readable.fromWeb(response.body);
|
|
211
205
|
}
|
|
212
206
|
|
|
213
207
|
async killCommand(params: {
|
|
@@ -239,22 +233,15 @@ export class APIClient extends BaseClient {
|
|
|
239
233
|
});
|
|
240
234
|
}
|
|
241
235
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
*
|
|
247
|
-
* This is a temporary solution, we should be able to handle this in
|
|
248
|
-
* the backend in the future.
|
|
249
|
-
*/
|
|
250
|
-
if (logHits.get(url)) {
|
|
251
|
-
console.warn(
|
|
252
|
-
`Multiple consumers for logs of command \`${params.cmdId}\`. This may lead to unexpected behavior.`,
|
|
253
|
-
);
|
|
236
|
+
if (response.body === null) {
|
|
237
|
+
throw new APIError(response, {
|
|
238
|
+
message: "No response body",
|
|
239
|
+
});
|
|
254
240
|
}
|
|
255
241
|
|
|
256
|
-
|
|
257
|
-
|
|
242
|
+
for await (const chunk of Readable.fromWeb(response.body).pipe(
|
|
243
|
+
jsonlines.parse(),
|
|
244
|
+
)) {
|
|
258
245
|
yield LogLine.parse(chunk);
|
|
259
246
|
}
|
|
260
247
|
}
|
|
@@ -3,7 +3,6 @@ import { APIError } from "./api-error";
|
|
|
3
3
|
import { ZodType } from "zod";
|
|
4
4
|
import { array } from "../utils/array";
|
|
5
5
|
import { withRetry, type RequestOptions } from "./with-retry";
|
|
6
|
-
import nodeFetch, { type Response, type RequestInit } from "node-fetch";
|
|
7
6
|
|
|
8
7
|
export interface RequestParams extends RequestInit {
|
|
9
8
|
headers?: Record<string, string>;
|
|
@@ -25,7 +24,7 @@ export class BaseClient {
|
|
|
25
24
|
private host: string;
|
|
26
25
|
|
|
27
26
|
constructor(params: { debug?: boolean; host: string; token?: string }) {
|
|
28
|
-
this.fetch = withRetry(
|
|
27
|
+
this.fetch = withRetry(globalThis.fetch);
|
|
29
28
|
this.host = params.host;
|
|
30
29
|
this.debug = params.debug ?? process.env.DEBUG_FETCH === "true";
|
|
31
30
|
this.token = params.token;
|
package/src/command.test.ts
CHANGED
|
@@ -11,8 +11,7 @@ afterEach(async () => {
|
|
|
11
11
|
await sandbox.stop();
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it("
|
|
15
|
-
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
14
|
+
it("supports more than one logs consumer", async () => {
|
|
16
15
|
const stdoutSpy = vi
|
|
17
16
|
.spyOn(process.stdout, "write")
|
|
18
17
|
.mockImplementation(() => true);
|
|
@@ -23,13 +22,8 @@ it("warns when there is more than one logs consumer", async () => {
|
|
|
23
22
|
stdout: process.stdout,
|
|
24
23
|
});
|
|
25
24
|
|
|
26
|
-
expect(await cmd.stdout()).toEqual("");
|
|
25
|
+
expect(await cmd.stdout()).toEqual("Hello World!\n");
|
|
27
26
|
expect(stdoutSpy).toHaveBeenCalledWith("Hello World!\n");
|
|
28
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
29
|
-
expect.stringMatching(
|
|
30
|
-
/Multiple consumers for logs of command `[^`]+`\.\sThis may lead to unexpected behavior\./,
|
|
31
|
-
),
|
|
32
|
-
);
|
|
33
27
|
});
|
|
34
28
|
|
|
35
29
|
it("does not warn when there is only one logs consumer", async () => {
|
|
@@ -85,9 +79,12 @@ it("can execute commands with sudo", async () => {
|
|
|
85
79
|
expect(output).toContain("USER=root\n");
|
|
86
80
|
expect(output).toContain("SUDO_USER=vercel-sandbox\n");
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
const pathLine = output.split("\n").find((line) => line.startsWith("PATH="));
|
|
83
|
+
expect(pathLine).toBeDefined();
|
|
84
|
+
|
|
85
|
+
const pathSegments = pathLine!.slice(5).split(":");
|
|
86
|
+
expect(pathSegments).toContain("/vercel/bin");
|
|
87
|
+
expect(pathSegments).toContain("/vercel/runtimes/node22/bin");
|
|
91
88
|
|
|
92
89
|
const dnf = await sandbox.runCommand({
|
|
93
90
|
cmd: "dnf",
|
|
@@ -98,5 +95,5 @@ it("can execute commands with sudo", async () => {
|
|
|
98
95
|
expect(dnf.exitCode).toBe(0);
|
|
99
96
|
|
|
100
97
|
const which = await sandbox.runCommand("which", ["go"]);
|
|
101
|
-
expect(which.output()).
|
|
98
|
+
expect(await which.output()).toContain("/usr/bin/go");
|
|
102
99
|
});
|
package/src/sandbox.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SandboxMetaData, SandboxRouteData } from "./api-client";
|
|
2
2
|
import type { Writable } from "stream";
|
|
3
3
|
import { APIClient } from "./api-client";
|
|
4
4
|
import { Command, type CommandFinished } from "./command";
|
|
@@ -51,7 +51,7 @@ export interface CreateSandboxParams {
|
|
|
51
51
|
* The runtime of the sandbox, currently only `node22` and `python3.13` are supported.
|
|
52
52
|
* If not specified, the default runtime `node22` will be used.
|
|
53
53
|
*/
|
|
54
|
-
runtime?: "node22" | "python3.13";
|
|
54
|
+
runtime?: "node22" | "python3.13" | (string & {});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/** @inline */
|
|
@@ -121,9 +121,16 @@ export class Sandbox {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
|
-
*
|
|
124
|
+
* The status of the sandbox.
|
|
125
125
|
*/
|
|
126
|
-
|
|
126
|
+
public get status(): SandboxMetaData["status"] {
|
|
127
|
+
return this.sandbox.status;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Internal metadata about this sandbox.
|
|
132
|
+
*/
|
|
133
|
+
private readonly sandbox: SandboxMetaData;
|
|
127
134
|
|
|
128
135
|
/**
|
|
129
136
|
* Create a new sandbox.
|
|
@@ -196,7 +203,7 @@ export class Sandbox {
|
|
|
196
203
|
}: {
|
|
197
204
|
client: APIClient;
|
|
198
205
|
routes: SandboxRouteData[];
|
|
199
|
-
sandbox:
|
|
206
|
+
sandbox: SandboxMetaData;
|
|
200
207
|
}) {
|
|
201
208
|
this.client = client;
|
|
202
209
|
this.routes = routes;
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Autogenerated by inject-version.ts
|
|
2
|
-
export const VERSION = "0.0.
|
|
2
|
+
export const VERSION = "0.0.16";
|