@vercel/sandbox 0.0.8 → 0.0.10

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/dist/sandbox.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { type Writable } from "stream";
1
+ import type { SandboxData, SandboxRouteData } from "./api-client";
2
+ import type { Writable } from "stream";
2
3
  import { APIClient } from "./api-client";
3
- import { Command, CommandFinished } from "./command";
4
+ import { Command, type CommandFinished } from "./command";
4
5
  import { type Credentials } from "./utils/get-credentials";
5
6
  /** @inline */
6
7
  export interface CreateSandboxParams {
@@ -18,6 +19,13 @@ export interface CreateSandboxParams {
18
19
  url: string;
19
20
  depth?: number;
20
21
  revision?: string;
22
+ } | {
23
+ type: "git";
24
+ url: string;
25
+ username: string;
26
+ password: string;
27
+ depth?: number;
28
+ revision?: string;
21
29
  } | {
22
30
  type: "tarball";
23
31
  url: string;
@@ -47,13 +55,6 @@ export interface CreateSandboxParams {
47
55
  }
48
56
  /** @inline */
49
57
  interface GetSandboxParams {
50
- /**
51
- * Port-to-subdomain route mappings.
52
- */
53
- routes: Array<{
54
- subdomain: string;
55
- port: number;
56
- }>;
57
58
  /**
58
59
  * Unique identifier of the sandbox.
59
60
  */
@@ -102,14 +103,15 @@ export declare class Sandbox {
102
103
  * Routes from ports to subdomains.
103
104
  /* @hidden
104
105
  */
105
- readonly routes: {
106
- subdomain: string;
107
- port: number;
108
- }[];
106
+ readonly routes: SandboxRouteData[];
109
107
  /**
110
108
  * Unique ID of this sandbox.
111
109
  */
112
- readonly sandboxId: string;
110
+ get sandboxId(): string;
111
+ /**
112
+ * Data about this sandbox.
113
+ */
114
+ private readonly sandbox;
113
115
  /**
114
116
  * Create a new sandbox.
115
117
  *
@@ -131,13 +133,10 @@ export declare class Sandbox {
131
133
  * @param routes - Port-to-subdomain mappings for exposed ports
132
134
  * @param sandboxId - Unique identifier for the sandbox
133
135
  */
134
- constructor({ client, routes, sandboxId, }: {
136
+ constructor({ client, routes, sandbox, }: {
135
137
  client: APIClient;
136
- routes: {
137
- subdomain: string;
138
- port: number;
139
- }[];
140
- sandboxId: string;
138
+ routes: SandboxRouteData[];
139
+ sandbox: SandboxData;
141
140
  });
142
141
  /**
143
142
  * Get a previously run command by its ID.
@@ -145,7 +144,7 @@ export declare class Sandbox {
145
144
  * @param cmdId - ID of the command to retrieve
146
145
  * @returns A {@link Command} instance representing the command
147
146
  */
148
- getCommand(cmdId: string): Command;
147
+ getCommand(cmdId: string): Promise<Command>;
149
148
  /**
150
149
  * Start executing a command in this sandbox.
151
150
  *
@@ -184,6 +183,16 @@ export declare class Sandbox {
184
183
  * @param path - Path of the directory to create
185
184
  */
186
185
  mkDir(path: string): Promise<void>;
186
+ /**
187
+ * Read a file from the filesystem of this sandbox.
188
+ *
189
+ * @param file - File to read, with path and optional cwd
190
+ * @returns A promise that resolves to a ReadableStream containing the file contents
191
+ */
192
+ readFile(file: {
193
+ path: string;
194
+ cwd?: string;
195
+ }): Promise<NodeJS.ReadableStream | null>;
187
196
  /**
188
197
  * Write files to the filesystem of this sandbox.
189
198
  *
package/dist/sandbox.js CHANGED
@@ -11,6 +11,12 @@ const get_credentials_1 = require("./utils/get-credentials");
11
11
  * @hideconstructor
12
12
  */
13
13
  class Sandbox {
14
+ /**
15
+ * Unique ID of this sandbox.
16
+ */
17
+ get sandboxId() {
18
+ return this.sandbox.id;
19
+ }
14
20
  /**
15
21
  * Create a new sandbox.
16
22
  *
@@ -33,7 +39,7 @@ class Sandbox {
33
39
  });
34
40
  return new Sandbox({
35
41
  client,
36
- sandboxId: sandbox.json.sandboxId,
42
+ sandbox: sandbox.json.sandbox,
37
43
  routes: sandbox.json.routes,
38
44
  });
39
45
  }
@@ -49,10 +55,13 @@ class Sandbox {
49
55
  teamId: credentials.teamId,
50
56
  token: credentials.token,
51
57
  });
58
+ const sandbox = await client.getSandbox({
59
+ sandboxId: params.sandboxId,
60
+ });
52
61
  return new Sandbox({
53
62
  client,
54
- sandboxId: params.sandboxId,
55
- routes: params.routes,
63
+ sandbox: sandbox.json.sandbox,
64
+ routes: sandbox.json.routes,
56
65
  });
57
66
  }
58
67
  /**
@@ -62,10 +71,10 @@ class Sandbox {
62
71
  * @param routes - Port-to-subdomain mappings for exposed ports
63
72
  * @param sandboxId - Unique identifier for the sandbox
64
73
  */
65
- constructor({ client, routes, sandboxId, }) {
74
+ constructor({ client, routes, sandbox, }) {
66
75
  this.client = client;
67
76
  this.routes = routes;
68
- this.sandboxId = sandboxId;
77
+ this.sandbox = sandbox;
69
78
  }
70
79
  /**
71
80
  * Get a previously run command by its ID.
@@ -73,11 +82,15 @@ class Sandbox {
73
82
  * @param cmdId - ID of the command to retrieve
74
83
  * @returns A {@link Command} instance representing the command
75
84
  */
76
- getCommand(cmdId) {
85
+ async getCommand(cmdId) {
86
+ const command = await this.client.getCommand({
87
+ sandboxId: this.sandbox.id,
88
+ cmdId,
89
+ });
77
90
  return new command_1.Command({
78
91
  client: this.client,
79
- sandboxId: this.sandboxId,
80
- cmdId,
92
+ sandboxId: this.sandbox.id,
93
+ cmd: command.json.command,
81
94
  });
82
95
  }
83
96
  async runCommand(commandOrParams, args) {
@@ -94,7 +107,7 @@ class Sandbox {
94
107
  */
95
108
  async _runCommand(params) {
96
109
  const commandResponse = await this.client.runCommand({
97
- sandboxId: this.sandboxId,
110
+ sandboxId: this.sandbox.id,
98
111
  command: params.cmd,
99
112
  args: params.args ?? [],
100
113
  cwd: params.cwd,
@@ -102,8 +115,8 @@ class Sandbox {
102
115
  });
103
116
  const command = new command_1.Command({
104
117
  client: this.client,
105
- sandboxId: this.sandboxId,
106
- cmdId: commandResponse.json.cmdId,
118
+ sandboxId: this.sandbox.id,
119
+ cmd: commandResponse.json.command,
107
120
  });
108
121
  if (params.stdout || params.stderr) {
109
122
  (async () => {
@@ -126,10 +139,23 @@ class Sandbox {
126
139
  */
127
140
  async mkDir(path) {
128
141
  await this.client.mkDir({
129
- sandboxId: this.sandboxId,
142
+ sandboxId: this.sandbox.id,
130
143
  path: path,
131
144
  });
132
145
  }
146
+ /**
147
+ * Read a file from the filesystem of this sandbox.
148
+ *
149
+ * @param file - File to read, with path and optional cwd
150
+ * @returns A promise that resolves to a ReadableStream containing the file contents
151
+ */
152
+ async readFile(file) {
153
+ return this.client.readFile({
154
+ sandboxId: this.sandbox.id,
155
+ path: file.path,
156
+ cwd: file.cwd,
157
+ });
158
+ }
133
159
  /**
134
160
  * Write files to the filesystem of this sandbox.
135
161
  *
@@ -138,7 +164,7 @@ class Sandbox {
138
164
  */
139
165
  async writeFiles(files) {
140
166
  return this.client.writeFiles({
141
- sandboxId: this.sandboxId,
167
+ sandboxId: this.sandbox.id,
142
168
  files: files,
143
169
  });
144
170
  }
@@ -165,7 +191,7 @@ class Sandbox {
165
191
  */
166
192
  async stop() {
167
193
  await this.client.stopSandbox({
168
- sandboxId: this.sandboxId,
194
+ sandboxId: this.sandbox.id,
169
195
  });
170
196
  }
171
197
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Consumes a readable entirely concatenating all content in a single Buffer
3
+ * @param readable A Readable stream
4
+ */
5
+ export declare function consumeReadable(readable: NodeJS.ReadableStream): Promise<Buffer<ArrayBufferLike>>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.consumeReadable = consumeReadable;
4
+ /**
5
+ * Consumes a readable entirely concatenating all content in a single Buffer
6
+ * @param readable A Readable stream
7
+ */
8
+ function consumeReadable(readable) {
9
+ return new Promise((resolve, reject) => {
10
+ const chunks = [];
11
+ readable.on("error", (err) => reject(err));
12
+ readable.on("data", (chunk) => chunks.push(chunk));
13
+ readable.on("end", () => resolve(Buffer.concat(chunks)));
14
+ });
15
+ }
@@ -0,0 +1,13 @@
1
+ declare const linuxSignalMapping: {
2
+ readonly SIGHUP: 1;
3
+ readonly SIGINT: 2;
4
+ readonly SIGQUIT: 3;
5
+ readonly SIGKILL: 9;
6
+ readonly SIGTERM: 15;
7
+ readonly SIGCONT: 18;
8
+ readonly SIGSTOP: 19;
9
+ };
10
+ type CommonLinuxSignals = keyof typeof linuxSignalMapping;
11
+ export type Signal = CommonLinuxSignals | number;
12
+ export declare function resolveSignal(signal: Signal): number;
13
+ export {};
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveSignal = resolveSignal;
4
+ const linuxSignalMapping = {
5
+ SIGHUP: 1,
6
+ SIGINT: 2,
7
+ SIGQUIT: 3,
8
+ SIGKILL: 9,
9
+ SIGTERM: 15,
10
+ SIGCONT: 18,
11
+ SIGSTOP: 19,
12
+ };
13
+ function resolveSignal(signal) {
14
+ if (typeof signal === "number") {
15
+ return signal;
16
+ }
17
+ if (signal in linuxSignalMapping) {
18
+ return linuxSignalMapping[signal];
19
+ }
20
+ throw new Error(`Unknown signal name: ${String(signal)}`);
21
+ }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.0.8";
1
+ export declare const VERSION = "0.0.10";
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Autogenerated by inject-version.ts
5
- exports.VERSION = "0.0.8";
5
+ exports.VERSION = "0.0.10";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/sandbox",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -5,18 +5,18 @@ import {
5
5
  type RequestParams,
6
6
  } from "./base-client";
7
7
  import {
8
- Command,
9
- CommandFinished,
10
- CreatedCommand,
11
- CreatedSandbox,
8
+ SandboxAndRoutesResponse,
9
+ SandboxResponse,
10
+ CommandResponse,
11
+ CommandFinishedResponse,
12
+ EmptyResponse,
12
13
  LogLine,
13
- StoppedSandbox,
14
- WrittenFile,
15
14
  } from "./validators";
16
15
  import { APIError } from "./api-error";
17
16
  import { FileWriter } from "./file-writer";
18
17
  import { LRUCache } from "lru-cache";
19
18
  import { VERSION } from "../version";
19
+ import { consumeReadable } from "../utils/consume-readable";
20
20
  import { z } from "zod";
21
21
  import jsonlines from "jsonlines";
22
22
  import os from "os";
@@ -56,18 +56,32 @@ export class APIClient extends BaseClient {
56
56
  });
57
57
  }
58
58
 
59
+ async getSandbox(params: { sandboxId: string }) {
60
+ return parseOrThrow(
61
+ SandboxAndRoutesResponse,
62
+ await this.request(`/v1/sandboxes/${params.sandboxId}`),
63
+ );
64
+ }
65
+
59
66
  async createSandbox(params: {
60
67
  ports?: number[];
61
68
  projectId: string;
62
69
  source?:
63
- | { type: "git"; url: string; depth?: number; revision?: string }
70
+ | {
71
+ type: "git";
72
+ url: string;
73
+ depth?: number;
74
+ revision?: string;
75
+ username?: string;
76
+ password?: string;
77
+ }
64
78
  | { type: "tarball"; url: string };
65
79
  timeout?: number;
66
80
  resources?: { vcpus: number };
67
81
  runtime?: "node22" | "python3.13";
68
82
  }) {
69
83
  return parseOrThrow(
70
- CreatedSandbox,
84
+ SandboxAndRoutesResponse,
71
85
  await this.request("/v1/sandboxes", {
72
86
  method: "POST",
73
87
  body: JSON.stringify({
@@ -90,7 +104,7 @@ export class APIClient extends BaseClient {
90
104
  env: Record<string, string>;
91
105
  }) {
92
106
  return parseOrThrow(
93
- CreatedCommand,
107
+ CommandResponse,
94
108
  await this.request(`/v1/sandboxes/${params.sandboxId}/cmd`, {
95
109
  method: "POST",
96
110
  body: JSON.stringify({
@@ -107,12 +121,12 @@ export class APIClient extends BaseClient {
107
121
  sandboxId: string;
108
122
  cmdId: string;
109
123
  wait: true;
110
- }): Promise<Parsed<z.infer<typeof CommandFinished>>>;
124
+ }): Promise<Parsed<z.infer<typeof CommandFinishedResponse>>>;
111
125
  async getCommand(params: {
112
126
  sandboxId: string;
113
127
  cmdId: string;
114
128
  wait?: boolean;
115
- }): Promise<Parsed<z.infer<typeof Command>>>;
129
+ }): Promise<Parsed<z.infer<typeof CommandResponse>>>;
116
130
  async getCommand(params: {
117
131
  sandboxId: string;
118
132
  cmdId: string;
@@ -120,14 +134,14 @@ export class APIClient extends BaseClient {
120
134
  }) {
121
135
  return params.wait
122
136
  ? parseOrThrow(
123
- CommandFinished,
137
+ CommandFinishedResponse,
124
138
  await this.request(
125
139
  `/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`,
126
140
  { query: { wait: "true" } },
127
141
  ),
128
142
  )
129
143
  : parseOrThrow(
130
- Command,
144
+ CommandResponse,
131
145
  await this.request(
132
146
  `/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`,
133
147
  ),
@@ -136,7 +150,7 @@ export class APIClient extends BaseClient {
136
150
 
137
151
  async mkDir(params: { sandboxId: string; path: string; cwd?: string }) {
138
152
  return parseOrThrow(
139
- WrittenFile,
153
+ EmptyResponse,
140
154
  await this.request(`/v1/sandboxes/${params.sandboxId}/fs/mkdir`, {
141
155
  method: "POST",
142
156
  body: JSON.stringify({ path: params.path, cwd: params.cwd }),
@@ -147,11 +161,13 @@ export class APIClient extends BaseClient {
147
161
  getFileWriter(params: { sandboxId: string }) {
148
162
  const writer = new FileWriter();
149
163
  return {
150
- response: this.request(`/v1/sandboxes/${params.sandboxId}/fs/write`, {
151
- method: "POST",
152
- headers: { "content-type": "application/gzip" },
153
- body: writer.readable,
154
- }),
164
+ response: (async () => {
165
+ return this.request(`/v1/sandboxes/${params.sandboxId}/fs/write`, {
166
+ method: "POST",
167
+ headers: { "content-type": "application/gzip" },
168
+ body: await consumeReadable(writer.readable),
169
+ });
170
+ })(),
155
171
  writer,
156
172
  };
157
173
  }
@@ -168,8 +184,8 @@ export class APIClient extends BaseClient {
168
184
  await writer.addFile({ name: file.path, content: file.stream });
169
185
  }
170
186
 
171
- await writer.end();
172
- await parseOrThrow(WrittenFile, await response);
187
+ writer.end();
188
+ await parseOrThrow(EmptyResponse, await response);
173
189
  }
174
190
 
175
191
  async readFile(params: {
@@ -192,6 +208,23 @@ export class APIClient extends BaseClient {
192
208
  return response.body;
193
209
  }
194
210
 
211
+ async killCommand(params: {
212
+ sandboxId: string;
213
+ commandId: string;
214
+ signal: number;
215
+ }) {
216
+ return parseOrThrow(
217
+ CommandResponse,
218
+ await this.request(
219
+ `/v1/sandboxes/${params.sandboxId}/${params.commandId}/kill`,
220
+ {
221
+ method: "POST",
222
+ body: JSON.stringify({ signal: params.signal }),
223
+ },
224
+ ),
225
+ );
226
+ }
227
+
195
228
  async *getLogs(params: {
196
229
  sandboxId: string;
197
230
  cmdId: string;
@@ -226,10 +259,10 @@ export class APIClient extends BaseClient {
226
259
 
227
260
  async stopSandbox(params: {
228
261
  sandboxId: string;
229
- }): Promise<Parsed<z.infer<typeof StoppedSandbox>>> {
262
+ }): Promise<Parsed<z.infer<typeof SandboxResponse>>> {
230
263
  const url = `/v1/sandboxes/${params.sandboxId}/stop`;
231
264
  return parseOrThrow(
232
- StoppedSandbox,
265
+ SandboxResponse,
233
266
  await this.request(url, { method: "POST" }),
234
267
  );
235
268
  }
@@ -1 +1,2 @@
1
1
  export { APIClient } from "./api-client";
2
+ export * from "./validators";
@@ -1,36 +1,66 @@
1
1
  import { z } from "zod";
2
2
 
3
- export const CreatedSandbox = z.object({
4
- sandboxId: z.string(),
5
- routes: z.array(z.object({ subdomain: z.string(), port: z.number() })),
3
+ export type SandboxData = z.infer<typeof Sandbox>;
4
+
5
+ export const Sandbox = z.object({
6
+ id: z.string(),
7
+ memory: z.number(),
8
+ vcpus: z.number(),
9
+ region: z.string(),
10
+ runtime: z.string(),
11
+ timeout: z.number(),
12
+ status: z.enum(["pending", "running", "stopping", "stopped", "failed"]),
13
+ requestedAt: z.number(),
14
+ startedAt: z.number().optional(),
15
+ requestedStopAt: z.number().optional(),
16
+ stoppedAt: z.number().optional(),
17
+ duration: z.number().optional(),
18
+ createdAt: z.number(),
19
+ updatedAt: z.number(),
6
20
  });
7
21
 
8
- export const CreatedCommand = z.object({
9
- cmdId: z.string(),
22
+ export type SandboxRouteData = z.infer<typeof SandboxRoute>;
23
+
24
+ export const SandboxRoute = z.object({
25
+ url: z.string(),
26
+ subdomain: z.string(),
27
+ port: z.number(),
10
28
  });
11
29
 
30
+ export type CommandData = z.infer<typeof Command>;
31
+
12
32
  export const Command = z.object({
33
+ id: z.string(),
34
+ name: z.string(),
13
35
  args: z.array(z.string()),
14
- cmdId: z.string(),
15
36
  cwd: z.string(),
37
+ sandboxId: z.string(),
16
38
  exitCode: z.number().nullable(),
17
- name: z.string(),
39
+ startedAt: z.number(),
18
40
  });
19
41
 
20
- export const CommandFinished = z.object({
21
- args: z.array(z.string()),
22
- cmdId: z.string(),
23
- cwd: z.string(),
42
+ const CommandFinished = Command.extend({
24
43
  exitCode: z.number(),
25
- name: z.string(),
26
44
  });
27
45
 
28
- export const WrittenFile = z.object({});
46
+ export const SandboxResponse = z.object({
47
+ sandbox: Sandbox,
48
+ });
29
49
 
30
- export const StoppedSandbox = z.object({
31
- sandboxId: z.string(),
50
+ export const SandboxAndRoutesResponse = SandboxResponse.extend({
51
+ routes: z.array(SandboxRoute),
52
+ });
53
+
54
+ export const CommandResponse = z.object({
55
+ command: Command,
56
+ });
57
+
58
+ export const CommandFinishedResponse = z.object({
59
+ command: CommandFinished,
32
60
  });
33
61
 
62
+ export const EmptyResponse = z.object({});
63
+
34
64
  export const LogLine = z.object({
35
65
  stream: z.enum(["stdout", "stderr"]),
36
66
  data: z.string(),
@@ -1,17 +1,25 @@
1
- import { it, expect, vi } from "vitest";
1
+ import { expect, it, vi, beforeEach, afterEach } from "vitest";
2
2
  import { Sandbox } from "./sandbox";
3
3
 
4
- it("warns when there is more than one logs consumer", async () => {
5
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
6
- const stdoutSpy = vi
7
- .spyOn(process.stdout, "write")
8
- .mockImplementation(() => true);
4
+ let sandbox: Sandbox;
9
5
 
10
- const sandbox = await Sandbox.create({
6
+ beforeEach(async () => {
7
+ sandbox = await Sandbox.create({
11
8
  projectId: process.env.VERCEL_PROJECT_ID!,
12
9
  teamId: process.env.VERCEL_TEAM_ID!,
13
10
  token: process.env.VERCEL_TOKEN!,
14
11
  });
12
+ });
13
+
14
+ afterEach(async () => {
15
+ await sandbox.stop();
16
+ });
17
+
18
+ it("warns when there is more than one logs consumer", async () => {
19
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
20
+ const stdoutSpy = vi
21
+ .spyOn(process.stdout, "write")
22
+ .mockImplementation(() => true);
15
23
 
16
24
  const cmd = await sandbox.runCommand({
17
25
  cmd: "echo",
@@ -26,19 +34,11 @@ it("warns when there is more than one logs consumer", async () => {
26
34
  /Multiple consumers for logs of command `[^`]+`\.\sThis may lead to unexpected behavior\./,
27
35
  ),
28
36
  );
29
-
30
- await sandbox.stop();
31
37
  });
32
38
 
33
39
  it("does not warn when there is only one logs consumer", async () => {
34
40
  const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
35
41
 
36
- const sandbox = await Sandbox.create({
37
- projectId: process.env.VERCEL_PROJECT_ID!,
38
- teamId: process.env.VERCEL_TEAM_ID!,
39
- token: process.env.VERCEL_TOKEN!,
40
- });
41
-
42
42
  const cmd = await sandbox.runCommand({
43
43
  cmd: "echo",
44
44
  args: ["Hello World!"],
@@ -46,6 +46,29 @@ it("does not warn when there is only one logs consumer", async () => {
46
46
 
47
47
  expect(await cmd.stdout()).toEqual("Hello World!\n");
48
48
  expect(warnSpy).not.toHaveBeenCalled();
49
+ });
49
50
 
50
- await sandbox.stop();
51
+ it("Kills a command with a SIGINT", async () => {
52
+ const cmd = await sandbox.runCommand({
53
+ cmd: "sleep",
54
+ args: ["200000"],
55
+ detached: true,
56
+ });
57
+
58
+ await cmd.kill("SIGINT");
59
+ const result = await cmd.wait();
60
+ expect(result.exitCode).toBe(130); // 128 + 2
61
+ });
62
+
63
+ it("Kills a command with a SIGTERM", async () => {
64
+ const cmd = await sandbox.runCommand({
65
+ cmd: "sleep",
66
+ args: ["200000"],
67
+ detached: true,
68
+ });
69
+
70
+ await cmd.kill("SIGTERM");
71
+
72
+ const result = await cmd.wait();
73
+ expect(result.exitCode).toBe(143); // 128 + 15
51
74
  });