@cloudflare/sandbox 0.4.11 → 0.4.14

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 (79) hide show
  1. package/.turbo/turbo-build.log +13 -47
  2. package/CHANGELOG.md +44 -16
  3. package/Dockerfile +15 -9
  4. package/README.md +0 -1
  5. package/dist/index.d.ts +1889 -9
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +3144 -65
  8. package/dist/index.js.map +1 -1
  9. package/package.json +5 -5
  10. package/src/clients/base-client.ts +39 -24
  11. package/src/clients/command-client.ts +8 -8
  12. package/src/clients/file-client.ts +31 -26
  13. package/src/clients/git-client.ts +3 -4
  14. package/src/clients/index.ts +12 -16
  15. package/src/clients/interpreter-client.ts +51 -47
  16. package/src/clients/port-client.ts +10 -10
  17. package/src/clients/process-client.ts +11 -8
  18. package/src/clients/sandbox-client.ts +2 -4
  19. package/src/clients/types.ts +6 -2
  20. package/src/clients/utility-client.ts +10 -6
  21. package/src/errors/adapter.ts +90 -32
  22. package/src/errors/classes.ts +189 -64
  23. package/src/errors/index.ts +9 -5
  24. package/src/file-stream.ts +11 -6
  25. package/src/index.ts +22 -15
  26. package/src/interpreter.ts +50 -41
  27. package/src/request-handler.ts +24 -21
  28. package/src/sandbox.ts +370 -148
  29. package/src/security.ts +21 -6
  30. package/src/sse-parser.ts +4 -3
  31. package/src/version.ts +1 -1
  32. package/tests/base-client.test.ts +116 -80
  33. package/tests/command-client.test.ts +149 -112
  34. package/tests/file-client.test.ts +309 -197
  35. package/tests/file-stream.test.ts +24 -20
  36. package/tests/get-sandbox.test.ts +45 -6
  37. package/tests/git-client.test.ts +188 -101
  38. package/tests/port-client.test.ts +100 -108
  39. package/tests/process-client.test.ts +204 -179
  40. package/tests/request-handler.test.ts +117 -65
  41. package/tests/sandbox.test.ts +220 -68
  42. package/tests/sse-parser.test.ts +17 -16
  43. package/tests/utility-client.test.ts +79 -72
  44. package/tsdown.config.ts +12 -0
  45. package/vitest.config.ts +6 -6
  46. package/dist/chunk-BFVUNTP4.js +0 -104
  47. package/dist/chunk-BFVUNTP4.js.map +0 -1
  48. package/dist/chunk-EKSWCBCA.js +0 -86
  49. package/dist/chunk-EKSWCBCA.js.map +0 -1
  50. package/dist/chunk-FE4PJSRB.js +0 -7
  51. package/dist/chunk-FE4PJSRB.js.map +0 -1
  52. package/dist/chunk-JXZMAU2C.js +0 -559
  53. package/dist/chunk-JXZMAU2C.js.map +0 -1
  54. package/dist/chunk-SVWLTRHD.js +0 -2456
  55. package/dist/chunk-SVWLTRHD.js.map +0 -1
  56. package/dist/chunk-Z532A7QC.js +0 -78
  57. package/dist/chunk-Z532A7QC.js.map +0 -1
  58. package/dist/file-stream.d.ts +0 -43
  59. package/dist/file-stream.js +0 -9
  60. package/dist/file-stream.js.map +0 -1
  61. package/dist/interpreter.d.ts +0 -33
  62. package/dist/interpreter.js +0 -8
  63. package/dist/interpreter.js.map +0 -1
  64. package/dist/request-handler.d.ts +0 -18
  65. package/dist/request-handler.js +0 -13
  66. package/dist/request-handler.js.map +0 -1
  67. package/dist/sandbox-DWQVgVTY.d.ts +0 -603
  68. package/dist/sandbox.d.ts +0 -4
  69. package/dist/sandbox.js +0 -13
  70. package/dist/sandbox.js.map +0 -1
  71. package/dist/security.d.ts +0 -31
  72. package/dist/security.js +0 -13
  73. package/dist/security.js.map +0 -1
  74. package/dist/sse-parser.d.ts +0 -28
  75. package/dist/sse-parser.js +0 -11
  76. package/dist/sse-parser.js.map +0 -1
  77. package/dist/version.d.ts +0 -8
  78. package/dist/version.js +0 -7
  79. package/dist/version.js.map +0 -1
@@ -21,13 +21,13 @@ describe('ProcessClient', () => {
21
21
 
22
22
  beforeEach(() => {
23
23
  vi.clearAllMocks();
24
-
24
+
25
25
  mockFetch = vi.fn();
26
26
  global.fetch = mockFetch as unknown as typeof fetch;
27
-
27
+
28
28
  client = new ProcessClient({
29
29
  baseUrl: 'http://test.com',
30
- port: 3000,
30
+ port: 3000
31
31
  });
32
32
  });
33
33
 
@@ -44,15 +44,14 @@ describe('ProcessClient', () => {
44
44
  command: 'npm run dev',
45
45
  status: 'running',
46
46
  pid: 12345,
47
- startTime: '2023-01-01T00:00:00Z',
47
+ startTime: '2023-01-01T00:00:00Z'
48
48
  },
49
- timestamp: '2023-01-01T00:00:00Z',
49
+ timestamp: '2023-01-01T00:00:00Z'
50
50
  };
51
51
 
52
- mockFetch.mockResolvedValue(new Response(
53
- JSON.stringify(mockResponse),
54
- { status: 200 }
55
- ));
52
+ mockFetch.mockResolvedValue(
53
+ new Response(JSON.stringify(mockResponse), { status: 200 })
54
+ );
56
55
 
57
56
  const result = await client.startProcess('npm run dev', 'session-123');
58
57
 
@@ -71,17 +70,18 @@ describe('ProcessClient', () => {
71
70
  command: 'python app.py',
72
71
  status: 'running',
73
72
  pid: 54321,
74
- startTime: '2023-01-01T00:00:00Z',
73
+ startTime: '2023-01-01T00:00:00Z'
75
74
  },
76
- timestamp: '2023-01-01T00:00:00Z',
75
+ timestamp: '2023-01-01T00:00:00Z'
77
76
  };
78
77
 
79
- mockFetch.mockResolvedValue(new Response(
80
- JSON.stringify(mockResponse),
81
- { status: 200 }
82
- ));
78
+ mockFetch.mockResolvedValue(
79
+ new Response(JSON.stringify(mockResponse), { status: 200 })
80
+ );
83
81
 
84
- const result = await client.startProcess('python app.py', 'session-456', { processId: 'my-api-server' });
82
+ const result = await client.startProcess('python app.py', 'session-456', {
83
+ processId: 'my-api-server'
84
+ });
85
85
 
86
86
  expect(result.success).toBe(true);
87
87
  expect(result.process.id).toBe('my-api-server');
@@ -97,21 +97,28 @@ describe('ProcessClient', () => {
97
97
  command: 'docker run postgres',
98
98
  status: 'running',
99
99
  pid: 99999,
100
- startTime: '2023-01-01T00:00:00Z',
100
+ startTime: '2023-01-01T00:00:00Z'
101
101
  },
102
- timestamp: '2023-01-01T00:00:05Z',
102
+ timestamp: '2023-01-01T00:00:05Z'
103
103
  };
104
104
 
105
- mockFetch.mockImplementation(() =>
106
- new Promise(resolve =>
107
- setTimeout(() => resolve(new Response(
108
- JSON.stringify(mockResponse),
109
- { status: 200 }
110
- )), 100)
111
- )
105
+ mockFetch.mockImplementation(
106
+ () =>
107
+ new Promise((resolve) =>
108
+ setTimeout(
109
+ () =>
110
+ resolve(
111
+ new Response(JSON.stringify(mockResponse), { status: 200 })
112
+ ),
113
+ 100
114
+ )
115
+ )
112
116
  );
113
117
 
114
- const result = await client.startProcess('docker run postgres', 'session-789');
118
+ const result = await client.startProcess(
119
+ 'docker run postgres',
120
+ 'session-789'
121
+ );
115
122
 
116
123
  expect(result.success).toBe(true);
117
124
  expect(result.process.status).toBe('running');
@@ -124,13 +131,13 @@ describe('ProcessClient', () => {
124
131
  code: 'COMMAND_NOT_FOUND'
125
132
  };
126
133
 
127
- mockFetch.mockResolvedValue(new Response(
128
- JSON.stringify(errorResponse),
129
- { status: 404 }
130
- ));
134
+ mockFetch.mockResolvedValue(
135
+ new Response(JSON.stringify(errorResponse), { status: 404 })
136
+ );
131
137
 
132
- await expect(client.startProcess('invalidcmd', 'session-err'))
133
- .rejects.toThrow(CommandNotFoundError);
138
+ await expect(
139
+ client.startProcess('invalidcmd', 'session-err')
140
+ ).rejects.toThrow(CommandNotFoundError);
134
141
  });
135
142
 
136
143
  it('should handle process startup failures', async () => {
@@ -139,13 +146,13 @@ describe('ProcessClient', () => {
139
146
  code: 'PROCESS_ERROR'
140
147
  };
141
148
 
142
- mockFetch.mockResolvedValue(new Response(
143
- JSON.stringify(errorResponse),
144
- { status: 500 }
145
- ));
149
+ mockFetch.mockResolvedValue(
150
+ new Response(JSON.stringify(errorResponse), { status: 500 })
151
+ );
146
152
 
147
- await expect(client.startProcess('sudo privileged-command', 'session-err'))
148
- .rejects.toThrow(ProcessError);
153
+ await expect(
154
+ client.startProcess('sudo privileged-command', 'session-err')
155
+ ).rejects.toThrow(ProcessError);
149
156
  });
150
157
  });
151
158
 
@@ -159,14 +166,14 @@ describe('ProcessClient', () => {
159
166
  command: 'npm run dev',
160
167
  status: 'running',
161
168
  pid: 12345,
162
- startTime: '2023-01-01T00:00:00Z',
169
+ startTime: '2023-01-01T00:00:00Z'
163
170
  },
164
171
  {
165
172
  id: 'proc-api',
166
173
  command: 'python api.py',
167
174
  status: 'running',
168
175
  pid: 12346,
169
- startTime: '2023-01-01T00:00:30Z',
176
+ startTime: '2023-01-01T00:00:30Z'
170
177
  },
171
178
  {
172
179
  id: 'proc-worker',
@@ -175,17 +182,16 @@ describe('ProcessClient', () => {
175
182
  pid: 12347,
176
183
  exitCode: 0,
177
184
  startTime: '2023-01-01T00:01:00Z',
178
- endTime: '2023-01-01T00:05:00Z',
185
+ endTime: '2023-01-01T00:05:00Z'
179
186
  }
180
187
  ],
181
188
  count: 3,
182
- timestamp: '2023-01-01T00:05:30Z',
189
+ timestamp: '2023-01-01T00:05:30Z'
183
190
  };
184
191
 
185
- mockFetch.mockResolvedValue(new Response(
186
- JSON.stringify(mockResponse),
187
- { status: 200 }
188
- ));
192
+ mockFetch.mockResolvedValue(
193
+ new Response(JSON.stringify(mockResponse), { status: 200 })
194
+ );
189
195
 
190
196
  const result = await client.listProcesses('session-list');
191
197
 
@@ -193,12 +199,16 @@ describe('ProcessClient', () => {
193
199
  expect(result.count).toBe(3);
194
200
  expect(result.processes).toHaveLength(3);
195
201
 
196
- const runningProcesses = result.processes.filter(p => p.status === 'running');
202
+ const runningProcesses = result.processes.filter(
203
+ (p) => p.status === 'running'
204
+ );
197
205
  expect(runningProcesses).toHaveLength(2);
198
206
  expect(runningProcesses[0].pid).toBeDefined();
199
207
  expect(runningProcesses[1].pid).toBeDefined();
200
208
 
201
- const completedProcess = result.processes.find(p => p.status === 'completed');
209
+ const completedProcess = result.processes.find(
210
+ (p) => p.status === 'completed'
211
+ );
202
212
  expect(completedProcess?.exitCode).toBe(0);
203
213
  expect(completedProcess?.endTime).toBeDefined();
204
214
  });
@@ -211,15 +221,14 @@ describe('ProcessClient', () => {
211
221
  command: 'python analytics.py --batch-size=1000',
212
222
  status: 'running',
213
223
  pid: 98765,
214
- startTime: '2023-01-01T00:00:00Z',
224
+ startTime: '2023-01-01T00:00:00Z'
215
225
  },
216
- timestamp: '2023-01-01T00:10:00Z',
226
+ timestamp: '2023-01-01T00:10:00Z'
217
227
  };
218
228
 
219
- mockFetch.mockResolvedValue(new Response(
220
- JSON.stringify(mockResponse),
221
- { status: 200 }
222
- ));
229
+ mockFetch.mockResolvedValue(
230
+ new Response(JSON.stringify(mockResponse), { status: 200 })
231
+ );
223
232
 
224
233
  const result = await client.getProcess('proc-analytics', 'session-get');
225
234
 
@@ -236,13 +245,13 @@ describe('ProcessClient', () => {
236
245
  code: 'PROCESS_NOT_FOUND'
237
246
  };
238
247
 
239
- mockFetch.mockResolvedValue(new Response(
240
- JSON.stringify(errorResponse),
241
- { status: 404 }
242
- ));
248
+ mockFetch.mockResolvedValue(
249
+ new Response(JSON.stringify(errorResponse), { status: 404 })
250
+ );
243
251
 
244
- await expect(client.getProcess('nonexistent-proc', 'session-err'))
245
- .rejects.toThrow(ProcessNotFoundError);
252
+ await expect(
253
+ client.getProcess('nonexistent-proc', 'session-err')
254
+ ).rejects.toThrow(ProcessNotFoundError);
246
255
  });
247
256
 
248
257
  it('should handle empty process list', async () => {
@@ -250,13 +259,12 @@ describe('ProcessClient', () => {
250
259
  success: true,
251
260
  processes: [],
252
261
  count: 0,
253
- timestamp: '2023-01-01T00:00:00Z',
262
+ timestamp: '2023-01-01T00:00:00Z'
254
263
  };
255
264
 
256
- mockFetch.mockResolvedValue(new Response(
257
- JSON.stringify(mockResponse),
258
- { status: 200 }
259
- ));
265
+ mockFetch.mockResolvedValue(
266
+ new Response(JSON.stringify(mockResponse), { status: 200 })
267
+ );
260
268
 
261
269
  const result = await client.listProcesses('session-list');
262
270
 
@@ -271,13 +279,12 @@ describe('ProcessClient', () => {
271
279
  const mockResponse: KillProcessResponse = {
272
280
  success: true,
273
281
  message: 'Process proc-web killed successfully',
274
- timestamp: '2023-01-01T00:10:00Z',
282
+ timestamp: '2023-01-01T00:10:00Z'
275
283
  };
276
284
 
277
- mockFetch.mockResolvedValue(new Response(
278
- JSON.stringify(mockResponse),
279
- { status: 200 }
280
- ));
285
+ mockFetch.mockResolvedValue(
286
+ new Response(JSON.stringify(mockResponse), { status: 200 })
287
+ );
281
288
 
282
289
  const result = await client.killProcess('proc-web', 'session-kill');
283
290
 
@@ -292,13 +299,13 @@ describe('ProcessClient', () => {
292
299
  code: 'PROCESS_NOT_FOUND'
293
300
  };
294
301
 
295
- mockFetch.mockResolvedValue(new Response(
296
- JSON.stringify(errorResponse),
297
- { status: 404 }
298
- ));
302
+ mockFetch.mockResolvedValue(
303
+ new Response(JSON.stringify(errorResponse), { status: 404 })
304
+ );
299
305
 
300
- await expect(client.killProcess('already-dead-proc', 'session-err'))
301
- .rejects.toThrow(ProcessNotFoundError);
306
+ await expect(
307
+ client.killProcess('already-dead-proc', 'session-err')
308
+ ).rejects.toThrow(ProcessNotFoundError);
302
309
  });
303
310
 
304
311
  it('should kill all processes at once', async () => {
@@ -306,13 +313,12 @@ describe('ProcessClient', () => {
306
313
  success: true,
307
314
  killedCount: 5,
308
315
  message: 'All 5 processes killed successfully',
309
- timestamp: '2023-01-01T00:15:00Z',
316
+ timestamp: '2023-01-01T00:15:00Z'
310
317
  };
311
318
 
312
- mockFetch.mockResolvedValue(new Response(
313
- JSON.stringify(mockResponse),
314
- { status: 200 }
315
- ));
319
+ mockFetch.mockResolvedValue(
320
+ new Response(JSON.stringify(mockResponse), { status: 200 })
321
+ );
316
322
 
317
323
  const result = await client.killAllProcesses('session-killall');
318
324
 
@@ -326,13 +332,12 @@ describe('ProcessClient', () => {
326
332
  success: true,
327
333
  killedCount: 0,
328
334
  message: 'No processes to kill',
329
- timestamp: '2023-01-01T00:00:00Z',
335
+ timestamp: '2023-01-01T00:00:00Z'
330
336
  };
331
337
 
332
- mockFetch.mockResolvedValue(new Response(
333
- JSON.stringify(mockResponse),
334
- { status: 200 }
335
- ));
338
+ mockFetch.mockResolvedValue(
339
+ new Response(JSON.stringify(mockResponse), { status: 200 })
340
+ );
336
341
 
337
342
  const result = await client.killAllProcesses('session-killall');
338
343
 
@@ -347,13 +352,13 @@ describe('ProcessClient', () => {
347
352
  code: 'PROCESS_ERROR'
348
353
  };
349
354
 
350
- mockFetch.mockResolvedValue(new Response(
351
- JSON.stringify(errorResponse),
352
- { status: 500 }
353
- ));
355
+ mockFetch.mockResolvedValue(
356
+ new Response(JSON.stringify(errorResponse), { status: 500 })
357
+ );
354
358
 
355
- await expect(client.killProcess('protected-proc', 'session-err'))
356
- .rejects.toThrow(ProcessError);
359
+ await expect(
360
+ client.killProcess('protected-proc', 'session-err')
361
+ ).rejects.toThrow(ProcessError);
357
362
  });
358
363
  });
359
364
 
@@ -370,13 +375,12 @@ describe('ProcessClient', () => {
370
375
  [INFO] Response: 200 OK`,
371
376
  stderr: `[WARN] Deprecated function used in auth.js:45
372
377
  [WARN] High memory usage: 85%`,
373
- timestamp: '2023-01-01T00:10:00Z',
378
+ timestamp: '2023-01-01T00:10:00Z'
374
379
  };
375
380
 
376
- mockFetch.mockResolvedValue(new Response(
377
- JSON.stringify(mockResponse),
378
- { status: 200 }
379
- ));
381
+ mockFetch.mockResolvedValue(
382
+ new Response(JSON.stringify(mockResponse), { status: 200 })
383
+ );
380
384
 
381
385
  const result = await client.getProcessLogs('proc-server', 'session-logs');
382
386
 
@@ -394,13 +398,13 @@ describe('ProcessClient', () => {
394
398
  code: 'PROCESS_NOT_FOUND'
395
399
  };
396
400
 
397
- mockFetch.mockResolvedValue(new Response(
398
- JSON.stringify(errorResponse),
399
- { status: 404 }
400
- ));
401
+ mockFetch.mockResolvedValue(
402
+ new Response(JSON.stringify(errorResponse), { status: 404 })
403
+ );
401
404
 
402
- await expect(client.getProcessLogs('missing-proc', 'session-err'))
403
- .rejects.toThrow(ProcessNotFoundError);
405
+ await expect(
406
+ client.getProcessLogs('missing-proc', 'session-err')
407
+ ).rejects.toThrow(ProcessNotFoundError);
404
408
  });
405
409
 
406
410
  it('should retrieve logs for processes with large output', async () => {
@@ -412,13 +416,12 @@ describe('ProcessClient', () => {
412
416
  processId: 'proc-batch',
413
417
  stdout: largeStdout,
414
418
  stderr: largeStderr,
415
- timestamp: '2023-01-01T00:30:00Z',
419
+ timestamp: '2023-01-01T00:30:00Z'
416
420
  };
417
421
 
418
- mockFetch.mockResolvedValue(new Response(
419
- JSON.stringify(mockResponse),
420
- { status: 200 }
421
- ));
422
+ mockFetch.mockResolvedValue(
423
+ new Response(JSON.stringify(mockResponse), { status: 200 })
424
+ );
422
425
 
423
426
  const result = await client.getProcessLogs('proc-batch', 'session-logs');
424
427
 
@@ -435,13 +438,12 @@ describe('ProcessClient', () => {
435
438
  processId: 'proc-silent',
436
439
  stdout: '',
437
440
  stderr: '',
438
- timestamp: '2023-01-01T00:05:00Z',
441
+ timestamp: '2023-01-01T00:05:00Z'
439
442
  };
440
443
 
441
- mockFetch.mockResolvedValue(new Response(
442
- JSON.stringify(mockResponse),
443
- { status: 200 }
444
- ));
444
+ mockFetch.mockResolvedValue(
445
+ new Response(JSON.stringify(mockResponse), { status: 200 })
446
+ );
445
447
 
446
448
  const result = await client.getProcessLogs('proc-silent', 'session-logs');
447
449
 
@@ -471,12 +473,17 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
471
473
  }
472
474
  });
473
475
 
474
- mockFetch.mockResolvedValue(new Response(mockStream, {
475
- status: 200,
476
- headers: { 'Content-Type': 'text/event-stream' }
477
- }));
476
+ mockFetch.mockResolvedValue(
477
+ new Response(mockStream, {
478
+ status: 200,
479
+ headers: { 'Content-Type': 'text/event-stream' }
480
+ })
481
+ );
478
482
 
479
- const stream = await client.streamProcessLogs('proc-realtime', 'session-stream');
483
+ const stream = await client.streamProcessLogs(
484
+ 'proc-realtime',
485
+ 'session-stream'
486
+ );
480
487
 
481
488
  expect(stream).toBeInstanceOf(ReadableStream);
482
489
 
@@ -506,13 +513,13 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
506
513
  code: 'PROCESS_NOT_FOUND'
507
514
  };
508
515
 
509
- mockFetch.mockResolvedValue(new Response(
510
- JSON.stringify(errorResponse),
511
- { status: 404 }
512
- ));
516
+ mockFetch.mockResolvedValue(
517
+ new Response(JSON.stringify(errorResponse), { status: 404 })
518
+ );
513
519
 
514
- await expect(client.streamProcessLogs('stream-missing', 'session-err'))
515
- .rejects.toThrow(ProcessNotFoundError);
520
+ await expect(
521
+ client.streamProcessLogs('stream-missing', 'session-err')
522
+ ).rejects.toThrow(ProcessNotFoundError);
516
523
  });
517
524
 
518
525
  it('should handle streaming setup failures', async () => {
@@ -521,23 +528,26 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
521
528
  code: 'PROCESS_ERROR'
522
529
  };
523
530
 
524
- mockFetch.mockResolvedValue(new Response(
525
- JSON.stringify(errorResponse),
526
- { status: 500 }
527
- ));
531
+ mockFetch.mockResolvedValue(
532
+ new Response(JSON.stringify(errorResponse), { status: 500 })
533
+ );
528
534
 
529
- await expect(client.streamProcessLogs('proc-no-logs', 'session-err'))
530
- .rejects.toThrow(ProcessError);
535
+ await expect(
536
+ client.streamProcessLogs('proc-no-logs', 'session-err')
537
+ ).rejects.toThrow(ProcessError);
531
538
  });
532
539
 
533
540
  it('should handle missing stream body', async () => {
534
- mockFetch.mockResolvedValue(new Response(null, {
535
- status: 200,
536
- headers: { 'Content-Type': 'text/event-stream' }
537
- }));
541
+ mockFetch.mockResolvedValue(
542
+ new Response(null, {
543
+ status: 200,
544
+ headers: { 'Content-Type': 'text/event-stream' }
545
+ })
546
+ );
538
547
 
539
- await expect(client.streamProcessLogs('proc-empty-stream', 'session-err'))
540
- .rejects.toThrow('No response body for streaming');
548
+ await expect(
549
+ client.streamProcessLogs('proc-empty-stream', 'session-err')
550
+ ).rejects.toThrow('No response body for streaming');
541
551
  });
542
552
  });
543
553
 
@@ -550,17 +560,19 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
550
560
  command: 'echo session-test',
551
561
  status: 'running',
552
562
  pid: 11111,
553
- startTime: '2023-01-01T00:00:00Z',
563
+ startTime: '2023-01-01T00:00:00Z'
554
564
  },
555
- timestamp: '2023-01-01T00:00:00Z',
565
+ timestamp: '2023-01-01T00:00:00Z'
556
566
  };
557
567
 
558
- mockFetch.mockResolvedValue(new Response(
559
- JSON.stringify(mockResponse),
560
- { status: 200 }
561
- ));
568
+ mockFetch.mockResolvedValue(
569
+ new Response(JSON.stringify(mockResponse), { status: 200 })
570
+ );
562
571
 
563
- const result = await client.startProcess('echo session-test', 'session-test');
572
+ const result = await client.startProcess(
573
+ 'echo session-test',
574
+ 'session-test'
575
+ );
564
576
 
565
577
  expect(result.success).toBe(true);
566
578
 
@@ -575,32 +587,44 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
575
587
  it('should handle multiple simultaneous process operations', async () => {
576
588
  mockFetch.mockImplementation((url: string, options: RequestInit) => {
577
589
  if (url.includes('/start')) {
578
- return Promise.resolve(new Response(JSON.stringify({
579
- success: true,
580
- process: {
581
- id: `proc-${Date.now()}`,
582
- command: JSON.parse(options.body as string).command,
583
- status: 'running',
584
- pid: Math.floor(Math.random() * 90000) + 10000,
585
- startTime: new Date().toISOString(),
586
- },
587
- timestamp: new Date().toISOString(),
588
- })));
590
+ return Promise.resolve(
591
+ new Response(
592
+ JSON.stringify({
593
+ success: true,
594
+ process: {
595
+ id: `proc-${Date.now()}`,
596
+ command: JSON.parse(options.body as string).command,
597
+ status: 'running',
598
+ pid: Math.floor(Math.random() * 90000) + 10000,
599
+ startTime: new Date().toISOString()
600
+ },
601
+ timestamp: new Date().toISOString()
602
+ })
603
+ )
604
+ );
589
605
  } else if (url.includes('/list')) {
590
- return Promise.resolve(new Response(JSON.stringify({
591
- success: true,
592
- processes: [],
593
- count: 0,
594
- timestamp: new Date().toISOString(),
595
- })));
606
+ return Promise.resolve(
607
+ new Response(
608
+ JSON.stringify({
609
+ success: true,
610
+ processes: [],
611
+ count: 0,
612
+ timestamp: new Date().toISOString()
613
+ })
614
+ )
615
+ );
596
616
  } else if (url.includes('/logs')) {
597
- return Promise.resolve(new Response(JSON.stringify({
598
- success: true,
599
- processId: url.split('/')[4],
600
- stdout: 'log output',
601
- stderr: '',
602
- timestamp: new Date().toISOString(),
603
- })));
617
+ return Promise.resolve(
618
+ new Response(
619
+ JSON.stringify({
620
+ success: true,
621
+ processId: url.split('/')[4],
622
+ stdout: 'log output',
623
+ stderr: '',
624
+ timestamp: new Date().toISOString()
625
+ })
626
+ )
627
+ );
604
628
  }
605
629
  return Promise.resolve(new Response('{}', { status: 200 }));
606
630
  });
@@ -610,11 +634,11 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
610
634
  client.startProcess('python api.py', 'session-concurrent'),
611
635
  client.listProcesses('session-concurrent'),
612
636
  client.getProcessLogs('existing-proc', 'session-concurrent'),
613
- client.startProcess('node worker.js', 'session-concurrent'),
637
+ client.startProcess('node worker.js', 'session-concurrent')
614
638
  ]);
615
639
 
616
640
  expect(operations).toHaveLength(5);
617
- operations.forEach(result => {
641
+ operations.forEach((result) => {
618
642
  expect(result.success).toBe(true);
619
643
  });
620
644
 
@@ -626,18 +650,19 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
626
650
  it('should handle network failures gracefully', async () => {
627
651
  mockFetch.mockRejectedValue(new Error('Network connection failed'));
628
652
 
629
- await expect(client.listProcesses('session-err'))
630
- .rejects.toThrow('Network connection failed');
653
+ await expect(client.listProcesses('session-err')).rejects.toThrow(
654
+ 'Network connection failed'
655
+ );
631
656
  });
632
657
 
633
658
  it('should handle malformed server responses', async () => {
634
- mockFetch.mockResolvedValue(new Response(
635
- 'invalid json {',
636
- { status: 200 }
637
- ));
659
+ mockFetch.mockResolvedValue(
660
+ new Response('invalid json {', { status: 200 })
661
+ );
638
662
 
639
- await expect(client.startProcess('test-command', 'session-err'))
640
- .rejects.toThrow(SandboxError);
663
+ await expect(
664
+ client.startProcess('test-command', 'session-err')
665
+ ).rejects.toThrow(SandboxError);
641
666
  });
642
667
  });
643
668
 
@@ -650,9 +675,9 @@ data: {"type":"stdout","data":"Server ready on port 3000\\n","timestamp":"2023-0
650
675
  it('should initialize with full options', () => {
651
676
  const fullOptionsClient = new ProcessClient({
652
677
  baseUrl: 'http://custom.com',
653
- port: 8080,
678
+ port: 8080
654
679
  });
655
680
  expect(fullOptionsClient).toBeDefined();
656
681
  });
657
682
  });
658
- });
683
+ });