@vercel/sandbox 0.0.18 → 0.0.19
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 +11 -0
- package/dist/api-client/api-client.d.ts +52 -3
- package/dist/api-client/api-client.js +89 -14
- package/dist/api-client/validators.d.ts +147 -0
- package/dist/api-client/validators.js +22 -1
- package/dist/command.d.ts +8 -2
- package/dist/command.js +4 -1
- package/dist/sandbox.d.ts +31 -1
- package/dist/sandbox.js +16 -0
- package/dist/utils/types.d.ts +13 -0
- package/dist/utils/types.js +11 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/api-client/api-client.ts +146 -34
- package/src/api-client/validators.ts +23 -0
- package/src/command.ts +4 -1
- package/src/sandbox.ts +22 -1
- package/src/utils/types.test.js +7 -0
- package/src/utils/types.ts +23 -0
- package/src/version.ts +1 -1
- package/turbo.json +9 -0
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @vercel/sandbox
|
|
2
2
|
|
|
3
|
+
## 0.0.19
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- https://github.com/vercel/sandbox-sdk/pull/104/files introduced `Sandbox.list` ([#119](https://github.com/vercel/sandbox-sdk/pull/119))
|
|
8
|
+
|
|
9
|
+
- support interrupting the log consuming ([#123](https://github.com/vercel/sandbox-sdk/pull/123))
|
|
10
|
+
|
|
11
|
+
- using [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) with `cmd.logs({ signal })`
|
|
12
|
+
- using [`Disposable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using) with `using logs = cmd.logs()`
|
|
13
|
+
|
|
3
14
|
## 0.0.18
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -2,6 +2,7 @@ import { BaseClient, type Parsed, type RequestParams } from "./base-client";
|
|
|
2
2
|
import { SandboxResponse, CommandResponse, CommandFinishedResponse, LogLine } from "./validators";
|
|
3
3
|
import { FileWriter } from "./file-writer";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { WithPrivate } from "../utils/types";
|
|
5
6
|
export declare class APIClient extends BaseClient {
|
|
6
7
|
private teamId;
|
|
7
8
|
private tokenExpiry;
|
|
@@ -38,7 +39,7 @@ export declare class APIClient extends BaseClient {
|
|
|
38
39
|
port: number;
|
|
39
40
|
}[];
|
|
40
41
|
}>>;
|
|
41
|
-
createSandbox(params: {
|
|
42
|
+
createSandbox(params: WithPrivate<{
|
|
42
43
|
ports?: number[];
|
|
43
44
|
projectId: string;
|
|
44
45
|
source?: {
|
|
@@ -57,7 +58,7 @@ export declare class APIClient extends BaseClient {
|
|
|
57
58
|
vcpus: number;
|
|
58
59
|
};
|
|
59
60
|
runtime?: "node22" | "python3.13" | (string & {});
|
|
60
|
-
}): Promise<Parsed<{
|
|
61
|
+
}>): Promise<Parsed<{
|
|
61
62
|
sandbox: {
|
|
62
63
|
region: string;
|
|
63
64
|
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
@@ -121,6 +122,51 @@ export declare class APIClient extends BaseClient {
|
|
|
121
122
|
response: Promise<Response>;
|
|
122
123
|
writer: FileWriter;
|
|
123
124
|
};
|
|
125
|
+
listSandboxes(params: {
|
|
126
|
+
/**
|
|
127
|
+
* The ID or name of the project to which the sandboxes belong.
|
|
128
|
+
* @example "my-project"
|
|
129
|
+
*/
|
|
130
|
+
projectId: string;
|
|
131
|
+
/**
|
|
132
|
+
* Maximum number of sandboxes to list from a request.
|
|
133
|
+
* @example 10
|
|
134
|
+
*/
|
|
135
|
+
limit?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Get sandboxes created after this JavaScript timestamp.
|
|
138
|
+
* @example 1540095775941
|
|
139
|
+
*/
|
|
140
|
+
since?: number | Date;
|
|
141
|
+
/**
|
|
142
|
+
* Get sandboxes created before this JavaScript timestamp.
|
|
143
|
+
* @example 1540095775951
|
|
144
|
+
*/
|
|
145
|
+
until?: number | Date;
|
|
146
|
+
}): Promise<Parsed<{
|
|
147
|
+
sandboxes: {
|
|
148
|
+
region: string;
|
|
149
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
150
|
+
id: string;
|
|
151
|
+
memory: number;
|
|
152
|
+
vcpus: number;
|
|
153
|
+
runtime: string;
|
|
154
|
+
timeout: number;
|
|
155
|
+
requestedAt: number;
|
|
156
|
+
createdAt: number;
|
|
157
|
+
cwd: string;
|
|
158
|
+
updatedAt: number;
|
|
159
|
+
duration?: number | undefined;
|
|
160
|
+
startedAt?: number | undefined;
|
|
161
|
+
requestedStopAt?: number | undefined;
|
|
162
|
+
stoppedAt?: number | undefined;
|
|
163
|
+
}[];
|
|
164
|
+
pagination: {
|
|
165
|
+
count: number;
|
|
166
|
+
next: number | null;
|
|
167
|
+
prev: number | null;
|
|
168
|
+
};
|
|
169
|
+
}>>;
|
|
124
170
|
writeFiles(params: {
|
|
125
171
|
sandboxId: string;
|
|
126
172
|
cwd: string;
|
|
@@ -153,7 +199,10 @@ export declare class APIClient extends BaseClient {
|
|
|
153
199
|
getLogs(params: {
|
|
154
200
|
sandboxId: string;
|
|
155
201
|
cmdId: string;
|
|
156
|
-
|
|
202
|
+
signal?: AbortSignal;
|
|
203
|
+
}): AsyncGenerator<z.infer<typeof LogLine>, void, void> & Disposable & {
|
|
204
|
+
close(): void;
|
|
205
|
+
};
|
|
157
206
|
stopSandbox(params: {
|
|
158
207
|
sandboxId: string;
|
|
159
208
|
}): Promise<Parsed<z.infer<typeof SandboxResponse>>>;
|
|
@@ -15,6 +15,7 @@ const os_1 = __importDefault(require("os"));
|
|
|
15
15
|
const stream_1 = require("stream");
|
|
16
16
|
const normalizePath_1 = require("../utils/normalizePath");
|
|
17
17
|
const jwt_expiry_1 = require("../utils/jwt-expiry");
|
|
18
|
+
const types_1 = require("../utils/types");
|
|
18
19
|
class APIClient extends base_client_1.BaseClient {
|
|
19
20
|
constructor(params) {
|
|
20
21
|
super({
|
|
@@ -55,6 +56,7 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
55
56
|
return (0, base_client_1.parseOrThrow)(validators_1.SandboxAndRoutesResponse, await this.request(`/v1/sandboxes/${params.sandboxId}`));
|
|
56
57
|
}
|
|
57
58
|
async createSandbox(params) {
|
|
59
|
+
const privateParams = (0, types_1.getPrivateParams)(params);
|
|
58
60
|
return (0, base_client_1.parseOrThrow)(validators_1.SandboxAndRoutesResponse, await this.request("/v1/sandboxes", {
|
|
59
61
|
method: "POST",
|
|
60
62
|
body: JSON.stringify({
|
|
@@ -64,6 +66,7 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
64
66
|
timeout: params.timeout,
|
|
65
67
|
resources: params.resources,
|
|
66
68
|
runtime: params.runtime,
|
|
69
|
+
...privateParams,
|
|
67
70
|
}),
|
|
68
71
|
}));
|
|
69
72
|
}
|
|
@@ -106,6 +109,21 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
106
109
|
writer,
|
|
107
110
|
};
|
|
108
111
|
}
|
|
112
|
+
async listSandboxes(params) {
|
|
113
|
+
return (0, base_client_1.parseOrThrow)(validators_1.SandboxesResponse, await this.request(`/v1/sandboxes`, {
|
|
114
|
+
query: {
|
|
115
|
+
project: params.projectId,
|
|
116
|
+
limit: params.limit,
|
|
117
|
+
since: typeof params.since === "number"
|
|
118
|
+
? params.since
|
|
119
|
+
: params.since?.getTime(),
|
|
120
|
+
until: typeof params.until === "number"
|
|
121
|
+
? params.until
|
|
122
|
+
: params.until?.getTime(),
|
|
123
|
+
},
|
|
124
|
+
method: "GET",
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
109
127
|
async writeFiles(params) {
|
|
110
128
|
const { writer, response } = this.getFileWriter({
|
|
111
129
|
sandboxId: params.sandboxId,
|
|
@@ -143,22 +161,42 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
143
161
|
body: JSON.stringify({ signal: params.signal }),
|
|
144
162
|
}));
|
|
145
163
|
}
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
164
|
+
getLogs(params) {
|
|
165
|
+
const self = this;
|
|
166
|
+
const disposer = new AbortController();
|
|
167
|
+
const signal = !params.signal
|
|
168
|
+
? disposer.signal
|
|
169
|
+
: mergeSignals(params.signal, disposer.signal);
|
|
170
|
+
const generator = (async function* () {
|
|
171
|
+
const url = `/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}/logs`;
|
|
172
|
+
const response = await self.request(url, {
|
|
173
|
+
method: "GET",
|
|
174
|
+
signal,
|
|
152
175
|
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
176
|
+
if (response.headers.get("content-type") !== "application/x-ndjson") {
|
|
177
|
+
throw new api_error_1.APIError(response, {
|
|
178
|
+
message: "Expected a stream of logs",
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (response.body === null) {
|
|
182
|
+
throw new api_error_1.APIError(response, {
|
|
183
|
+
message: "No response body",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const jsonlinesStream = jsonlines_1.default.parse();
|
|
187
|
+
pipe(response.body, jsonlinesStream).catch((err) => {
|
|
188
|
+
console.error("Error piping logs:", err);
|
|
157
189
|
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
190
|
+
for await (const chunk of jsonlinesStream) {
|
|
191
|
+
yield validators_1.LogLine.parse(chunk);
|
|
192
|
+
}
|
|
193
|
+
})();
|
|
194
|
+
return Object.assign(generator, {
|
|
195
|
+
[Symbol.dispose]() {
|
|
196
|
+
disposer.abort("Disposed");
|
|
197
|
+
},
|
|
198
|
+
close: () => disposer.abort("Disposed"),
|
|
199
|
+
});
|
|
162
200
|
}
|
|
163
201
|
async stopSandbox(params) {
|
|
164
202
|
const url = `/v1/sandboxes/${params.sandboxId}/stop`;
|
|
@@ -166,3 +204,40 @@ class APIClient extends base_client_1.BaseClient {
|
|
|
166
204
|
}
|
|
167
205
|
}
|
|
168
206
|
exports.APIClient = APIClient;
|
|
207
|
+
async function pipe(readable, output) {
|
|
208
|
+
const reader = readable.getReader();
|
|
209
|
+
try {
|
|
210
|
+
while (true) {
|
|
211
|
+
const read = await reader.read();
|
|
212
|
+
if (read.value) {
|
|
213
|
+
output.write(Buffer.from(read.value));
|
|
214
|
+
}
|
|
215
|
+
if (read.done) {
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
output.emit("error", err);
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
output.end();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function mergeSignals(...signals) {
|
|
228
|
+
const controller = new AbortController();
|
|
229
|
+
const onAbort = () => {
|
|
230
|
+
controller.abort();
|
|
231
|
+
for (const signal of signals) {
|
|
232
|
+
signal.removeEventListener("abort", onAbort);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
for (const signal of signals) {
|
|
236
|
+
if (signal.aborted) {
|
|
237
|
+
controller.abort();
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
signal.addEventListener("abort", onAbort);
|
|
241
|
+
}
|
|
242
|
+
return controller.signal;
|
|
243
|
+
}
|
|
@@ -63,6 +63,31 @@ export declare const SandboxRoute: z.ZodObject<{
|
|
|
63
63
|
subdomain: string;
|
|
64
64
|
port: number;
|
|
65
65
|
}>;
|
|
66
|
+
export declare const Pagination: z.ZodObject<{
|
|
67
|
+
/**
|
|
68
|
+
* Amount of items in the current page.
|
|
69
|
+
* @example 20
|
|
70
|
+
*/
|
|
71
|
+
count: z.ZodNumber;
|
|
72
|
+
/**
|
|
73
|
+
* Timestamp that must be used to request the next page.
|
|
74
|
+
* @example 1540095775951
|
|
75
|
+
*/
|
|
76
|
+
next: z.ZodNullable<z.ZodNumber>;
|
|
77
|
+
/**
|
|
78
|
+
* Timestamp that must be used to request the previous page.
|
|
79
|
+
* @example 1540095775951
|
|
80
|
+
*/
|
|
81
|
+
prev: z.ZodNullable<z.ZodNumber>;
|
|
82
|
+
}, "strip", z.ZodTypeAny, {
|
|
83
|
+
count: number;
|
|
84
|
+
next: number | null;
|
|
85
|
+
prev: number | null;
|
|
86
|
+
}, {
|
|
87
|
+
count: number;
|
|
88
|
+
next: number | null;
|
|
89
|
+
prev: number | null;
|
|
90
|
+
}>;
|
|
66
91
|
export type CommandData = z.infer<typeof Command>;
|
|
67
92
|
export declare const Command: z.ZodObject<{
|
|
68
93
|
id: z.ZodString;
|
|
@@ -393,3 +418,125 @@ export declare const LogLine: z.ZodObject<{
|
|
|
393
418
|
stream: "stdout" | "stderr";
|
|
394
419
|
data: string;
|
|
395
420
|
}>;
|
|
421
|
+
export declare const SandboxesResponse: z.ZodObject<{
|
|
422
|
+
sandboxes: z.ZodArray<z.ZodObject<{
|
|
423
|
+
id: z.ZodString;
|
|
424
|
+
memory: z.ZodNumber;
|
|
425
|
+
vcpus: z.ZodNumber;
|
|
426
|
+
region: z.ZodString;
|
|
427
|
+
runtime: z.ZodString;
|
|
428
|
+
timeout: z.ZodNumber;
|
|
429
|
+
status: z.ZodEnum<["pending", "running", "stopping", "stopped", "failed"]>;
|
|
430
|
+
requestedAt: z.ZodNumber;
|
|
431
|
+
startedAt: z.ZodOptional<z.ZodNumber>;
|
|
432
|
+
requestedStopAt: z.ZodOptional<z.ZodNumber>;
|
|
433
|
+
stoppedAt: z.ZodOptional<z.ZodNumber>;
|
|
434
|
+
duration: z.ZodOptional<z.ZodNumber>;
|
|
435
|
+
createdAt: z.ZodNumber;
|
|
436
|
+
cwd: z.ZodString;
|
|
437
|
+
updatedAt: z.ZodNumber;
|
|
438
|
+
}, "strip", z.ZodTypeAny, {
|
|
439
|
+
region: string;
|
|
440
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
441
|
+
id: string;
|
|
442
|
+
memory: number;
|
|
443
|
+
vcpus: number;
|
|
444
|
+
runtime: string;
|
|
445
|
+
timeout: number;
|
|
446
|
+
requestedAt: number;
|
|
447
|
+
createdAt: number;
|
|
448
|
+
cwd: string;
|
|
449
|
+
updatedAt: number;
|
|
450
|
+
duration?: number | undefined;
|
|
451
|
+
startedAt?: number | undefined;
|
|
452
|
+
requestedStopAt?: number | undefined;
|
|
453
|
+
stoppedAt?: number | undefined;
|
|
454
|
+
}, {
|
|
455
|
+
region: string;
|
|
456
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
457
|
+
id: string;
|
|
458
|
+
memory: number;
|
|
459
|
+
vcpus: number;
|
|
460
|
+
runtime: string;
|
|
461
|
+
timeout: number;
|
|
462
|
+
requestedAt: number;
|
|
463
|
+
createdAt: number;
|
|
464
|
+
cwd: string;
|
|
465
|
+
updatedAt: number;
|
|
466
|
+
duration?: number | undefined;
|
|
467
|
+
startedAt?: number | undefined;
|
|
468
|
+
requestedStopAt?: number | undefined;
|
|
469
|
+
stoppedAt?: number | undefined;
|
|
470
|
+
}>, "many">;
|
|
471
|
+
pagination: z.ZodObject<{
|
|
472
|
+
/**
|
|
473
|
+
* Amount of items in the current page.
|
|
474
|
+
* @example 20
|
|
475
|
+
*/
|
|
476
|
+
count: z.ZodNumber;
|
|
477
|
+
/**
|
|
478
|
+
* Timestamp that must be used to request the next page.
|
|
479
|
+
* @example 1540095775951
|
|
480
|
+
*/
|
|
481
|
+
next: z.ZodNullable<z.ZodNumber>;
|
|
482
|
+
/**
|
|
483
|
+
* Timestamp that must be used to request the previous page.
|
|
484
|
+
* @example 1540095775951
|
|
485
|
+
*/
|
|
486
|
+
prev: z.ZodNullable<z.ZodNumber>;
|
|
487
|
+
}, "strip", z.ZodTypeAny, {
|
|
488
|
+
count: number;
|
|
489
|
+
next: number | null;
|
|
490
|
+
prev: number | null;
|
|
491
|
+
}, {
|
|
492
|
+
count: number;
|
|
493
|
+
next: number | null;
|
|
494
|
+
prev: number | null;
|
|
495
|
+
}>;
|
|
496
|
+
}, "strip", z.ZodTypeAny, {
|
|
497
|
+
sandboxes: {
|
|
498
|
+
region: string;
|
|
499
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
500
|
+
id: string;
|
|
501
|
+
memory: number;
|
|
502
|
+
vcpus: number;
|
|
503
|
+
runtime: string;
|
|
504
|
+
timeout: number;
|
|
505
|
+
requestedAt: number;
|
|
506
|
+
createdAt: number;
|
|
507
|
+
cwd: string;
|
|
508
|
+
updatedAt: number;
|
|
509
|
+
duration?: number | undefined;
|
|
510
|
+
startedAt?: number | undefined;
|
|
511
|
+
requestedStopAt?: number | undefined;
|
|
512
|
+
stoppedAt?: number | undefined;
|
|
513
|
+
}[];
|
|
514
|
+
pagination: {
|
|
515
|
+
count: number;
|
|
516
|
+
next: number | null;
|
|
517
|
+
prev: number | null;
|
|
518
|
+
};
|
|
519
|
+
}, {
|
|
520
|
+
sandboxes: {
|
|
521
|
+
region: string;
|
|
522
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
523
|
+
id: string;
|
|
524
|
+
memory: number;
|
|
525
|
+
vcpus: number;
|
|
526
|
+
runtime: string;
|
|
527
|
+
timeout: number;
|
|
528
|
+
requestedAt: number;
|
|
529
|
+
createdAt: number;
|
|
530
|
+
cwd: string;
|
|
531
|
+
updatedAt: number;
|
|
532
|
+
duration?: number | undefined;
|
|
533
|
+
startedAt?: number | undefined;
|
|
534
|
+
requestedStopAt?: number | undefined;
|
|
535
|
+
stoppedAt?: number | undefined;
|
|
536
|
+
}[];
|
|
537
|
+
pagination: {
|
|
538
|
+
count: number;
|
|
539
|
+
next: number | null;
|
|
540
|
+
prev: number | null;
|
|
541
|
+
};
|
|
542
|
+
}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LogLine = exports.EmptyResponse = exports.CommandFinishedResponse = exports.CommandResponse = exports.SandboxAndRoutesResponse = exports.SandboxResponse = exports.Command = exports.SandboxRoute = exports.Sandbox = void 0;
|
|
3
|
+
exports.SandboxesResponse = exports.LogLine = exports.EmptyResponse = exports.CommandFinishedResponse = exports.CommandResponse = exports.SandboxAndRoutesResponse = exports.SandboxResponse = exports.Command = exports.Pagination = exports.SandboxRoute = exports.Sandbox = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
exports.Sandbox = zod_1.z.object({
|
|
6
6
|
id: zod_1.z.string(),
|
|
@@ -24,6 +24,23 @@ exports.SandboxRoute = zod_1.z.object({
|
|
|
24
24
|
subdomain: zod_1.z.string(),
|
|
25
25
|
port: zod_1.z.number(),
|
|
26
26
|
});
|
|
27
|
+
exports.Pagination = zod_1.z.object({
|
|
28
|
+
/**
|
|
29
|
+
* Amount of items in the current page.
|
|
30
|
+
* @example 20
|
|
31
|
+
*/
|
|
32
|
+
count: zod_1.z.number(),
|
|
33
|
+
/**
|
|
34
|
+
* Timestamp that must be used to request the next page.
|
|
35
|
+
* @example 1540095775951
|
|
36
|
+
*/
|
|
37
|
+
next: zod_1.z.number().nullable(),
|
|
38
|
+
/**
|
|
39
|
+
* Timestamp that must be used to request the previous page.
|
|
40
|
+
* @example 1540095775951
|
|
41
|
+
*/
|
|
42
|
+
prev: zod_1.z.number().nullable(),
|
|
43
|
+
});
|
|
27
44
|
exports.Command = zod_1.z.object({
|
|
28
45
|
id: zod_1.z.string(),
|
|
29
46
|
name: zod_1.z.string(),
|
|
@@ -53,3 +70,7 @@ exports.LogLine = zod_1.z.object({
|
|
|
53
70
|
stream: zod_1.z.enum(["stdout", "stderr"]),
|
|
54
71
|
data: zod_1.z.string(),
|
|
55
72
|
});
|
|
73
|
+
exports.SandboxesResponse = zod_1.z.object({
|
|
74
|
+
sandboxes: zod_1.z.array(exports.Sandbox),
|
|
75
|
+
pagination: exports.Pagination,
|
|
76
|
+
});
|
package/dist/command.d.ts
CHANGED
|
@@ -58,15 +58,21 @@ export declare class Command {
|
|
|
58
58
|
* }
|
|
59
59
|
* ```
|
|
60
60
|
*
|
|
61
|
+
* @param opts - Optional parameters.
|
|
62
|
+
* @param opts.signal - An AbortSignal to cancel log streaming.
|
|
61
63
|
* @returns An async iterable of log entries from the command output.
|
|
62
64
|
*
|
|
63
65
|
* @see {@link Command.stdout}, {@link Command.stderr}, and {@link Command.output}
|
|
64
66
|
* to access output as a string.
|
|
65
67
|
*/
|
|
66
|
-
logs(
|
|
68
|
+
logs(opts?: {
|
|
69
|
+
signal?: AbortSignal;
|
|
70
|
+
}): AsyncGenerator<{
|
|
67
71
|
stream: "stdout" | "stderr";
|
|
68
72
|
data: string;
|
|
69
|
-
}
|
|
73
|
+
}, void, void> & Disposable & {
|
|
74
|
+
close(): void;
|
|
75
|
+
};
|
|
70
76
|
/**
|
|
71
77
|
* Wait for a command to exit and populate its exit code.
|
|
72
78
|
*
|
package/dist/command.js
CHANGED
|
@@ -53,15 +53,18 @@ class Command {
|
|
|
53
53
|
* }
|
|
54
54
|
* ```
|
|
55
55
|
*
|
|
56
|
+
* @param opts - Optional parameters.
|
|
57
|
+
* @param opts.signal - An AbortSignal to cancel log streaming.
|
|
56
58
|
* @returns An async iterable of log entries from the command output.
|
|
57
59
|
*
|
|
58
60
|
* @see {@link Command.stdout}, {@link Command.stderr}, and {@link Command.output}
|
|
59
61
|
* to access output as a string.
|
|
60
62
|
*/
|
|
61
|
-
logs() {
|
|
63
|
+
logs(opts) {
|
|
62
64
|
return this.client.getLogs({
|
|
63
65
|
sandboxId: this.sandboxId,
|
|
64
66
|
cmdId: this.cmd.id,
|
|
67
|
+
signal: opts?.signal,
|
|
65
68
|
});
|
|
66
69
|
}
|
|
67
70
|
/**
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Writable } from "stream";
|
|
|
3
3
|
import { APIClient } from "./api-client";
|
|
4
4
|
import { Command, type CommandFinished } from "./command";
|
|
5
5
|
import { type Credentials } from "./utils/get-credentials";
|
|
6
|
+
import { WithPrivate } from "./utils/types";
|
|
6
7
|
/** @inline */
|
|
7
8
|
export interface CreateSandboxParams {
|
|
8
9
|
/**
|
|
@@ -121,13 +122,42 @@ export declare class Sandbox {
|
|
|
121
122
|
* Internal metadata about this sandbox.
|
|
122
123
|
*/
|
|
123
124
|
private readonly sandbox;
|
|
125
|
+
/**
|
|
126
|
+
* Allow to get a list of sandboxes for a team narrowed to the given params.
|
|
127
|
+
* It returns both the sandboxes and the pagination metadata to allow getting
|
|
128
|
+
* the next page of results.
|
|
129
|
+
*/
|
|
130
|
+
static list(params: Parameters<APIClient["listSandboxes"]>[0] & Partial<Credentials>): Promise<import("./api-client/base-client").Parsed<{
|
|
131
|
+
sandboxes: {
|
|
132
|
+
region: string;
|
|
133
|
+
status: "pending" | "running" | "stopping" | "stopped" | "failed";
|
|
134
|
+
id: string;
|
|
135
|
+
memory: number;
|
|
136
|
+
vcpus: number;
|
|
137
|
+
runtime: string;
|
|
138
|
+
timeout: number;
|
|
139
|
+
requestedAt: number;
|
|
140
|
+
createdAt: number;
|
|
141
|
+
cwd: string;
|
|
142
|
+
updatedAt: number;
|
|
143
|
+
duration?: number | undefined;
|
|
144
|
+
startedAt?: number | undefined;
|
|
145
|
+
requestedStopAt?: number | undefined;
|
|
146
|
+
stoppedAt?: number | undefined;
|
|
147
|
+
}[];
|
|
148
|
+
pagination: {
|
|
149
|
+
count: number;
|
|
150
|
+
next: number | null;
|
|
151
|
+
prev: number | null;
|
|
152
|
+
};
|
|
153
|
+
}>>;
|
|
124
154
|
/**
|
|
125
155
|
* Create a new sandbox.
|
|
126
156
|
*
|
|
127
157
|
* @param params - Creation parameters and optional credentials.
|
|
128
158
|
* @returns A promise resolving to the created {@link Sandbox}.
|
|
129
159
|
*/
|
|
130
|
-
static create(params?: CreateSandboxParams | (CreateSandboxParams & Credentials)): Promise<Sandbox>;
|
|
160
|
+
static create(params?: WithPrivate<CreateSandboxParams | (CreateSandboxParams & Credentials)>): Promise<Sandbox>;
|
|
131
161
|
/**
|
|
132
162
|
* Retrieve an existing sandbox.
|
|
133
163
|
*
|
package/dist/sandbox.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.Sandbox = void 0;
|
|
|
4
4
|
const api_client_1 = require("./api-client");
|
|
5
5
|
const command_1 = require("./command");
|
|
6
6
|
const get_credentials_1 = require("./utils/get-credentials");
|
|
7
|
+
const types_1 = require("./utils/types");
|
|
7
8
|
/**
|
|
8
9
|
* A Sandbox is an isolated Linux MicroVM to run commands in.
|
|
9
10
|
*
|
|
@@ -23,6 +24,19 @@ class Sandbox {
|
|
|
23
24
|
get status() {
|
|
24
25
|
return this.sandbox.status;
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Allow to get a list of sandboxes for a team narrowed to the given params.
|
|
29
|
+
* It returns both the sandboxes and the pagination metadata to allow getting
|
|
30
|
+
* the next page of results.
|
|
31
|
+
*/
|
|
32
|
+
static async list(params) {
|
|
33
|
+
const credentials = await (0, get_credentials_1.getCredentials)(params);
|
|
34
|
+
const client = new api_client_1.APIClient({
|
|
35
|
+
teamId: credentials.teamId,
|
|
36
|
+
token: credentials.token,
|
|
37
|
+
});
|
|
38
|
+
return client.listSandboxes(params);
|
|
39
|
+
}
|
|
26
40
|
/**
|
|
27
41
|
* Create a new sandbox.
|
|
28
42
|
*
|
|
@@ -35,6 +49,7 @@ class Sandbox {
|
|
|
35
49
|
teamId: credentials.teamId,
|
|
36
50
|
token: credentials.token,
|
|
37
51
|
});
|
|
52
|
+
const privateParams = (0, types_1.getPrivateParams)(params);
|
|
38
53
|
const sandbox = await client.createSandbox({
|
|
39
54
|
source: params?.source,
|
|
40
55
|
projectId: credentials.projectId,
|
|
@@ -42,6 +57,7 @@ class Sandbox {
|
|
|
42
57
|
timeout: params?.timeout,
|
|
43
58
|
resources: params?.resources,
|
|
44
59
|
runtime: params?.runtime,
|
|
60
|
+
...privateParams,
|
|
45
61
|
});
|
|
46
62
|
return new Sandbox({
|
|
47
63
|
client,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility type that extends a type to accept private parameters.
|
|
3
|
+
*
|
|
4
|
+
* The private parameters can then be extracted out of the object using
|
|
5
|
+
* `getPrivateParams`.
|
|
6
|
+
*/
|
|
7
|
+
export type WithPrivate<T> = T & {
|
|
8
|
+
[K in `__${string}`]?: unknown;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Extract private parameters out of an object.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getPrivateParams: (params?: object) => { [K in keyof typeof params as K extends `__${string}` ? K : never]: (typeof params)[K]; };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPrivateParams = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Extract private parameters out of an object.
|
|
6
|
+
*/
|
|
7
|
+
const getPrivateParams = (params) => {
|
|
8
|
+
const privateEntries = Object.entries(params ?? {}).filter(([k]) => k.startsWith("__"));
|
|
9
|
+
return Object.fromEntries(privateEntries);
|
|
10
|
+
};
|
|
11
|
+
exports.getPrivateParams = getPrivateParams;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.0.
|
|
1
|
+
export declare const VERSION = "0.0.19";
|
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.19",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"test": "vitest run",
|
|
34
34
|
"typedoc": "typedoc",
|
|
35
35
|
"typecheck": "tsc --noEmit",
|
|
36
|
-
"
|
|
36
|
+
"version:bump": "ts-node scripts/inject-version.ts"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
CommandFinishedResponse,
|
|
12
12
|
EmptyResponse,
|
|
13
13
|
LogLine,
|
|
14
|
+
SandboxesResponse,
|
|
14
15
|
} from "./validators";
|
|
15
16
|
import { APIError } from "./api-error";
|
|
16
17
|
import { FileWriter } from "./file-writer";
|
|
@@ -22,6 +23,7 @@ import os from "os";
|
|
|
22
23
|
import { Readable } from "stream";
|
|
23
24
|
import { normalizePath } from "../utils/normalizePath";
|
|
24
25
|
import { JwtExpiry } from "../utils/jwt-expiry";
|
|
26
|
+
import { getPrivateParams, WithPrivate } from "../utils/types";
|
|
25
27
|
|
|
26
28
|
export class APIClient extends BaseClient {
|
|
27
29
|
private teamId: string;
|
|
@@ -76,23 +78,26 @@ export class APIClient extends BaseClient {
|
|
|
76
78
|
);
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
async createSandbox(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
async createSandbox(
|
|
82
|
+
params: WithPrivate<{
|
|
83
|
+
ports?: number[];
|
|
84
|
+
projectId: string;
|
|
85
|
+
source?:
|
|
86
|
+
| {
|
|
87
|
+
type: "git";
|
|
88
|
+
url: string;
|
|
89
|
+
depth?: number;
|
|
90
|
+
revision?: string;
|
|
91
|
+
username?: string;
|
|
92
|
+
password?: string;
|
|
93
|
+
}
|
|
94
|
+
| { type: "tarball"; url: string };
|
|
95
|
+
timeout?: number;
|
|
96
|
+
resources?: { vcpus: number };
|
|
97
|
+
runtime?: "node22" | "python3.13" | (string & {});
|
|
98
|
+
}>,
|
|
99
|
+
) {
|
|
100
|
+
const privateParams = getPrivateParams(params);
|
|
96
101
|
return parseOrThrow(
|
|
97
102
|
SandboxAndRoutesResponse,
|
|
98
103
|
await this.request("/v1/sandboxes", {
|
|
@@ -104,6 +109,7 @@ export class APIClient extends BaseClient {
|
|
|
104
109
|
timeout: params.timeout,
|
|
105
110
|
resources: params.resources,
|
|
106
111
|
runtime: params.runtime,
|
|
112
|
+
...privateParams,
|
|
107
113
|
}),
|
|
108
114
|
}),
|
|
109
115
|
);
|
|
@@ -190,6 +196,48 @@ export class APIClient extends BaseClient {
|
|
|
190
196
|
};
|
|
191
197
|
}
|
|
192
198
|
|
|
199
|
+
async listSandboxes(params: {
|
|
200
|
+
/**
|
|
201
|
+
* The ID or name of the project to which the sandboxes belong.
|
|
202
|
+
* @example "my-project"
|
|
203
|
+
*/
|
|
204
|
+
projectId: string;
|
|
205
|
+
/**
|
|
206
|
+
* Maximum number of sandboxes to list from a request.
|
|
207
|
+
* @example 10
|
|
208
|
+
*/
|
|
209
|
+
limit?: number;
|
|
210
|
+
/**
|
|
211
|
+
* Get sandboxes created after this JavaScript timestamp.
|
|
212
|
+
* @example 1540095775941
|
|
213
|
+
*/
|
|
214
|
+
since?: number | Date;
|
|
215
|
+
/**
|
|
216
|
+
* Get sandboxes created before this JavaScript timestamp.
|
|
217
|
+
* @example 1540095775951
|
|
218
|
+
*/
|
|
219
|
+
until?: number | Date;
|
|
220
|
+
}) {
|
|
221
|
+
return parseOrThrow(
|
|
222
|
+
SandboxesResponse,
|
|
223
|
+
await this.request(`/v1/sandboxes`, {
|
|
224
|
+
query: {
|
|
225
|
+
project: params.projectId,
|
|
226
|
+
limit: params.limit,
|
|
227
|
+
since:
|
|
228
|
+
typeof params.since === "number"
|
|
229
|
+
? params.since
|
|
230
|
+
: params.since?.getTime(),
|
|
231
|
+
until:
|
|
232
|
+
typeof params.until === "number"
|
|
233
|
+
? params.until
|
|
234
|
+
: params.until?.getTime(),
|
|
235
|
+
},
|
|
236
|
+
method: "GET",
|
|
237
|
+
}),
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
193
241
|
async writeFiles(params: {
|
|
194
242
|
sandboxId: string;
|
|
195
243
|
cwd: string;
|
|
@@ -257,29 +305,53 @@ export class APIClient extends BaseClient {
|
|
|
257
305
|
);
|
|
258
306
|
}
|
|
259
307
|
|
|
260
|
-
|
|
308
|
+
getLogs(params: {
|
|
261
309
|
sandboxId: string;
|
|
262
310
|
cmdId: string;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
311
|
+
signal?: AbortSignal;
|
|
312
|
+
}): AsyncGenerator<z.infer<typeof LogLine>, void, void> &
|
|
313
|
+
Disposable & { close(): void } {
|
|
314
|
+
const self = this;
|
|
315
|
+
const disposer = new AbortController();
|
|
316
|
+
|
|
317
|
+
const signal = !params.signal
|
|
318
|
+
? disposer.signal
|
|
319
|
+
: mergeSignals(params.signal, disposer.signal);
|
|
320
|
+
|
|
321
|
+
const generator = (async function* () {
|
|
322
|
+
const url = `/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}/logs`;
|
|
323
|
+
const response = await self.request(url, {
|
|
324
|
+
method: "GET",
|
|
325
|
+
signal,
|
|
269
326
|
});
|
|
270
|
-
|
|
327
|
+
if (response.headers.get("content-type") !== "application/x-ndjson") {
|
|
328
|
+
throw new APIError(response, {
|
|
329
|
+
message: "Expected a stream of logs",
|
|
330
|
+
});
|
|
331
|
+
}
|
|
271
332
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
333
|
+
if (response.body === null) {
|
|
334
|
+
throw new APIError(response, {
|
|
335
|
+
message: "No response body",
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const jsonlinesStream = jsonlines.parse();
|
|
340
|
+
pipe(response.body, jsonlinesStream).catch((err) => {
|
|
341
|
+
console.error("Error piping logs:", err);
|
|
275
342
|
});
|
|
276
|
-
}
|
|
277
343
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
344
|
+
for await (const chunk of jsonlinesStream) {
|
|
345
|
+
yield LogLine.parse(chunk);
|
|
346
|
+
}
|
|
347
|
+
})();
|
|
348
|
+
|
|
349
|
+
return Object.assign(generator, {
|
|
350
|
+
[Symbol.dispose]() {
|
|
351
|
+
disposer.abort("Disposed");
|
|
352
|
+
},
|
|
353
|
+
close: () => disposer.abort("Disposed"),
|
|
354
|
+
});
|
|
283
355
|
}
|
|
284
356
|
|
|
285
357
|
async stopSandbox(params: {
|
|
@@ -292,3 +364,43 @@ export class APIClient extends BaseClient {
|
|
|
292
364
|
);
|
|
293
365
|
}
|
|
294
366
|
}
|
|
367
|
+
|
|
368
|
+
async function pipe(
|
|
369
|
+
readable: ReadableStream<Uint8Array>,
|
|
370
|
+
output: NodeJS.WritableStream,
|
|
371
|
+
) {
|
|
372
|
+
const reader = readable.getReader();
|
|
373
|
+
try {
|
|
374
|
+
while (true) {
|
|
375
|
+
const read = await reader.read();
|
|
376
|
+
if (read.value) {
|
|
377
|
+
output.write(Buffer.from(read.value));
|
|
378
|
+
}
|
|
379
|
+
if (read.done) {
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
} catch (err) {
|
|
384
|
+
output.emit("error", err);
|
|
385
|
+
} finally {
|
|
386
|
+
output.end();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function mergeSignals(...signals: [AbortSignal, ...AbortSignal[]]) {
|
|
391
|
+
const controller = new AbortController();
|
|
392
|
+
const onAbort = () => {
|
|
393
|
+
controller.abort();
|
|
394
|
+
for (const signal of signals) {
|
|
395
|
+
signal.removeEventListener("abort", onAbort);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
for (const signal of signals) {
|
|
399
|
+
if (signal.aborted) {
|
|
400
|
+
controller.abort();
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
signal.addEventListener("abort", onAbort);
|
|
404
|
+
}
|
|
405
|
+
return controller.signal;
|
|
406
|
+
}
|
|
@@ -28,6 +28,24 @@ export const SandboxRoute = z.object({
|
|
|
28
28
|
port: z.number(),
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
export const Pagination = z.object({
|
|
32
|
+
/**
|
|
33
|
+
* Amount of items in the current page.
|
|
34
|
+
* @example 20
|
|
35
|
+
*/
|
|
36
|
+
count: z.number(),
|
|
37
|
+
/**
|
|
38
|
+
* Timestamp that must be used to request the next page.
|
|
39
|
+
* @example 1540095775951
|
|
40
|
+
*/
|
|
41
|
+
next: z.number().nullable(),
|
|
42
|
+
/**
|
|
43
|
+
* Timestamp that must be used to request the previous page.
|
|
44
|
+
* @example 1540095775951
|
|
45
|
+
*/
|
|
46
|
+
prev: z.number().nullable(),
|
|
47
|
+
});
|
|
48
|
+
|
|
31
49
|
export type CommandData = z.infer<typeof Command>;
|
|
32
50
|
|
|
33
51
|
export const Command = z.object({
|
|
@@ -66,3 +84,8 @@ export const LogLine = z.object({
|
|
|
66
84
|
stream: z.enum(["stdout", "stderr"]),
|
|
67
85
|
data: z.string(),
|
|
68
86
|
});
|
|
87
|
+
|
|
88
|
+
export const SandboxesResponse = z.object({
|
|
89
|
+
sandboxes: z.array(Sandbox),
|
|
90
|
+
pagination: Pagination,
|
|
91
|
+
});
|
package/src/command.ts
CHANGED
|
@@ -82,15 +82,18 @@ export class Command {
|
|
|
82
82
|
* }
|
|
83
83
|
* ```
|
|
84
84
|
*
|
|
85
|
+
* @param opts - Optional parameters.
|
|
86
|
+
* @param opts.signal - An AbortSignal to cancel log streaming.
|
|
85
87
|
* @returns An async iterable of log entries from the command output.
|
|
86
88
|
*
|
|
87
89
|
* @see {@link Command.stdout}, {@link Command.stderr}, and {@link Command.output}
|
|
88
90
|
* to access output as a string.
|
|
89
91
|
*/
|
|
90
|
-
logs() {
|
|
92
|
+
logs(opts?: { signal?: AbortSignal }) {
|
|
91
93
|
return this.client.getLogs({
|
|
92
94
|
sandboxId: this.sandboxId,
|
|
93
95
|
cmdId: this.cmd.id,
|
|
96
|
+
signal: opts?.signal,
|
|
94
97
|
});
|
|
95
98
|
}
|
|
96
99
|
|
package/src/sandbox.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Writable } from "stream";
|
|
|
3
3
|
import { APIClient } from "./api-client";
|
|
4
4
|
import { Command, type CommandFinished } from "./command";
|
|
5
5
|
import { type Credentials, getCredentials } from "./utils/get-credentials";
|
|
6
|
+
import { getPrivateParams, WithPrivate } from "./utils/types";
|
|
6
7
|
|
|
7
8
|
/** @inline */
|
|
8
9
|
export interface CreateSandboxParams {
|
|
@@ -133,6 +134,22 @@ export class Sandbox {
|
|
|
133
134
|
*/
|
|
134
135
|
private readonly sandbox: SandboxMetaData;
|
|
135
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Allow to get a list of sandboxes for a team narrowed to the given params.
|
|
139
|
+
* It returns both the sandboxes and the pagination metadata to allow getting
|
|
140
|
+
* the next page of results.
|
|
141
|
+
*/
|
|
142
|
+
static async list(
|
|
143
|
+
params: Parameters<APIClient["listSandboxes"]>[0] & Partial<Credentials>,
|
|
144
|
+
) {
|
|
145
|
+
const credentials = await getCredentials(params);
|
|
146
|
+
const client = new APIClient({
|
|
147
|
+
teamId: credentials.teamId,
|
|
148
|
+
token: credentials.token,
|
|
149
|
+
});
|
|
150
|
+
return client.listSandboxes(params);
|
|
151
|
+
}
|
|
152
|
+
|
|
136
153
|
/**
|
|
137
154
|
* Create a new sandbox.
|
|
138
155
|
*
|
|
@@ -140,7 +157,9 @@ export class Sandbox {
|
|
|
140
157
|
* @returns A promise resolving to the created {@link Sandbox}.
|
|
141
158
|
*/
|
|
142
159
|
static async create(
|
|
143
|
-
params?:
|
|
160
|
+
params?: WithPrivate<
|
|
161
|
+
CreateSandboxParams | (CreateSandboxParams & Credentials)
|
|
162
|
+
>,
|
|
144
163
|
): Promise<Sandbox> {
|
|
145
164
|
const credentials = await getCredentials(params);
|
|
146
165
|
const client = new APIClient({
|
|
@@ -148,6 +167,7 @@ export class Sandbox {
|
|
|
148
167
|
token: credentials.token,
|
|
149
168
|
});
|
|
150
169
|
|
|
170
|
+
const privateParams = getPrivateParams(params);
|
|
151
171
|
const sandbox = await client.createSandbox({
|
|
152
172
|
source: params?.source,
|
|
153
173
|
projectId: credentials.projectId,
|
|
@@ -155,6 +175,7 @@ export class Sandbox {
|
|
|
155
175
|
timeout: params?.timeout,
|
|
156
176
|
resources: params?.resources,
|
|
157
177
|
runtime: params?.runtime,
|
|
178
|
+
...privateParams,
|
|
158
179
|
});
|
|
159
180
|
|
|
160
181
|
return new Sandbox({
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { expect, it } from "vitest";
|
|
2
|
+
import { getPrivateParams } from "./types";
|
|
3
|
+
|
|
4
|
+
it("getPrivateParams filters unknown params", async () => {
|
|
5
|
+
const result = getPrivateParams({ foo: 123, __someParam: "abc" });
|
|
6
|
+
expect(result).toEqual({ __someParam: "abc" });
|
|
7
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility type that extends a type to accept private parameters.
|
|
3
|
+
*
|
|
4
|
+
* The private parameters can then be extracted out of the object using
|
|
5
|
+
* `getPrivateParams`.
|
|
6
|
+
*/
|
|
7
|
+
export type WithPrivate<T> = T & {
|
|
8
|
+
[K in `__${string}`]?: unknown;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extract private parameters out of an object.
|
|
13
|
+
*/
|
|
14
|
+
export const getPrivateParams = (params?: object) => {
|
|
15
|
+
const privateEntries = Object.entries(params ?? {}).filter(([k]) =>
|
|
16
|
+
k.startsWith("__"),
|
|
17
|
+
);
|
|
18
|
+
return Object.fromEntries(privateEntries) as {
|
|
19
|
+
[K in keyof typeof params as K extends `__${string}`
|
|
20
|
+
? K
|
|
21
|
+
: never]: (typeof params)[K];
|
|
22
|
+
};
|
|
23
|
+
};
|
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.19";
|