@vercel/sandbox 0.0.5 → 0.0.6
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 +8 -0
- package/README.md +1 -0
- package/dist/{client/client.d.ts → api-client/api-client.d.ts} +30 -17
- package/dist/{client/client.js → api-client/api-client.js} +49 -44
- package/dist/{client → api-client}/base-client.d.ts +1 -1
- package/dist/{client → api-client}/base-client.js +3 -3
- package/dist/api-client/index.d.ts +1 -0
- package/dist/api-client/index.js +5 -0
- package/dist/{client → api-client}/validators.d.ts +20 -1
- package/dist/{client → api-client}/validators.js +9 -2
- package/dist/command.d.ts +127 -0
- package/dist/command.js +137 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +6 -5
- package/dist/sandbox.d.ts +201 -0
- package/dist/sandbox.js +174 -0
- package/dist/utils/decode-base64-url.d.ts +7 -0
- package/dist/utils/decode-base64-url.js +12 -0
- package/dist/utils/get-credentials.d.ts +26 -0
- package/dist/utils/get-credentials.js +84 -0
- package/dist/utils/get-vercel-oidc-token.d.ts +6 -0
- package/dist/utils/get-vercel-oidc-token.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -3
- package/src/api-client/api-client.ts +225 -0
- package/src/{client → api-client}/base-client.ts +1 -1
- package/src/api-client/index.ts +1 -0
- package/src/{client → api-client}/validators.ts +9 -1
- package/src/command.test.ts +51 -0
- package/src/command.ts +176 -0
- package/src/index.ts +2 -1
- package/src/sandbox.ts +309 -0
- package/src/utils/decode-base64-url.ts +14 -0
- package/src/utils/get-credentials.ts +113 -0
- package/src/utils/get-vercel-oidc-token.ts +31 -0
- package/src/version.ts +1 -1
- package/tsconfig.json +2 -1
- package/typedoc.json +7 -1
- package/vitest.config.ts +8 -0
- package/vitest.setup.ts +4 -0
- package/dist/create-sandbox.d.ts +0 -219
- package/dist/create-sandbox.js +0 -231
- package/dist/utils/deferred-generator.d.ts +0 -5
- package/dist/utils/deferred-generator.js +0 -32
- package/dist/utils/deferred.d.ts +0 -6
- package/dist/utils/deferred.js +0 -12
- package/src/client/client.ts +0 -188
- package/src/create-sandbox.ts +0 -330
- package/src/utils/deferred-generator.ts +0 -38
- package/src/utils/deferred.ts +0 -12
- /package/dist/{client → api-client}/api-error.d.ts +0 -0
- /package/dist/{client → api-client}/api-error.js +0 -0
- /package/dist/{client → api-client}/with-retry.d.ts +0 -0
- /package/dist/{client → api-client}/with-retry.js +0 -0
- /package/src/{client → api-client}/api-error.ts +0 -0
- /package/src/{client → api-client}/with-retry.ts +0 -0
package/src/create-sandbox.ts
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
import { SandboxClient } from "./client/client";
|
|
2
|
-
import { Readable } from "stream";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* SDK for interacting with the Sandbox API. Provides methods to create and
|
|
6
|
-
* manage sandboxes configured with specific source code and network ports.
|
|
7
|
-
*
|
|
8
|
-
* Example:
|
|
9
|
-
* ```ts
|
|
10
|
-
* const sdk = new SDK({
|
|
11
|
-
* teamId: process.env.VERCEL_TEAM_ID!,
|
|
12
|
-
* token: process.env.VERCEL_TOKEN!,
|
|
13
|
-
* });
|
|
14
|
-
* ```
|
|
15
|
-
*
|
|
16
|
-
* @see {@link SDK.createSandbox} to start a new sandbox.
|
|
17
|
-
*/
|
|
18
|
-
export class SDK {
|
|
19
|
-
/**
|
|
20
|
-
* Internal API client for communicating with the sandbox backend.
|
|
21
|
-
*/
|
|
22
|
-
private client: SandboxClient;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Create a new instance of `SDK`.
|
|
26
|
-
*
|
|
27
|
-
* @param config - Configuration options for the SDK.
|
|
28
|
-
* @param config.teamId - The Vercel team ID used to scope the Sandbox.
|
|
29
|
-
* @param config.token - The API token used for authentication.
|
|
30
|
-
*/
|
|
31
|
-
constructor({ teamId, token }: { teamId: string; token: string }) {
|
|
32
|
-
this.client = new SandboxClient({ teamId, token });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Creates a new sandbox instance using the provided Git repository and exposed ports.
|
|
37
|
-
*
|
|
38
|
-
* The repository must be public. On start, the sandbox will clone the repository
|
|
39
|
-
* and expose the specified ports for access.
|
|
40
|
-
*
|
|
41
|
-
* @param params - Configuration parameters for the sandbox.
|
|
42
|
-
* @param params.source - The source of the sandbox, currently supports Git repositories only.
|
|
43
|
-
* @param params.source.type - Type of source, must be `"git"`.
|
|
44
|
-
* @param params.source.url - The URL of the public Git repository to clone.
|
|
45
|
-
* @param params.projectId - The Vercel project ID used to link the Sandbox to.
|
|
46
|
-
* @param params.ports - Array of port numbers to expose from the sandbox.
|
|
47
|
-
* @param params.timeout - (Optional) Timeout in seconds before the sandbox auto-terminates.
|
|
48
|
-
*
|
|
49
|
-
* @returns A promise that resolves to a `Sandbox` instance.
|
|
50
|
-
*/
|
|
51
|
-
async createSandbox(params: {
|
|
52
|
-
source: { type: "git"; url: string };
|
|
53
|
-
projectId: string;
|
|
54
|
-
ports?: number[];
|
|
55
|
-
timeout?: number;
|
|
56
|
-
}) {
|
|
57
|
-
const { client } = this;
|
|
58
|
-
const sandbox = await client.createSandbox({
|
|
59
|
-
source: params.source,
|
|
60
|
-
projectId: params.projectId,
|
|
61
|
-
ports: params.ports ?? [],
|
|
62
|
-
timeout: params.timeout,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return new Sandbox({
|
|
66
|
-
client,
|
|
67
|
-
sandboxId: sandbox.json.sandboxId,
|
|
68
|
-
routes: sandbox.json.routes,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** @hidden */
|
|
73
|
-
async getSandbox({
|
|
74
|
-
routes,
|
|
75
|
-
sandboxId,
|
|
76
|
-
}: {
|
|
77
|
-
routes: { subdomain: string; port: number }[];
|
|
78
|
-
sandboxId: string;
|
|
79
|
-
}) {
|
|
80
|
-
return new Sandbox({
|
|
81
|
-
client: this.client,
|
|
82
|
-
sandboxId: sandboxId,
|
|
83
|
-
routes: routes,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** @inline */
|
|
89
|
-
interface RunCommandParams {
|
|
90
|
-
/** The command to execute */
|
|
91
|
-
cmd: string;
|
|
92
|
-
/** Arguments to pass to the command */
|
|
93
|
-
args?: string[];
|
|
94
|
-
/** Working directory to execute the command in */
|
|
95
|
-
cwd?: string;
|
|
96
|
-
/** Environment variables to set for this command */
|
|
97
|
-
env?: Record<string, string>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* A Sandbox is an isolated Linux MicroVM that you can your experiments on.
|
|
102
|
-
*
|
|
103
|
-
* @see {@link SDK.createSandbox} to construct a Sandbox.
|
|
104
|
-
* @hideconstructor
|
|
105
|
-
*/
|
|
106
|
-
export class Sandbox {
|
|
107
|
-
private client: SandboxClient;
|
|
108
|
-
|
|
109
|
-
/** @hidden */
|
|
110
|
-
public routes: { subdomain: string; port: number }[];
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* The ID of this sandbox.
|
|
114
|
-
*/
|
|
115
|
-
public sandboxId: string;
|
|
116
|
-
|
|
117
|
-
constructor({
|
|
118
|
-
client,
|
|
119
|
-
routes,
|
|
120
|
-
sandboxId,
|
|
121
|
-
}: {
|
|
122
|
-
client: SandboxClient;
|
|
123
|
-
routes: { subdomain: string; port: number }[];
|
|
124
|
-
sandboxId: string;
|
|
125
|
-
}) {
|
|
126
|
-
this.client = client;
|
|
127
|
-
this.routes = routes;
|
|
128
|
-
this.sandboxId = sandboxId;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Start executing a command in this sandbox.
|
|
133
|
-
*
|
|
134
|
-
* @param command - The command to execute.
|
|
135
|
-
* @param args - Arguments to pass to the command.
|
|
136
|
-
*
|
|
137
|
-
* @returns A {@link Command} instance.
|
|
138
|
-
*/
|
|
139
|
-
async runCommand(command: string, args?: string[]): Promise<Command>;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Start executing a command in this sandbox.
|
|
143
|
-
*
|
|
144
|
-
* @param params - What should be executed.
|
|
145
|
-
*
|
|
146
|
-
* @returns A {@link Command} instance.
|
|
147
|
-
*/
|
|
148
|
-
async runCommand(params: RunCommandParams): Promise<Command>;
|
|
149
|
-
|
|
150
|
-
async runCommand(
|
|
151
|
-
commandOrParams: string | RunCommandParams,
|
|
152
|
-
args?: string[],
|
|
153
|
-
): Promise<Command> {
|
|
154
|
-
return typeof commandOrParams === "string"
|
|
155
|
-
? this._runCommand({ cmd: commandOrParams, args })
|
|
156
|
-
: this._runCommand(commandOrParams);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async _runCommand(params: RunCommandParams) {
|
|
160
|
-
const commandResponse = await this.client.runCommand({
|
|
161
|
-
sandboxId: this.sandboxId,
|
|
162
|
-
command: params.cmd,
|
|
163
|
-
args: params.args ?? [],
|
|
164
|
-
cwd: params.cwd,
|
|
165
|
-
env: params.env ?? {},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
return new Command({
|
|
169
|
-
client: this.client,
|
|
170
|
-
sandboxId: this.sandboxId,
|
|
171
|
-
cmdId: commandResponse.json.cmdId,
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Write files to the filesystem of this sandbox.
|
|
177
|
-
*/
|
|
178
|
-
async writeFiles(files: { path: string; stream: Readable | Buffer }[]) {
|
|
179
|
-
return this.client.writeFiles({
|
|
180
|
-
sandboxId: this.sandboxId,
|
|
181
|
-
files: files,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Get the public domain of a port of this sandbox.
|
|
187
|
-
*
|
|
188
|
-
* E.g. `2grza2l7imxe.vercel.run`
|
|
189
|
-
*/
|
|
190
|
-
domain(p: number): string {
|
|
191
|
-
const route = this.routes.find(({ port }) => port == p);
|
|
192
|
-
if (route) {
|
|
193
|
-
return `https://${route.subdomain}.vercel.run`;
|
|
194
|
-
} else {
|
|
195
|
-
throw new Error(`No route for port ${p}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* A command executed in a Sandbox.
|
|
202
|
-
*
|
|
203
|
-
* You can {@link wait} on commands to access their {@link exitCode}, and
|
|
204
|
-
* iterate over their output with {@link logs}.
|
|
205
|
-
*
|
|
206
|
-
* @see {@link Sandbox.runCommand} to start a command.
|
|
207
|
-
*
|
|
208
|
-
* @hideconstructor
|
|
209
|
-
*/
|
|
210
|
-
export class Command {
|
|
211
|
-
private client: SandboxClient;
|
|
212
|
-
private sandboxId: string;
|
|
213
|
-
/**
|
|
214
|
-
* ID of the command execution.
|
|
215
|
-
*/
|
|
216
|
-
public cmdId: string;
|
|
217
|
-
/**
|
|
218
|
-
* The exit code of the command, if available. This is set after
|
|
219
|
-
* {@link wait} has returned.
|
|
220
|
-
*/
|
|
221
|
-
public exitCode: number | null;
|
|
222
|
-
|
|
223
|
-
constructor({
|
|
224
|
-
client,
|
|
225
|
-
sandboxId,
|
|
226
|
-
cmdId,
|
|
227
|
-
}: {
|
|
228
|
-
client: SandboxClient;
|
|
229
|
-
sandboxId: string;
|
|
230
|
-
cmdId: string;
|
|
231
|
-
}) {
|
|
232
|
-
this.client = client;
|
|
233
|
-
this.sandboxId = sandboxId;
|
|
234
|
-
this.cmdId = cmdId;
|
|
235
|
-
this.exitCode = null;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Iterate over the output of this command.
|
|
240
|
-
*
|
|
241
|
-
* ```
|
|
242
|
-
* for await (const log of cmd.logs()) {
|
|
243
|
-
* if (log.stream === "stdout") {
|
|
244
|
-
* process.stdout.write(log.data);
|
|
245
|
-
* } else {
|
|
246
|
-
* process.stderr.write(log.data);
|
|
247
|
-
* }
|
|
248
|
-
* }
|
|
249
|
-
* ```
|
|
250
|
-
*
|
|
251
|
-
* @see {@link Command.stdout}, {@link Command.stderr}, and {@link Command.output}
|
|
252
|
-
* to access output as a string.
|
|
253
|
-
*/
|
|
254
|
-
logs() {
|
|
255
|
-
return this.client.getLogs({
|
|
256
|
-
sandboxId: this.sandboxId,
|
|
257
|
-
cmdId: this.cmdId,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Wait for a command to exit and populate it's exit code.
|
|
263
|
-
*
|
|
264
|
-
* ```
|
|
265
|
-
* await cmd.wait()
|
|
266
|
-
* if (cmd.exitCode != 0) {
|
|
267
|
-
* console.error("Something went wrong...")
|
|
268
|
-
* }
|
|
269
|
-
* ````
|
|
270
|
-
*/
|
|
271
|
-
async wait() {
|
|
272
|
-
const command = await this.client.getCommand({
|
|
273
|
-
sandboxId: this.sandboxId,
|
|
274
|
-
cmdId: this.cmdId,
|
|
275
|
-
wait: true,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
this.exitCode = command.json.exitCode;
|
|
279
|
-
return this;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Print command logs to stdout/stderr
|
|
284
|
-
*/
|
|
285
|
-
async printLogs() {
|
|
286
|
-
for await (const log of this.logs()) {
|
|
287
|
-
if (log.stream === "stdout") {
|
|
288
|
-
process.stdout.write(log.data);
|
|
289
|
-
} else {
|
|
290
|
-
process.stderr.write(log.data);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Get the output of `stdout` or `stderr` as a string.
|
|
297
|
-
*
|
|
298
|
-
* NOTE: This may error with string conversion errors if the command does
|
|
299
|
-
* not ouptut valid unicode.
|
|
300
|
-
*/
|
|
301
|
-
async output(stream: "stdout" | "stderr" | "both" = "both") {
|
|
302
|
-
let data = "";
|
|
303
|
-
for await (const log of this.logs()) {
|
|
304
|
-
if (log.stream === stream) {
|
|
305
|
-
data += log.data;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return data;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Get the output of `stdout` as a string.
|
|
313
|
-
*
|
|
314
|
-
* NOTE: This may error with string conversion errors if the command does
|
|
315
|
-
* not ouptut valid unicode.
|
|
316
|
-
*/
|
|
317
|
-
async stdout() {
|
|
318
|
-
return this.output("stdout");
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Get the output of `stderr` as a string.
|
|
323
|
-
*
|
|
324
|
-
* NOTE: This may error with string conversion errors if the command does
|
|
325
|
-
* not ouptut valid unicode.
|
|
326
|
-
*/
|
|
327
|
-
async stderr() {
|
|
328
|
-
return this.output("stderr");
|
|
329
|
-
}
|
|
330
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Deferred } from "./deferred";
|
|
2
|
-
|
|
3
|
-
export interface DeferredGenerator<T, R> {
|
|
4
|
-
generator(): AsyncGenerator<T, R, void>;
|
|
5
|
-
next: (value: IteratorResult<T | Promise<T>>) => void;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function createDeferredGenerator<T, R>(): DeferredGenerator<T, R> {
|
|
9
|
-
const deferreds = [new Deferred<IteratorResult<Promise<T> | T>>()];
|
|
10
|
-
let currentIndex = 0;
|
|
11
|
-
|
|
12
|
-
const next = (value: IteratorResult<T | Promise<T>, R>) => {
|
|
13
|
-
const currentDeferred = deferreds[currentIndex];
|
|
14
|
-
if (!value.done) {
|
|
15
|
-
deferreds.push(new Deferred<IteratorResult<Promise<T> | T>>());
|
|
16
|
-
currentIndex++;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
currentDeferred.resolve(value);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function generator(): AsyncGenerator<T, R> {
|
|
23
|
-
let currentIndex = 0;
|
|
24
|
-
return (async function* () {
|
|
25
|
-
while (true) {
|
|
26
|
-
const result = await deferreds[currentIndex].promise;
|
|
27
|
-
if (result.done) return result.value;
|
|
28
|
-
yield result.value;
|
|
29
|
-
currentIndex++;
|
|
30
|
-
}
|
|
31
|
-
})();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
generator,
|
|
36
|
-
next,
|
|
37
|
-
};
|
|
38
|
-
}
|
package/src/utils/deferred.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export class Deferred<T> {
|
|
2
|
-
promise: Promise<T>;
|
|
3
|
-
resolve!: (value: T | PromiseLike<T>) => void;
|
|
4
|
-
reject!: (reason?: any) => void;
|
|
5
|
-
|
|
6
|
-
constructor() {
|
|
7
|
-
this.promise = new Promise((res, rej) => {
|
|
8
|
-
this.resolve = res;
|
|
9
|
-
this.reject = rej;
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|