@vercel/sandbox 0.0.4 → 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.
Files changed (59) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +16 -0
  4. package/README.md +3 -1
  5. package/dist/{client/client.d.ts → api-client/api-client.d.ts} +31 -17
  6. package/dist/{client/client.js → api-client/api-client.js} +50 -44
  7. package/dist/{client → api-client}/base-client.d.ts +1 -1
  8. package/dist/{client → api-client}/base-client.js +3 -3
  9. package/dist/api-client/index.d.ts +1 -0
  10. package/dist/api-client/index.js +5 -0
  11. package/dist/{client → api-client}/validators.d.ts +20 -1
  12. package/dist/{client → api-client}/validators.js +9 -2
  13. package/dist/command.d.ts +127 -0
  14. package/dist/command.js +137 -0
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.js +6 -7
  17. package/dist/sandbox.d.ts +201 -0
  18. package/dist/sandbox.js +174 -0
  19. package/dist/utils/decode-base64-url.d.ts +7 -0
  20. package/dist/utils/decode-base64-url.js +12 -0
  21. package/dist/utils/get-credentials.d.ts +26 -0
  22. package/dist/utils/get-credentials.js +84 -0
  23. package/dist/utils/get-vercel-oidc-token.d.ts +6 -0
  24. package/dist/utils/get-vercel-oidc-token.js +21 -0
  25. package/dist/version.d.ts +1 -1
  26. package/dist/version.js +1 -1
  27. package/package.json +10 -3
  28. package/src/api-client/api-client.ts +225 -0
  29. package/src/{client → api-client}/base-client.ts +1 -1
  30. package/src/api-client/index.ts +1 -0
  31. package/src/{client → api-client}/validators.ts +9 -1
  32. package/src/command.test.ts +51 -0
  33. package/src/command.ts +176 -0
  34. package/src/index.ts +2 -2
  35. package/src/sandbox.ts +309 -0
  36. package/src/utils/decode-base64-url.ts +14 -0
  37. package/src/utils/get-credentials.ts +113 -0
  38. package/src/utils/get-vercel-oidc-token.ts +31 -0
  39. package/src/version.ts +1 -1
  40. package/tsconfig.json +2 -1
  41. package/typedoc.json +7 -1
  42. package/vitest.config.ts +8 -0
  43. package/vitest.setup.ts +4 -0
  44. package/dist/create-sandbox.d.ts +0 -196
  45. package/dist/create-sandbox.js +0 -230
  46. package/dist/utils/deferred-generator.d.ts +0 -5
  47. package/dist/utils/deferred-generator.js +0 -32
  48. package/dist/utils/deferred.d.ts +0 -6
  49. package/dist/utils/deferred.js +0 -12
  50. package/src/client/client.ts +0 -186
  51. package/src/create-sandbox.ts +0 -294
  52. package/src/utils/deferred-generator.ts +0 -38
  53. package/src/utils/deferred.ts +0 -12
  54. /package/dist/{client → api-client}/api-error.d.ts +0 -0
  55. /package/dist/{client → api-client}/api-error.js +0 -0
  56. /package/dist/{client → api-client}/with-retry.d.ts +0 -0
  57. /package/dist/{client → api-client}/with-retry.js +0 -0
  58. /package/src/{client → api-client}/api-error.ts +0 -0
  59. /package/src/{client → api-client}/with-retry.ts +0 -0
package/src/sandbox.ts ADDED
@@ -0,0 +1,309 @@
1
+ import { Readable, type Writable } from "stream";
2
+ import { APIClient } from "./api-client";
3
+ import { Command, CommandFinished } from "./command";
4
+ import { getCredentials, type Credentials } from "./utils/get-credentials";
5
+
6
+ /** @inline */
7
+ export interface CreateSandboxParams {
8
+ /**
9
+ * The source of the sandbox.
10
+ *
11
+ * Omit this parameter start a sandbox without a source.
12
+ */
13
+ source?: { type: "git"; url: string } | { type: "tarball"; url: string };
14
+ /**
15
+ * Array of port numbers to expose from the sandbox.
16
+ */
17
+ ports?: number[];
18
+ /**
19
+ * Timeout in milliseconds before the sandbox auto-terminates.
20
+ */
21
+ timeout?: number;
22
+ /**
23
+ * Resources to allocate to the sandbox.
24
+ *
25
+ * Your sandbox will get the amount of cores you specify here. For memory,
26
+ * you will get double the amount of cores.
27
+ */
28
+ resources?: { cores: number };
29
+ }
30
+
31
+ /** @inline */
32
+ interface GetSandboxParams {
33
+ /**
34
+ * Port-to-subdomain route mappings.
35
+ */
36
+ routes: Array<{ subdomain: string; port: number }>;
37
+ /**
38
+ * Unique identifier of the sandbox.
39
+ */
40
+ sandboxId: string;
41
+ }
42
+
43
+ /** @inline */
44
+ interface RunCommandParams {
45
+ /**
46
+ * The command to execute
47
+ */
48
+ cmd: string;
49
+ /**
50
+ * Arguments to pass to the command
51
+ */
52
+ args?: string[];
53
+ /**
54
+ * Working directory to execute the command in
55
+ */
56
+ cwd?: string;
57
+ /**
58
+ * Environment variables to set for this command
59
+ */
60
+ env?: Record<string, string>;
61
+ /**
62
+ * If true, the command will return without waiting for `exitCode`
63
+ */
64
+ detached?: boolean;
65
+ /**
66
+ * A `Writable` stream where `stdout` from the command will be piped
67
+ */
68
+ stdout?: Writable;
69
+ /**
70
+ * A `Writable` stream where `stderr` from the command will be piped
71
+ */
72
+ stderr?: Writable;
73
+ }
74
+
75
+ /**
76
+ * A Sandbox is an isolated Linux MicroVM to run commands in.
77
+ *
78
+ * Use {@link Sandbox.create} or {@link Sandbox.get} to construct.
79
+ * @hideconstructor
80
+ */
81
+ export class Sandbox {
82
+ private readonly client: APIClient;
83
+
84
+ /**
85
+ * Routes from ports to subdomains.
86
+ /* @hidden
87
+ */
88
+ public readonly routes: { subdomain: string; port: number }[];
89
+
90
+ /**
91
+ * Unique ID of this sandbox.
92
+ */
93
+ public readonly sandboxId: string;
94
+
95
+ /**
96
+ * Create a new sandbox.
97
+ *
98
+ * @param params - Creation parameters and optional credentials.
99
+ * @returns A promise resolving to the created {@link Sandbox}.
100
+ */
101
+ static async create(
102
+ params?: CreateSandboxParams | (CreateSandboxParams & Credentials),
103
+ ): Promise<Sandbox> {
104
+ const credentials = getCredentials(params);
105
+ const client = new APIClient({
106
+ teamId: credentials.teamId,
107
+ token: credentials.token,
108
+ });
109
+
110
+ const sandbox = await client.createSandbox({
111
+ source: params?.source,
112
+ projectId: credentials.projectId,
113
+ ports: params?.ports ?? [],
114
+ timeout: params?.timeout,
115
+ ...(params?.resources && {
116
+ cores: params.resources.cores,
117
+ memory: 2048 * params.resources.cores,
118
+ }),
119
+ });
120
+
121
+ return new Sandbox({
122
+ client,
123
+ sandboxId: sandbox.json.sandboxId,
124
+ routes: sandbox.json.routes,
125
+ });
126
+ }
127
+
128
+ /**
129
+ * Retrieve an existing sandbox.
130
+ *
131
+ * @param params - Get parameters and optional credentials.
132
+ * @returns A promise resolving to the {@link Sandbox}.
133
+ */
134
+ static async get(
135
+ params: GetSandboxParams | (GetSandboxParams & Credentials),
136
+ ): Promise<Sandbox> {
137
+ const credentials = getCredentials(params);
138
+ const client = new APIClient({
139
+ teamId: credentials.teamId,
140
+ token: credentials.token,
141
+ });
142
+
143
+ return new Sandbox({
144
+ client,
145
+ sandboxId: params.sandboxId,
146
+ routes: params.routes,
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Create a new Sandbox instance.
152
+ *
153
+ * @param client - API client used to communicate with the backend
154
+ * @param routes - Port-to-subdomain mappings for exposed ports
155
+ * @param sandboxId - Unique identifier for the sandbox
156
+ */
157
+ constructor({
158
+ client,
159
+ routes,
160
+ sandboxId,
161
+ }: {
162
+ client: APIClient;
163
+ routes: { subdomain: string; port: number }[];
164
+ sandboxId: string;
165
+ }) {
166
+ this.client = client;
167
+ this.routes = routes;
168
+ this.sandboxId = sandboxId;
169
+ }
170
+
171
+ /**
172
+ * Get a previously run command by its ID.
173
+ *
174
+ * @param cmdId - ID of the command to retrieve
175
+ * @returns A {@link Command} instance representing the command
176
+ */
177
+ getCommand(cmdId: string): Command {
178
+ return new Command({
179
+ client: this.client,
180
+ sandboxId: this.sandboxId,
181
+ cmdId,
182
+ });
183
+ }
184
+
185
+ /**
186
+ * Start executing a command in this sandbox.
187
+ *
188
+ * @param command - The command to execute.
189
+ * @param args - Arguments to pass to the command.
190
+ * @returns A {@link CommandFinished} result once execution is done.
191
+ */
192
+ async runCommand(command: string, args?: string[]): Promise<CommandFinished>;
193
+
194
+ /**
195
+ * Start executing a command in detached mode.
196
+ *
197
+ * @param params - The command parameters.
198
+ * @returns A {@link Command} instance for the running command.
199
+ */
200
+ async runCommand(
201
+ params: RunCommandParams & { detached: true },
202
+ ): Promise<Command>;
203
+
204
+ /**
205
+ * Start executing a command in this sandbox.
206
+ *
207
+ * @param params - The command parameters.
208
+ * @returns A {@link CommandFinished} result once execution is done.
209
+ */
210
+ async runCommand(params: RunCommandParams): Promise<CommandFinished>;
211
+
212
+ async runCommand(
213
+ commandOrParams: string | RunCommandParams,
214
+ args?: string[],
215
+ ): Promise<Command | CommandFinished> {
216
+ return typeof commandOrParams === "string"
217
+ ? this._runCommand({ cmd: commandOrParams, args })
218
+ : this._runCommand(commandOrParams);
219
+ }
220
+
221
+ /**
222
+ * Internal helper to start a command in the sandbox.
223
+ *
224
+ * @param params - Command execution parameters.
225
+ * @returns A {@link Command} or {@link CommandFinished}, depending on `detached`.
226
+ * @internal
227
+ */
228
+ async _runCommand(params: RunCommandParams) {
229
+ const commandResponse = await this.client.runCommand({
230
+ sandboxId: this.sandboxId,
231
+ command: params.cmd,
232
+ args: params.args ?? [],
233
+ cwd: params.cwd,
234
+ env: params.env ?? {},
235
+ });
236
+
237
+ const command = new Command({
238
+ client: this.client,
239
+ sandboxId: this.sandboxId,
240
+ cmdId: commandResponse.json.cmdId,
241
+ });
242
+
243
+ if (params.stdout || params.stderr) {
244
+ (async () => {
245
+ for await (const log of command.logs()) {
246
+ if (log.stream === "stdout") {
247
+ params.stdout?.write(log.data);
248
+ } else if (log.stream === "stderr") {
249
+ params.stderr?.write(log.data);
250
+ }
251
+ }
252
+ })();
253
+ }
254
+
255
+ return params.detached ? command : command.wait();
256
+ }
257
+
258
+ /**
259
+ * Create a directory in the filesystem of this sandbox.
260
+ *
261
+ * @param path - Path of the directory to create
262
+ */
263
+ async mkDir(path: string): Promise<void> {
264
+ await this.client.mkDir({
265
+ sandboxId: this.sandboxId,
266
+ path: path,
267
+ });
268
+ }
269
+
270
+ /**
271
+ * Write files to the filesystem of this sandbox.
272
+ *
273
+ * @param files - Array of files with path and stream/buffer contents
274
+ * @returns A promise that resolves when the files are written
275
+ */
276
+ async writeFiles(files: { path: string; stream: Readable | Buffer }[]) {
277
+ return this.client.writeFiles({
278
+ sandboxId: this.sandboxId,
279
+ files: files,
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Get the public domain of a port of this sandbox.
285
+ *
286
+ * @param p - Port number to resolve
287
+ * @returns A full domain (e.g. `https://subdomain.vercel.run`)
288
+ * @throws If the port has no associated route
289
+ */
290
+ domain(p: number): string {
291
+ const route = this.routes.find(({ port }) => port == p);
292
+ if (route) {
293
+ return `https://${route.subdomain}.vercel.run`;
294
+ } else {
295
+ throw new Error(`No route for port ${p}`);
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Stop the sandbox.
301
+ *
302
+ * @returns A promise that resolves when the sandbox is stopped
303
+ */
304
+ async stop() {
305
+ await this.client.stopSandbox({
306
+ sandboxId: this.sandboxId,
307
+ });
308
+ }
309
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Decode a Base64 URL-encoded string into a JSON object.
3
+ *
4
+ * @param base64Url - The Base64 URL-encoded string to decode.
5
+ * @returns The decoded JSON object or null if decoding fails.
6
+ */
7
+ export function decodeBase64Url(base64Url: string) {
8
+ return JSON.parse(
9
+ Buffer.from(
10
+ base64Url.replace(/-/g, "+").replace(/_/g, "/"),
11
+ "base64",
12
+ ).toString("utf8"),
13
+ );
14
+ }
@@ -0,0 +1,113 @@
1
+ import { getVercelOidcToken } from "./get-vercel-oidc-token";
2
+ import { decodeBase64Url } from "./decode-base64-url";
3
+ import { z } from "zod";
4
+
5
+ export interface Credentials {
6
+ /**
7
+ * Authentication token for the Vercel API. It could be an OIDC token
8
+ * or a personal access token.
9
+ */
10
+ token: string;
11
+ /**
12
+ * The ID of the project to associate Sandbox operations.
13
+ */
14
+ projectId: string;
15
+ /**
16
+ * The ID of the team to associate Sandbox operations.
17
+ */
18
+ teamId: string;
19
+ }
20
+
21
+ /**
22
+ * Allow to get credentials to access the Vercel API. Credentials can be
23
+ * provided in two different ways:
24
+ *
25
+ * 1. By passing an object with the `teamId`, `token`, and `projectId` properties.
26
+ * 2. By using an environment variable VERCEL_OIDC_TOKEN.
27
+ *
28
+ * If both methods are used, the object properties take precedence over the
29
+ * environment variable. If neither method is used, an error is thrown.
30
+ */
31
+ export function getCredentials<T>(params?: T | Credentials): Credentials {
32
+ const credentials = getCredentialsFromParams(params ?? {});
33
+ if (credentials) {
34
+ return credentials;
35
+ }
36
+
37
+ const oidcToken = getVercelOidcToken();
38
+ if (oidcToken) {
39
+ return getCredentialsFromOIDCToken(oidcToken);
40
+ }
41
+
42
+ throw new Error(
43
+ "You must provide credentials to access the Vercel API \n" +
44
+ "either through parameters or using OpenID Connect [https://vercel.com/docs/oidc]",
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Attempt to extract credentials from the provided parameters. Either all
50
+ * required fields (`token`, `teamId`, and `projectId`) must be present
51
+ * or none of them, otherwise an error is thrown.
52
+ */
53
+ function getCredentialsFromParams<Params extends Record<string, unknown>>(
54
+ params: Params | Credentials,
55
+ ): Credentials | null {
56
+ const missing = [
57
+ "token" in params && typeof params.token === "string" ? null : "token",
58
+ "teamId" in params && typeof params.teamId === "string" ? null : "teamId",
59
+ "projectId" in params && typeof params.projectId === "string"
60
+ ? null
61
+ : "projectId",
62
+ ].filter((value) => value !== null);
63
+
64
+ if (missing.length === 0) {
65
+ return {
66
+ token: params.token as string,
67
+ projectId: params.projectId as string,
68
+ teamId: params.teamId as string,
69
+ };
70
+ }
71
+
72
+ if (missing.length < 3) {
73
+ throw new Error(
74
+ `Missing credentials parameters to access the Vercel API: ${missing
75
+ .filter((value) => value !== null)
76
+ .join(", ")}`,
77
+ );
78
+ }
79
+
80
+ return null;
81
+ }
82
+
83
+ /**
84
+ * Schema to validate the payload of the Vercel OIDC token where we expect
85
+ * to find the `teamId` and `projectId`.
86
+ */
87
+ const schema = z.object({
88
+ owner_id: z.string(),
89
+ project_id: z.string(),
90
+ });
91
+
92
+ /**
93
+ * Extracts credentials from a Vercel OIDC token. The token is expected to be
94
+ * a JWT with a payload that contains `project_id` and `owner_id`.
95
+ *
96
+ * @param token - The Vercel OIDC token.
97
+ * @returns An object containing the token, projectId, and teamId.
98
+ * @throws If the token is invalid or does not contain the required fields.
99
+ */
100
+ function getCredentialsFromOIDCToken(token: string): Credentials {
101
+ try {
102
+ const payload = schema.parse(decodeBase64Url(token.split(".")[1]));
103
+ return {
104
+ token,
105
+ projectId: payload.project_id,
106
+ teamId: payload.owner_id,
107
+ };
108
+ } catch (error) {
109
+ throw new Error(
110
+ `Invalid Vercel OIDC token: ${error instanceof Error ? error.message : String(error)}`,
111
+ );
112
+ }
113
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * This function is implemented in @vercel/functions but it is asynchronous.
3
+ * In order to keep it synchronous, we are implementing it here as well.
4
+ * Ideally we should remove this and use the one from @vercel/functions.
5
+ */
6
+ export function getVercelOidcToken(): string | undefined {
7
+ const token =
8
+ getContext().headers?.["x-vercel-oidc-token"] ??
9
+ process.env.VERCEL_OIDC_TOKEN;
10
+
11
+ if (!token && process.env.NODE_ENV === "production") {
12
+ throw new Error(
13
+ `The 'x-vercel-oidc-token' header is missing from the request. Do you have the OIDC option enabled in the Vercel project settings?`,
14
+ );
15
+ }
16
+
17
+ return token;
18
+ }
19
+
20
+ const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
21
+
22
+ interface Context {
23
+ headers?: Record<string, string>;
24
+ }
25
+
26
+ function getContext(): Context {
27
+ const fromSymbol: typeof globalThis & {
28
+ [SYMBOL_FOR_REQ_CONTEXT]?: { get?: () => Context };
29
+ } = globalThis;
30
+ return fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
31
+ }
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Autogenerated by inject-version.ts
2
- export const VERSION = "0.0.4";
2
+ export const VERSION = "0.0.6";
package/tsconfig.json CHANGED
@@ -9,5 +9,6 @@
9
9
  "module": "commonjs",
10
10
  "resolveJsonModule": true
11
11
  },
12
- "include": ["src/**/*"]
12
+ "include": ["src/**/*.ts"],
13
+ "exclude": ["src/**/*.test.ts", "vitest.config.ts", "vitest.setup.ts"]
13
14
  }
package/typedoc.json CHANGED
@@ -3,5 +3,11 @@
3
3
  "sort": ["source-order"],
4
4
  "navigationLinks": {
5
5
  "GitHub": "https://github.com/vercel/sandbox-sdk"
6
- }
6
+ },
7
+ "compilerOptions": {
8
+ "exclude": ["src/command.test.ts"],
9
+ "stripInternal": true
10
+ },
11
+ "excludeInternal": false,
12
+ "excludePrivate": true
7
13
  }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ setupFiles: ["./vitest.setup.ts"],
6
+ testTimeout: 60_000,
7
+ },
8
+ });
@@ -0,0 +1,4 @@
1
+ import { config } from "dotenv";
2
+ import { resolve } from "path";
3
+
4
+ config({ path: resolve(__dirname, ".env.test") });
@@ -1,196 +0,0 @@
1
- import { SandboxClient } from "./client/client";
2
- import { Readable } from "stream";
3
- /**
4
- * SDK for interacting with the Sandbox API. Provides methods to create and
5
- * manage sandboxes configured with specific source code and network ports.
6
- *
7
- * Example:
8
- * ```ts
9
- * const sdk = new SDK({
10
- * teamId: process.env.VERCEL_TEAM_ID!,
11
- * token: process.env.VERCEL_TOKEN!,
12
- * });
13
- * ```
14
- *
15
- * @see {@link SDK.createSandbox} to start a new sandbox.
16
- */
17
- export declare class SDK {
18
- /**
19
- * Internal API client for communicating with the sandbox backend.
20
- */
21
- private client;
22
- /**
23
- * Create a new instance of `SDK`.
24
- *
25
- * @param config - Configuration options for the SDK.
26
- * @param config.teamId - The Vercel team ID used to scope the Sandbox.
27
- * @param config.token - The API token used for authentication.
28
- */
29
- constructor({ teamId, token }: {
30
- teamId: string;
31
- token: string;
32
- });
33
- /**
34
- * Creates a new sandbox instance using the provided Git repository and exposed ports.
35
- *
36
- * The repository must be public. On start, the sandbox will clone the repository
37
- * and expose the specified ports for access.
38
- *
39
- * @param params - Configuration parameters for the sandbox.
40
- * @param params.source - The source of the sandbox, currently supports Git repositories only.
41
- * @param params.source.type - Type of source, must be `"git"`.
42
- * @param params.source.url - The URL of the public Git repository to clone.
43
- * @param config.projectId - The Vercel project ID used to link the Sandbox to.
44
- * @param params.ports - Array of port numbers to expose from the sandbox.
45
- * @param params.timeout - (Optional) Timeout in seconds before the sandbox auto-terminates.
46
- *
47
- * @returns A promise that resolves to a `Sandbox` instance.
48
- */
49
- createSandbox(params: {
50
- source: {
51
- type: "git";
52
- url: string;
53
- };
54
- projectId: string;
55
- ports: number[];
56
- timeout?: number;
57
- }): Promise<Sandbox>;
58
- /** @hidden */
59
- getSandbox({ routes, sandboxId, }: {
60
- routes: {
61
- subdomain: string;
62
- port: number;
63
- }[];
64
- sandboxId: string;
65
- }): Promise<Sandbox>;
66
- }
67
- /**
68
- * A Sandbox is an isolated Linux MicroVM that you can your experiments on.
69
- *
70
- * @see {@link SDK.createSandbox} to construct a Sandbox.
71
- * @hideconstructor
72
- */
73
- export declare class Sandbox {
74
- private client;
75
- /** @hidden */
76
- routes: {
77
- subdomain: string;
78
- port: number;
79
- }[];
80
- /**
81
- * The ID of this sandbox.
82
- */
83
- sandboxId: string;
84
- constructor({ client, routes, sandboxId, }: {
85
- client: SandboxClient;
86
- routes: {
87
- subdomain: string;
88
- port: number;
89
- }[];
90
- sandboxId: string;
91
- });
92
- /**
93
- * Start executing a command in this sandbox.
94
- * @param command
95
- * @param args
96
- * @returns
97
- */
98
- runCommand(command: string, args?: string[]): Promise<Command>;
99
- /**
100
- * Write files to the filesystem of this sandbox.
101
- */
102
- writeFiles(files: {
103
- path: string;
104
- stream: Readable | Buffer;
105
- }[]): Promise<void>;
106
- /**
107
- * Get the public domain of a port of this sandbox.
108
- *
109
- * E.g. `2grza2l7imxe.vercel.run`
110
- */
111
- domain(p: number): string;
112
- }
113
- /**
114
- * A command executed in a Sandbox.
115
- *
116
- * You can {@link wait} on commands to access their {@link exitCode}, and
117
- * iterate over their output with {@link logs}.
118
- *
119
- * @see {@link Sandbox.runCommand} to start a command.
120
- *
121
- * @hideconstructor
122
- */
123
- export declare class Command {
124
- private client;
125
- private sandboxId;
126
- /**
127
- * ID of the command execution.
128
- */
129
- cmdId: string;
130
- /**
131
- * The exit code of the command, if available. This is set after
132
- * {@link wait} has returned.
133
- */
134
- exitCode: number | null;
135
- constructor({ client, sandboxId, cmdId, }: {
136
- client: SandboxClient;
137
- sandboxId: string;
138
- cmdId: string;
139
- });
140
- /**
141
- * Iterate over the output of this command.
142
- *
143
- * ```
144
- * for await (const log of cmd.logs()) {
145
- * if (log.stream === "stdout") {
146
- * process.stdout.write(log.data);
147
- * } else {
148
- * process.stderr.write(log.data);
149
- * }
150
- * }
151
- * ```
152
- *
153
- * @see {@link Command.stdout}, {@link Command.stderr}, and {@link Command.output}
154
- * to access output as a string.
155
- */
156
- logs(): AsyncGenerator<{
157
- data: string;
158
- stream: "stdout" | "stderr";
159
- }, void, void>;
160
- /**
161
- * Wait for a command to exit and populate it's exit code.
162
- *
163
- * ```
164
- * await cmd.wait()
165
- * if (cmd.exitCode != 0) {
166
- * console.error("Something went wrong...")
167
- * }
168
- * ````
169
- */
170
- wait(): Promise<this>;
171
- /**
172
- * Print command logs to stdout/stderr
173
- */
174
- printLogs(): Promise<void>;
175
- /**
176
- * Get the output of `stdout` or `stderr` as a string.
177
- *
178
- * NOTE: This may error with string conversion errors if the command does
179
- * not ouptut valid unicode.
180
- */
181
- output(stream?: "stdout" | "stderr" | "both"): Promise<string>;
182
- /**
183
- * Get the output of `stdout` as a string.
184
- *
185
- * NOTE: This may error with string conversion errors if the command does
186
- * not ouptut valid unicode.
187
- */
188
- stdout(): Promise<string>;
189
- /**
190
- * Get the output of `stderr` as a string.
191
- *
192
- * NOTE: This may error with string conversion errors if the command does
193
- * not ouptut valid unicode.
194
- */
195
- stderr(): Promise<string>;
196
- }