@vercel/sandbox 1.0.3 → 1.1.0

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 (63) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +18 -0
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/CHANGELOG.md +22 -0
  5. package/LICENSE +21 -0
  6. package/README.md +4 -4
  7. package/dist/api-client/api-client.d.ts +11 -3
  8. package/dist/api-client/api-client.js +6 -1
  9. package/dist/api-client/api-client.js.map +1 -0
  10. package/dist/api-client/api-error.js +1 -0
  11. package/dist/api-client/api-error.js.map +1 -0
  12. package/dist/api-client/base-client.d.ts +1 -0
  13. package/dist/api-client/base-client.js +2 -1
  14. package/dist/api-client/base-client.js.map +1 -0
  15. package/dist/api-client/file-writer.js +1 -0
  16. package/dist/api-client/file-writer.js.map +1 -0
  17. package/dist/api-client/index.js +1 -0
  18. package/dist/api-client/index.js.map +1 -0
  19. package/dist/api-client/validators.d.ts +23 -0
  20. package/dist/api-client/validators.js +2 -0
  21. package/dist/api-client/validators.js.map +1 -0
  22. package/dist/api-client/with-retry.js +11 -0
  23. package/dist/api-client/with-retry.js.map +1 -0
  24. package/dist/command.js +1 -0
  25. package/dist/command.js.map +1 -0
  26. package/dist/constants.d.ts +1 -0
  27. package/dist/constants.js +3 -0
  28. package/dist/constants.js.map +1 -0
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/sandbox.d.ts +14 -5
  32. package/dist/sandbox.js +27 -5
  33. package/dist/sandbox.js.map +1 -0
  34. package/dist/utils/array.js +1 -0
  35. package/dist/utils/array.js.map +1 -0
  36. package/dist/utils/consume-readable.js +1 -0
  37. package/dist/utils/consume-readable.js.map +1 -0
  38. package/dist/utils/decode-base64-url.js +1 -0
  39. package/dist/utils/decode-base64-url.js.map +1 -0
  40. package/dist/utils/get-credentials.js +1 -0
  41. package/dist/utils/get-credentials.js.map +1 -0
  42. package/dist/utils/jwt-expiry.js +1 -0
  43. package/dist/utils/jwt-expiry.js.map +1 -0
  44. package/dist/utils/normalizePath.js +1 -0
  45. package/dist/utils/normalizePath.js.map +1 -0
  46. package/dist/utils/resolveSignal.js +1 -0
  47. package/dist/utils/resolveSignal.js.map +1 -0
  48. package/dist/utils/types.js +1 -0
  49. package/dist/utils/types.js.map +1 -0
  50. package/dist/version.d.ts +1 -1
  51. package/dist/version.js +2 -1
  52. package/dist/version.js.map +1 -0
  53. package/package.json +2 -2
  54. package/src/api-client/api-client.ts +20 -4
  55. package/src/api-client/base-client.ts +7 -2
  56. package/src/api-client/validators.ts +1 -0
  57. package/src/api-client/with-retry.ts +11 -0
  58. package/src/command.test.ts +81 -77
  59. package/src/constants.ts +1 -0
  60. package/src/sandbox.test.ts +60 -58
  61. package/src/sandbox.ts +37 -10
  62. package/src/version.ts +1 -1
  63. package/tsconfig.json +1 -0
package/dist/sandbox.js CHANGED
@@ -18,6 +18,9 @@ class Sandbox {
18
18
  get sandboxId() {
19
19
  return this.sandbox.id;
20
20
  }
21
+ get interactivePort() {
22
+ return this.sandbox.interactivePort ?? undefined;
23
+ }
21
24
  /**
22
25
  * The status of the sandbox.
23
26
  */
@@ -40,6 +43,7 @@ class Sandbox {
40
43
  const client = new api_client_1.APIClient({
41
44
  teamId: credentials.teamId,
42
45
  token: credentials.token,
46
+ fetch: params.fetch,
43
47
  });
44
48
  return client.listSandboxes({
45
49
  ...params,
@@ -57,6 +61,7 @@ class Sandbox {
57
61
  const client = new api_client_1.APIClient({
58
62
  teamId: credentials.teamId,
59
63
  token: credentials.token,
64
+ fetch: params?.fetch,
60
65
  });
61
66
  const privateParams = (0, types_1.getPrivateParams)(params);
62
67
  const sandbox = await client.createSandbox({
@@ -86,10 +91,13 @@ class Sandbox {
86
91
  const client = new api_client_1.APIClient({
87
92
  teamId: credentials.teamId,
88
93
  token: credentials.token,
94
+ fetch: params.fetch,
89
95
  });
96
+ const privateParams = (0, types_1.getPrivateParams)(params);
90
97
  const sandbox = await client.getSandbox({
91
98
  sandboxId: params.sandboxId,
92
99
  signal: params.signal,
100
+ ...privateParams,
93
101
  });
94
102
  return new Sandbox({
95
103
  client,
@@ -158,13 +166,21 @@ class Sandbox {
158
166
  });
159
167
  if (params.stdout || params.stderr) {
160
168
  (async () => {
161
- for await (const log of command.logs({ signal: params.signal })) {
162
- if (log.stream === "stdout") {
163
- params.stdout?.write(log.data);
169
+ try {
170
+ for await (const log of command.logs({ signal: params.signal })) {
171
+ if (log.stream === "stdout") {
172
+ params.stdout?.write(log.data);
173
+ }
174
+ else if (log.stream === "stderr") {
175
+ params.stderr?.write(log.data);
176
+ }
164
177
  }
165
- else if (log.stream === "stderr") {
166
- params.stderr?.write(log.data);
178
+ }
179
+ catch (err) {
180
+ if (params.signal?.aborted) {
181
+ return;
167
182
  }
183
+ throw err;
168
184
  }
169
185
  })();
170
186
  }
@@ -258,6 +274,11 @@ class Sandbox {
258
274
  * @param opts - Optional parameters.
259
275
  * @param opts.signal - An AbortSignal to cancel the operation.
260
276
  * @returns A promise that resolves when the timeout is extended
277
+ *
278
+ * @example
279
+ * const sandbox = await Sandbox.create({ timeout: ms('10m') });
280
+ * // Extends timeout by 5 minutes, to a total of 15 minutes.
281
+ * await sandbox.extendTimeout(ms('5m'));
261
282
  */
262
283
  async extendTimeout(duration, opts) {
263
284
  const response = await this.client.extendTimeout({
@@ -270,3 +291,4 @@ class Sandbox {
270
291
  }
271
292
  }
272
293
  exports.Sandbox = Sandbox;
294
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
@@ -16,3 +16,4 @@ function array(item) {
16
16
  : [item]
17
17
  : [];
18
18
  }
19
+ //# sourceMappingURL=array.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.js","sourceRoot":"","sources":["../../src/utils/array.ts"],"names":[],"mappings":";;AAQA,sBAMC;AAdD;;;;;;;GAOG;AACH,SAAgB,KAAK,CAAI,IAAqB;IAC5C,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;QACxC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YACnB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,CAAC,IAAI,CAAC;QACV,CAAC,CAAC,EAAE,CAAC;AACT,CAAC"}
@@ -13,3 +13,4 @@ function consumeReadable(readable) {
13
13
  readable.on("end", () => resolve(Buffer.concat(chunks)));
14
14
  });
15
15
  }
16
+ //# sourceMappingURL=consume-readable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consume-readable.js","sourceRoot":"","sources":["../../src/utils/consume-readable.ts"],"names":[],"mappings":";;AAIA,0CAOC;AAXD;;;GAGG;AACH,SAAgB,eAAe,CAAC,QAA+B;IAC7D,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACnD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -10,3 +10,4 @@ exports.decodeBase64Url = decodeBase64Url;
10
10
  function decodeBase64Url(base64Url) {
11
11
  return JSON.parse(Buffer.from(base64Url.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8"));
12
12
  }
13
+ //# sourceMappingURL=decode-base64-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-base64-url.js","sourceRoot":"","sources":["../../src/utils/decode-base64-url.ts"],"names":[],"mappings":";;AAMA,0CAOC;AAbD;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,SAAiB;IAC/C,OAAO,IAAI,CAAC,KAAK,CACf,MAAM,CAAC,IAAI,CACT,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAC/C,QAAQ,CACT,CAAC,QAAQ,CAAC,MAAM,CAAC,CACnB,CAAC;AACJ,CAAC"}
@@ -89,3 +89,4 @@ function getCredentialsFromOIDCToken(token) {
89
89
  throw new Error(`Invalid Vercel OIDC token: ${error instanceof Error ? error.message : String(error)}`);
90
90
  }
91
91
  }
92
+ //# sourceMappingURL=get-credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-credentials.js","sourceRoot":"","sources":["../../src/utils/get-credentials.ts"],"names":[],"mappings":"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"}
@@ -103,3 +103,4 @@ exports.JwtExpiry = JwtExpiry;
103
103
  function isJwtFormat(token) {
104
104
  return token.split(".").length === 3;
105
105
  }
106
+ //# sourceMappingURL=jwt-expiry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-expiry.js","sourceRoot":"","sources":["../../src/utils/jwt-expiry.ts"],"names":[],"mappings":";;;;;;AACA,2DAAsD;AACtD,uDAA2C;AAC3C,uCAAkD;AAClD,4CAAoB;AAEpB,+EAA+E;AAC/E,MAAM,SAAS,GAAG,IAAA,YAAE,EAAC,IAAI,CAAC,CAAC;AAE3B,MAAa,gBAAiB,SAAQ,KAAK;IAA3C;;QACE,SAAI,GAAG,kBAAkB,CAAC;IAC5B,CAAC;CAAA;AAFD,4CAEC;AAED;;;GAGG;AACH,MAAa,SAAS;IAIpB,MAAM,CAAC,SAAS,CAAC,KAAa;QAC5B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,YAAqB,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;QAChC,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,IAAI,CAAC,OAAO,GAAG,wBAAM,CAAC,KAAK,CAAC,IAAA,mCAAe,EAAC,aAAa,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;YACxD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC,CAAC,gCAAgC;QAChD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;QAChC,OAAO,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;IACxC,CAAC;IAED;;;;OAIG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,IAAA,yBAAkB,GAAE,CAAC;YAC9C,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,EAAE;gBACzD,KAAK;aACN,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,CAAC,kCAAkC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;CACF;AA7ED,8BA6EC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACvC,CAAC"}
@@ -29,3 +29,4 @@ function normalizePath(params) {
29
29
  : path_1.default.posix.join(params.cwd, params.filePath);
30
30
  return path_1.default.posix.relative(params.extractDir, basePath);
31
31
  }
32
+ //# sourceMappingURL=normalizePath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizePath.js","sourceRoot":"","sources":["../../src/utils/normalizePath.ts"],"names":[],"mappings":";;;;;AAcA,sCAkBC;AAhCD,gDAAwB;AAExB;;;;;;;;;;;GAWG;AACH,SAAgB,aAAa,CAAC,MAI7B;IACC,IAAI,CAAC,cAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,CAAC,cAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,QAAQ,GAAG,cAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC;QACrD,CAAC,CAAC,cAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;QACvC,CAAC,CAAC,cAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEjD,OAAO,cAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC1D,CAAC"}
@@ -19,3 +19,4 @@ function resolveSignal(signal) {
19
19
  }
20
20
  throw new Error(`Unknown signal name: ${String(signal)}`);
21
21
  }
22
+ //# sourceMappingURL=resolveSignal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveSignal.js","sourceRoot":"","sources":["../../src/utils/resolveSignal.ts"],"names":[],"mappings":";;AAcA,sCASC;AAvBD,MAAM,kBAAkB,GAAG;IACzB,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;CACH,CAAC;AAMX,SAAgB,aAAa,CAAC,MAAc;IAC1C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,MAAM,IAAI,kBAAkB,EAAE,CAAC;QACjC,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC"}
@@ -9,3 +9,4 @@ const getPrivateParams = (params) => {
9
9
  return Object.fromEntries(privateEntries);
10
10
  };
11
11
  exports.getPrivateParams = getPrivateParams;
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":";;;AAUA;;GAEG;AACI,MAAM,gBAAgB,GAAG,CAAC,MAAe,EAAE,EAAE;IAClD,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CACjE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CACnB,CAAC;IACF,OAAO,MAAM,CAAC,WAAW,CAAC,cAAc,CAIvC,CAAC;AACJ,CAAC,CAAC;AATW,QAAA,gBAAgB,oBAS3B"}
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "1.0.3";
1
+ export declare const VERSION = "1.1.0";
package/dist/version.js CHANGED
@@ -2,4 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Autogenerated by inject-version.ts
5
- exports.VERSION = "1.0.3";
5
+ exports.VERSION = "1.1.0";
6
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AACxB,QAAA,OAAO,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@vercel/sandbox",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "private": false,
8
8
  "keywords": [],
9
9
  "author": "",
10
- "license": "ISC",
10
+ "license": "MIT",
11
11
  "dependencies": {
12
12
  "@vercel/oidc": "^3.0.5",
13
13
  "async-retry": "1.3.3",
@@ -25,16 +25,27 @@ import { Readable } from "stream";
25
25
  import { normalizePath } from "../utils/normalizePath";
26
26
  import { JwtExpiry } from "../utils/jwt-expiry";
27
27
  import { getPrivateParams, WithPrivate } from "../utils/types";
28
+ import { RUNTIMES } from "../constants";
29
+
30
+ export interface WithFetchOptions {
31
+ fetch?: typeof globalThis.fetch;
32
+ }
28
33
 
29
34
  export class APIClient extends BaseClient {
30
35
  private teamId: string;
31
36
  private tokenExpiry: JwtExpiry | null;
32
37
 
33
- constructor(params: { baseUrl?: string; teamId: string; token: string }) {
38
+ constructor(params: {
39
+ baseUrl?: string;
40
+ teamId: string;
41
+ token: string;
42
+ fetch?: typeof globalThis.fetch;
43
+ }) {
34
44
  super({
35
45
  baseUrl: params.baseUrl ?? "https://vercel.com/api",
36
46
  token: params.token,
37
47
  debug: false,
48
+ fetch: params.fetch,
38
49
  });
39
50
 
40
51
  this.teamId = params.teamId;
@@ -72,10 +83,15 @@ export class APIClient extends BaseClient {
72
83
  });
73
84
  }
74
85
 
75
- async getSandbox(params: { sandboxId: string; signal?: AbortSignal }) {
86
+ async getSandbox(
87
+ params: WithPrivate<{ sandboxId: string; signal?: AbortSignal }>,
88
+ ) {
89
+ const privateParams = getPrivateParams(params);
90
+ let querystring = new URLSearchParams(privateParams).toString();
91
+ querystring = querystring ? `?${querystring}` : "";
76
92
  return parseOrThrow(
77
93
  SandboxAndRoutesResponse,
78
- await this.request(`/v1/sandboxes/${params.sandboxId}`, {
94
+ await this.request(`/v1/sandboxes/${params.sandboxId}${querystring}`, {
79
95
  signal: params.signal,
80
96
  }),
81
97
  );
@@ -97,7 +113,7 @@ export class APIClient extends BaseClient {
97
113
  | { type: "tarball"; url: string };
98
114
  timeout?: number;
99
115
  resources?: { vcpus: number };
100
- runtime?: "node22" | "python3.13" | (string & {});
116
+ runtime?: RUNTIMES | (string & {});
101
117
  signal?: AbortSignal;
102
118
  }>,
103
119
  ) {
@@ -25,8 +25,13 @@ export class BaseClient {
25
25
  private baseUrl: string;
26
26
  private agent: Agent;
27
27
 
28
- constructor(params: { debug?: boolean; baseUrl: string; token?: string }) {
29
- this.fetch = withRetry(globalThis.fetch);
28
+ constructor(params: {
29
+ debug?: boolean;
30
+ baseUrl: string;
31
+ token?: string;
32
+ fetch?: typeof globalThis.fetch;
33
+ }) {
34
+ this.fetch = withRetry(params.fetch ?? globalThis.fetch);
30
35
  this.baseUrl = params.baseUrl;
31
36
  this.debug = params.debug ?? process.env.DEBUG_FETCH === "true";
32
37
  this.token = params.token;
@@ -18,6 +18,7 @@ export const Sandbox = z.object({
18
18
  createdAt: z.number(),
19
19
  cwd: z.string(),
20
20
  updatedAt: z.number(),
21
+ interactivePort: z.number().optional(),
21
22
  });
22
23
 
23
24
  export type SandboxRouteData = z.infer<typeof SandboxRoute>;
@@ -49,6 +49,9 @@ export function withRetry<T extends RequestInit>(
49
49
  try {
50
50
  return (await retry(async (bail) => {
51
51
  try {
52
+ if (opts.signal?.aborted) {
53
+ return bail(opts.signal.reason || new Error("Request aborted"));
54
+ }
52
55
  const response = await rawFetch(url, opts);
53
56
 
54
57
  /**
@@ -93,6 +96,14 @@ export function withRetry<T extends RequestInit>(
93
96
  return bail(error);
94
97
  }
95
98
 
99
+ /**
100
+ * If the signal was aborted meanwhile we were
101
+ * waiting, we bail from retrying.
102
+ */
103
+ if (opts.signal?.aborted) {
104
+ return bail(opts.signal.reason || new Error("Request aborted"));
105
+ }
106
+
96
107
  throw error;
97
108
  }
98
109
  }, retryOpts)) as Response;
@@ -1,99 +1,103 @@
1
- import { expect, it, vi, beforeEach, afterEach } from "vitest";
1
+ import { expect, it, vi, beforeEach, afterEach, describe } from "vitest";
2
2
  import { Sandbox } from "./sandbox";
3
3
 
4
- let sandbox: Sandbox;
4
+ describe.skipIf(process.env.RUN_INTEGRATION_TESTS !== "1")("Command", () => {
5
+ let sandbox: Sandbox;
5
6
 
6
- beforeEach(async () => {
7
- sandbox = await Sandbox.create();
8
- });
9
-
10
- afterEach(async () => {
11
- await sandbox.stop();
12
- });
13
-
14
- it("supports more than one logs consumer", async () => {
15
- const stdoutSpy = vi
16
- .spyOn(process.stdout, "write")
17
- .mockImplementation(() => true);
18
-
19
- const cmd = await sandbox.runCommand({
20
- cmd: "echo",
21
- args: ["Hello World!"],
22
- stdout: process.stdout,
7
+ beforeEach(async () => {
8
+ sandbox = await Sandbox.create();
23
9
  });
24
10
 
25
- expect(await cmd.stdout()).toEqual("Hello World!\n");
26
- expect(stdoutSpy).toHaveBeenCalledWith("Hello World!\n");
27
- });
28
-
29
- it("does not warn when there is only one logs consumer", async () => {
30
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
31
-
32
- const cmd = await sandbox.runCommand({
33
- cmd: "echo",
34
- args: ["Hello World!"],
11
+ afterEach(async () => {
12
+ await sandbox.stop();
35
13
  });
36
14
 
37
- expect(await cmd.stdout()).toEqual("Hello World!\n");
38
- expect(warnSpy).not.toHaveBeenCalled();
39
- });
40
-
41
- it("Kills a command with a SIGINT", async () => {
42
- const cmd = await sandbox.runCommand({
43
- cmd: "sleep",
44
- args: ["200000"],
45
- detached: true,
46
- });
15
+ it("supports more than one logs consumer", async () => {
16
+ const stdoutSpy = vi
17
+ .spyOn(process.stdout, "write")
18
+ .mockImplementation(() => true);
47
19
 
48
- await cmd.kill("SIGINT");
49
- const result = await cmd.wait();
50
- expect(result.exitCode).toBe(130); // 128 + 2
51
- });
20
+ const cmd = await sandbox.runCommand({
21
+ cmd: "echo",
22
+ args: ["Hello World!"],
23
+ stdout: process.stdout,
24
+ });
52
25
 
53
- it("Kills a command with a SIGTERM", async () => {
54
- const cmd = await sandbox.runCommand({
55
- cmd: "sleep",
56
- args: ["200000"],
57
- detached: true,
26
+ expect(await cmd.stdout()).toEqual("Hello World!\n");
27
+ expect(stdoutSpy).toHaveBeenCalledWith("Hello World!\n");
58
28
  });
59
29
 
60
- await cmd.kill("SIGTERM");
30
+ it("does not warn when there is only one logs consumer", async () => {
31
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
61
32
 
62
- const result = await cmd.wait();
63
- expect(result.exitCode).toBe(143); // 128 + 15
64
- });
33
+ const cmd = await sandbox.runCommand({
34
+ cmd: "echo",
35
+ args: ["Hello World!"],
36
+ });
65
37
 
66
- it("can execute commands with sudo", async () => {
67
- const cmd = await sandbox.runCommand({
68
- cmd: "env",
69
- sudo: true,
70
- env: {
71
- FOO: "bar",
72
- },
38
+ expect(await cmd.stdout()).toEqual("Hello World!\n");
39
+ expect(warnSpy).not.toHaveBeenCalled();
73
40
  });
74
41
 
75
- expect(cmd.exitCode).toBe(0);
42
+ it("Kills a command with a SIGINT", async () => {
43
+ const cmd = await sandbox.runCommand({
44
+ cmd: "sleep",
45
+ args: ["200000"],
46
+ detached: true,
47
+ });
76
48
 
77
- const output = await cmd.stdout();
78
- expect(output).toContain("FOO=bar\n");
79
- expect(output).toContain("USER=root\n");
80
- expect(output).toContain("SUDO_USER=vercel-sandbox\n");
49
+ await cmd.kill("SIGINT");
50
+ const result = await cmd.wait();
51
+ expect(result.exitCode).toBe(130); // 128 + 2
52
+ });
81
53
 
82
- const pathLine = output.split("\n").find((line) => line.startsWith("PATH="));
83
- expect(pathLine).toBeDefined();
54
+ it("Kills a command with a SIGTERM", async () => {
55
+ const cmd = await sandbox.runCommand({
56
+ cmd: "sleep",
57
+ args: ["200000"],
58
+ detached: true,
59
+ });
84
60
 
85
- const pathSegments = pathLine!.slice(5).split(":");
86
- expect(pathSegments).toContain("/vercel/bin");
87
- expect(pathSegments).toContain("/vercel/runtimes/node22/bin");
61
+ await cmd.kill("SIGTERM");
88
62
 
89
- const dnf = await sandbox.runCommand({
90
- cmd: "dnf",
91
- args: ["install", "-y", "golang"],
92
- sudo: true,
63
+ const result = await cmd.wait();
64
+ expect(result.exitCode).toBe(143); // 128 + 15
93
65
  });
94
66
 
95
- expect(dnf.exitCode).toBe(0);
96
-
97
- const which = await sandbox.runCommand("which", ["go"]);
98
- expect(await which.output()).toContain("/usr/bin/go");
67
+ it("can execute commands with sudo", async () => {
68
+ const cmd = await sandbox.runCommand({
69
+ cmd: "env",
70
+ sudo: true,
71
+ env: {
72
+ FOO: "bar",
73
+ },
74
+ });
75
+
76
+ expect(cmd.exitCode).toBe(0);
77
+
78
+ const output = await cmd.stdout();
79
+ expect(output).toContain("FOO=bar\n");
80
+ expect(output).toContain("USER=root\n");
81
+ expect(output).toContain("SUDO_USER=vercel-sandbox\n");
82
+
83
+ const pathLine = output
84
+ .split("\n")
85
+ .find((line) => line.startsWith("PATH="));
86
+ expect(pathLine).toBeDefined();
87
+
88
+ const pathSegments = pathLine!.slice(5).split(":");
89
+ expect(pathSegments).toContain("/vercel/bin");
90
+ expect(pathSegments).toContain("/vercel/runtimes/node22/bin");
91
+
92
+ const dnf = await sandbox.runCommand({
93
+ cmd: "dnf",
94
+ args: ["install", "-y", "golang"],
95
+ sudo: true,
96
+ });
97
+
98
+ expect(dnf.exitCode).toBe(0);
99
+
100
+ const which = await sandbox.runCommand("which", ["go"]);
101
+ expect(await which.output()).toContain("/usr/bin/go");
102
+ });
99
103
  });
@@ -0,0 +1 @@
1
+ export type RUNTIMES = "node24" | "node22" | "python3.13";