@cloudflare/sandbox 0.0.0-bb855ca → 0.0.0-c1f057e

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 (95) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/Dockerfile +107 -66
  3. package/README.md +88 -710
  4. package/dist/chunk-BFVUNTP4.js +104 -0
  5. package/dist/chunk-BFVUNTP4.js.map +1 -0
  6. package/dist/chunk-EKSWCBCA.js +86 -0
  7. package/dist/chunk-EKSWCBCA.js.map +1 -0
  8. package/dist/chunk-JXZMAU2C.js +559 -0
  9. package/dist/chunk-JXZMAU2C.js.map +1 -0
  10. package/dist/chunk-KWOEDJUN.js +7 -0
  11. package/dist/chunk-KWOEDJUN.js.map +1 -0
  12. package/dist/chunk-Y52QYTSM.js +2420 -0
  13. package/dist/chunk-Y52QYTSM.js.map +1 -0
  14. package/dist/chunk-Z532A7QC.js +78 -0
  15. package/dist/chunk-Z532A7QC.js.map +1 -0
  16. package/dist/file-stream.d.ts +43 -0
  17. package/dist/file-stream.js +9 -0
  18. package/dist/file-stream.js.map +1 -0
  19. package/dist/index.d.ts +9 -0
  20. package/dist/index.js +67 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/interpreter.d.ts +33 -0
  23. package/dist/interpreter.js +8 -0
  24. package/dist/interpreter.js.map +1 -0
  25. package/dist/request-handler.d.ts +18 -0
  26. package/dist/request-handler.js +13 -0
  27. package/dist/request-handler.js.map +1 -0
  28. package/dist/sandbox-DMlNr93l.d.ts +596 -0
  29. package/dist/sandbox.d.ts +4 -0
  30. package/dist/sandbox.js +13 -0
  31. package/dist/sandbox.js.map +1 -0
  32. package/dist/security.d.ts +31 -0
  33. package/dist/security.js +13 -0
  34. package/dist/security.js.map +1 -0
  35. package/dist/sse-parser.d.ts +28 -0
  36. package/dist/sse-parser.js +11 -0
  37. package/dist/sse-parser.js.map +1 -0
  38. package/dist/version.d.ts +8 -0
  39. package/dist/version.js +7 -0
  40. package/dist/version.js.map +1 -0
  41. package/package.json +13 -5
  42. package/src/clients/base-client.ts +280 -0
  43. package/src/clients/command-client.ts +115 -0
  44. package/src/clients/file-client.ts +269 -0
  45. package/src/clients/git-client.ts +92 -0
  46. package/src/clients/index.ts +64 -0
  47. package/src/clients/interpreter-client.ts +329 -0
  48. package/src/clients/port-client.ts +105 -0
  49. package/src/clients/process-client.ts +177 -0
  50. package/src/clients/sandbox-client.ts +41 -0
  51. package/src/clients/types.ts +84 -0
  52. package/src/clients/utility-client.ts +119 -0
  53. package/src/errors/adapter.ts +180 -0
  54. package/src/errors/classes.ts +469 -0
  55. package/src/errors/index.ts +105 -0
  56. package/src/file-stream.ts +164 -0
  57. package/src/index.ts +85 -21
  58. package/src/interpreter.ts +22 -13
  59. package/src/request-handler.ts +69 -43
  60. package/src/sandbox.ts +663 -444
  61. package/src/security.ts +14 -23
  62. package/src/sse-parser.ts +4 -8
  63. package/src/version.ts +6 -0
  64. package/startup.sh +3 -0
  65. package/tests/base-client.test.ts +328 -0
  66. package/tests/command-client.test.ts +407 -0
  67. package/tests/file-client.test.ts +643 -0
  68. package/tests/file-stream.test.ts +306 -0
  69. package/tests/get-sandbox.test.ts +110 -0
  70. package/tests/git-client.test.ts +328 -0
  71. package/tests/port-client.test.ts +301 -0
  72. package/tests/process-client.test.ts +658 -0
  73. package/tests/sandbox.test.ts +465 -0
  74. package/tests/sse-parser.test.ts +290 -0
  75. package/tests/utility-client.test.ts +332 -0
  76. package/tests/version.test.ts +16 -0
  77. package/tests/wrangler.jsonc +35 -0
  78. package/tsconfig.json +9 -1
  79. package/vitest.config.ts +31 -0
  80. package/container_src/bun.lock +0 -122
  81. package/container_src/handler/exec.ts +0 -340
  82. package/container_src/handler/file.ts +0 -844
  83. package/container_src/handler/git.ts +0 -182
  84. package/container_src/handler/ports.ts +0 -314
  85. package/container_src/handler/process.ts +0 -640
  86. package/container_src/index.ts +0 -531
  87. package/container_src/jupyter-server.ts +0 -336
  88. package/container_src/mime-processor.ts +0 -255
  89. package/container_src/package.json +0 -18
  90. package/container_src/startup.sh +0 -52
  91. package/container_src/types.ts +0 -108
  92. package/src/client.ts +0 -1021
  93. package/src/interpreter-types.ts +0 -383
  94. package/src/jupyter-client.ts +0 -266
  95. package/src/types.ts +0 -401
package/src/client.ts DELETED
@@ -1,1021 +0,0 @@
1
- import type { ExecuteRequest } from "../container_src/types";
2
- import type { Sandbox } from "./index";
3
- import type {
4
- BaseExecOptions,
5
- GetProcessLogsResponse,
6
- GetProcessResponse,
7
- ListProcessesResponse,
8
- StartProcessRequest,
9
- StartProcessResponse,
10
- } from "./types";
11
-
12
- export interface ExecuteResponse {
13
- success: boolean;
14
- stdout: string;
15
- stderr: string;
16
- exitCode: number;
17
- command: string;
18
- timestamp: string;
19
- }
20
-
21
- interface CommandsResponse {
22
- availableCommands: string[];
23
- timestamp: string;
24
- }
25
-
26
- interface GitCheckoutRequest {
27
- repoUrl: string;
28
- branch?: string;
29
- targetDir?: string;
30
- sessionId?: string;
31
- }
32
-
33
- export interface GitCheckoutResponse {
34
- success: boolean;
35
- stdout: string;
36
- stderr: string;
37
- exitCode: number;
38
- repoUrl: string;
39
- branch: string;
40
- targetDir: string;
41
- timestamp: string;
42
- }
43
-
44
- interface MkdirRequest {
45
- path: string;
46
- recursive?: boolean;
47
- sessionId?: string;
48
- }
49
-
50
- export interface MkdirResponse {
51
- success: boolean;
52
- stdout: string;
53
- stderr: string;
54
- exitCode: number;
55
- path: string;
56
- recursive: boolean;
57
- timestamp: string;
58
- }
59
-
60
- interface WriteFileRequest {
61
- path: string;
62
- content: string;
63
- encoding?: string;
64
- sessionId?: string;
65
- }
66
-
67
- export interface WriteFileResponse {
68
- success: boolean;
69
- exitCode: number;
70
- path: string;
71
- timestamp: string;
72
- }
73
-
74
- interface ReadFileRequest {
75
- path: string;
76
- encoding?: string;
77
- sessionId?: string;
78
- }
79
-
80
- export interface ReadFileResponse {
81
- success: boolean;
82
- exitCode: number;
83
- path: string;
84
- content: string;
85
- timestamp: string;
86
- }
87
-
88
- interface DeleteFileRequest {
89
- path: string;
90
- sessionId?: string;
91
- }
92
-
93
- export interface DeleteFileResponse {
94
- success: boolean;
95
- exitCode: number;
96
- path: string;
97
- timestamp: string;
98
- }
99
-
100
- interface RenameFileRequest {
101
- oldPath: string;
102
- newPath: string;
103
- sessionId?: string;
104
- }
105
-
106
- export interface RenameFileResponse {
107
- success: boolean;
108
- exitCode: number;
109
- oldPath: string;
110
- newPath: string;
111
- timestamp: string;
112
- }
113
-
114
- interface MoveFileRequest {
115
- sourcePath: string;
116
- destinationPath: string;
117
- sessionId?: string;
118
- }
119
-
120
- export interface MoveFileResponse {
121
- success: boolean;
122
- exitCode: number;
123
- sourcePath: string;
124
- destinationPath: string;
125
- timestamp: string;
126
- }
127
-
128
- interface PreviewInfo {
129
- url: string;
130
- port: number;
131
- name?: string;
132
- }
133
-
134
- interface ExposedPort extends PreviewInfo {
135
- exposedAt: string;
136
- timestamp: string;
137
- }
138
-
139
- interface ExposePortResponse {
140
- success: boolean;
141
- port: number;
142
- name?: string;
143
- exposedAt: string;
144
- timestamp: string;
145
- }
146
-
147
- interface UnexposePortResponse {
148
- success: boolean;
149
- port: number;
150
- timestamp: string;
151
- }
152
-
153
- interface GetExposedPortsResponse {
154
- ports: ExposedPort[];
155
- count: number;
156
- timestamp: string;
157
- }
158
-
159
- interface PingResponse {
160
- message: string;
161
- timestamp: string;
162
- }
163
-
164
- interface HttpClientOptions {
165
- stub?: Sandbox;
166
- baseUrl?: string;
167
- port?: number;
168
- onCommandStart?: (command: string) => void;
169
- onOutput?: (
170
- stream: "stdout" | "stderr",
171
- data: string,
172
- command: string
173
- ) => void;
174
- onCommandComplete?: (
175
- success: boolean,
176
- exitCode: number,
177
- stdout: string,
178
- stderr: string,
179
- command: string
180
- ) => void;
181
- onError?: (error: string, command?: string) => void;
182
- }
183
-
184
- export class HttpClient {
185
- private baseUrl: string;
186
- private options: HttpClientOptions;
187
- private sessionId: string | null = null;
188
-
189
- constructor(options: HttpClientOptions = {}) {
190
- this.options = {
191
- ...options,
192
- };
193
- this.baseUrl = this.options.baseUrl!;
194
- }
195
-
196
- protected async doFetch(
197
- path: string,
198
- options?: RequestInit
199
- ): Promise<Response> {
200
- const url = this.options.stub
201
- ? `http://localhost:${this.options.port}${path}`
202
- : `${this.baseUrl}${path}`;
203
- const method = options?.method || "GET";
204
-
205
- console.log(`[HTTP Client] Making ${method} request to ${url}`);
206
-
207
- try {
208
- let response: Response;
209
-
210
- if (this.options.stub) {
211
- response = await this.options.stub.containerFetch(
212
- url,
213
- options,
214
- this.options.port
215
- );
216
- } else {
217
- response = await fetch(url, options);
218
- }
219
-
220
- console.log(
221
- `[HTTP Client] Response: ${response.status} ${response.statusText}`
222
- );
223
-
224
- if (!response.ok) {
225
- console.error(
226
- `[HTTP Client] Request failed: ${method} ${url} - ${response.status} ${response.statusText}`
227
- );
228
- }
229
-
230
- return response;
231
- } catch (error) {
232
- console.error(`[HTTP Client] Request error: ${method} ${url}`, error);
233
- throw error;
234
- }
235
- }
236
-
237
- async execute(
238
- command: string,
239
- options: Pick<BaseExecOptions, "sessionId" | "cwd" | "env">
240
- ): Promise<ExecuteResponse> {
241
- try {
242
- const targetSessionId = options.sessionId || this.sessionId;
243
- const executeRequest = {
244
- command,
245
- sessionId: targetSessionId,
246
- cwd: options.cwd,
247
- env: options.env,
248
- } satisfies ExecuteRequest;
249
-
250
- const response = await this.doFetch(`/api/execute`, {
251
- body: JSON.stringify(executeRequest),
252
- headers: {
253
- "Content-Type": "application/json",
254
- },
255
- method: "POST",
256
- });
257
-
258
- if (!response.ok) {
259
- const errorData = (await response.json().catch(() => ({}))) as {
260
- error?: string;
261
- };
262
- throw new Error(
263
- errorData.error || `HTTP error! status: ${response.status}`
264
- );
265
- }
266
-
267
- const data: ExecuteResponse = await response.json();
268
- console.log(
269
- `[HTTP Client] Command executed: ${command}, Success: ${data.success}`
270
- );
271
-
272
- // Call the callback if provided
273
- this.options.onCommandComplete?.(
274
- data.success,
275
- data.exitCode,
276
- data.stdout,
277
- data.stderr,
278
- data.command
279
- );
280
-
281
- return data;
282
- } catch (error) {
283
- console.error("[HTTP Client] Error executing command:", error);
284
- this.options.onError?.(
285
- error instanceof Error ? error.message : "Unknown error",
286
- command
287
- );
288
- throw error;
289
- }
290
- }
291
-
292
- async executeCommandStream(
293
- command: string,
294
- sessionId?: string
295
- ): Promise<ReadableStream<Uint8Array>> {
296
- try {
297
- const targetSessionId = sessionId || this.sessionId;
298
-
299
- const response = await this.doFetch(`/api/execute/stream`, {
300
- body: JSON.stringify({
301
- command,
302
- sessionId: targetSessionId,
303
- }),
304
- headers: {
305
- "Content-Type": "application/json",
306
- Accept: "text/event-stream",
307
- },
308
- method: "POST",
309
- });
310
-
311
- if (!response.ok) {
312
- const errorData = (await response.json().catch(() => ({}))) as {
313
- error?: string;
314
- };
315
- throw new Error(
316
- errorData.error || `HTTP error! status: ${response.status}`
317
- );
318
- }
319
-
320
- if (!response.body) {
321
- throw new Error("No response body for streaming request");
322
- }
323
-
324
- console.log(`[HTTP Client] Started command stream: ${command}`);
325
-
326
- return response.body;
327
- } catch (error) {
328
- console.error("[HTTP Client] Error in command stream:", error);
329
- throw error;
330
- }
331
- }
332
-
333
- async gitCheckout(
334
- repoUrl: string,
335
- branch: string = "main",
336
- targetDir?: string,
337
- sessionId?: string
338
- ): Promise<GitCheckoutResponse> {
339
- try {
340
- const targetSessionId = sessionId || this.sessionId;
341
-
342
- const response = await this.doFetch(`/api/git/checkout`, {
343
- body: JSON.stringify({
344
- branch,
345
- repoUrl,
346
- sessionId: targetSessionId,
347
- targetDir,
348
- } as GitCheckoutRequest),
349
- headers: {
350
- "Content-Type": "application/json",
351
- },
352
- method: "POST",
353
- });
354
-
355
- if (!response.ok) {
356
- const errorData = (await response.json().catch(() => ({}))) as {
357
- error?: string;
358
- };
359
- throw new Error(
360
- errorData.error || `HTTP error! status: ${response.status}`
361
- );
362
- }
363
-
364
- const data: GitCheckoutResponse = await response.json();
365
- console.log(
366
- `[HTTP Client] Git checkout completed: ${repoUrl}, Success: ${data.success}, Target: ${data.targetDir}`
367
- );
368
-
369
- return data;
370
- } catch (error) {
371
- console.error("[HTTP Client] Error in git checkout:", error);
372
- throw error;
373
- }
374
- }
375
-
376
- async mkdir(
377
- path: string,
378
- recursive: boolean = false,
379
- sessionId?: string
380
- ): Promise<MkdirResponse> {
381
- try {
382
- const targetSessionId = sessionId || this.sessionId;
383
-
384
- const response = await this.doFetch(`/api/mkdir`, {
385
- body: JSON.stringify({
386
- path,
387
- recursive,
388
- sessionId: targetSessionId,
389
- } as MkdirRequest),
390
- headers: {
391
- "Content-Type": "application/json",
392
- },
393
- method: "POST",
394
- });
395
-
396
- if (!response.ok) {
397
- const errorData = (await response.json().catch(() => ({}))) as {
398
- error?: string;
399
- };
400
- throw new Error(
401
- errorData.error || `HTTP error! status: ${response.status}`
402
- );
403
- }
404
-
405
- const data: MkdirResponse = await response.json();
406
- console.log(
407
- `[HTTP Client] Directory created: ${path}, Success: ${data.success}, Recursive: ${data.recursive}`
408
- );
409
-
410
- return data;
411
- } catch (error) {
412
- console.error("[HTTP Client] Error creating directory:", error);
413
- throw error;
414
- }
415
- }
416
-
417
- async writeFile(
418
- path: string,
419
- content: string,
420
- encoding: string = "utf-8",
421
- sessionId?: string
422
- ): Promise<WriteFileResponse> {
423
- try {
424
- const targetSessionId = sessionId || this.sessionId;
425
-
426
- const response = await this.doFetch(`/api/write`, {
427
- body: JSON.stringify({
428
- content,
429
- encoding,
430
- path,
431
- sessionId: targetSessionId,
432
- } as WriteFileRequest),
433
- headers: {
434
- "Content-Type": "application/json",
435
- },
436
- method: "POST",
437
- });
438
-
439
- if (!response.ok) {
440
- const errorData = (await response.json().catch(() => ({}))) as {
441
- error?: string;
442
- };
443
- throw new Error(
444
- errorData.error || `HTTP error! status: ${response.status}`
445
- );
446
- }
447
-
448
- const data: WriteFileResponse = await response.json();
449
- console.log(
450
- `[HTTP Client] File written: ${path}, Success: ${data.success}`
451
- );
452
-
453
- return data;
454
- } catch (error) {
455
- console.error("[HTTP Client] Error writing file:", error);
456
- throw error;
457
- }
458
- }
459
-
460
- async readFile(
461
- path: string,
462
- encoding: string = "utf-8",
463
- sessionId?: string
464
- ): Promise<ReadFileResponse> {
465
- try {
466
- const targetSessionId = sessionId || this.sessionId;
467
-
468
- const response = await this.doFetch(`/api/read`, {
469
- body: JSON.stringify({
470
- encoding,
471
- path,
472
- sessionId: targetSessionId,
473
- } as ReadFileRequest),
474
- headers: {
475
- "Content-Type": "application/json",
476
- },
477
- method: "POST",
478
- });
479
-
480
- if (!response.ok) {
481
- const errorData = (await response.json().catch(() => ({}))) as {
482
- error?: string;
483
- };
484
- throw new Error(
485
- errorData.error || `HTTP error! status: ${response.status}`
486
- );
487
- }
488
-
489
- const data: ReadFileResponse = await response.json();
490
- console.log(
491
- `[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}`
492
- );
493
-
494
- return data;
495
- } catch (error) {
496
- console.error("[HTTP Client] Error reading file:", error);
497
- throw error;
498
- }
499
- }
500
-
501
- async deleteFile(
502
- path: string,
503
- sessionId?: string
504
- ): Promise<DeleteFileResponse> {
505
- try {
506
- const targetSessionId = sessionId || this.sessionId;
507
-
508
- const response = await this.doFetch(`/api/delete`, {
509
- body: JSON.stringify({
510
- path,
511
- sessionId: targetSessionId,
512
- } as DeleteFileRequest),
513
- headers: {
514
- "Content-Type": "application/json",
515
- },
516
- method: "POST",
517
- });
518
-
519
- if (!response.ok) {
520
- const errorData = (await response.json().catch(() => ({}))) as {
521
- error?: string;
522
- };
523
- throw new Error(
524
- errorData.error || `HTTP error! status: ${response.status}`
525
- );
526
- }
527
-
528
- const data: DeleteFileResponse = await response.json();
529
- console.log(
530
- `[HTTP Client] File deleted: ${path}, Success: ${data.success}`
531
- );
532
-
533
- return data;
534
- } catch (error) {
535
- console.error("[HTTP Client] Error deleting file:", error);
536
- throw error;
537
- }
538
- }
539
-
540
- async renameFile(
541
- oldPath: string,
542
- newPath: string,
543
- sessionId?: string
544
- ): Promise<RenameFileResponse> {
545
- try {
546
- const targetSessionId = sessionId || this.sessionId;
547
-
548
- const response = await this.doFetch(`/api/rename`, {
549
- body: JSON.stringify({
550
- newPath,
551
- oldPath,
552
- sessionId: targetSessionId,
553
- } as RenameFileRequest),
554
- headers: {
555
- "Content-Type": "application/json",
556
- },
557
- method: "POST",
558
- });
559
-
560
- if (!response.ok) {
561
- const errorData = (await response.json().catch(() => ({}))) as {
562
- error?: string;
563
- };
564
- throw new Error(
565
- errorData.error || `HTTP error! status: ${response.status}`
566
- );
567
- }
568
-
569
- const data: RenameFileResponse = await response.json();
570
- console.log(
571
- `[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}`
572
- );
573
-
574
- return data;
575
- } catch (error) {
576
- console.error("[HTTP Client] Error renaming file:", error);
577
- throw error;
578
- }
579
- }
580
-
581
- async moveFile(
582
- sourcePath: string,
583
- destinationPath: string,
584
- sessionId?: string
585
- ): Promise<MoveFileResponse> {
586
- try {
587
- const targetSessionId = sessionId || this.sessionId;
588
-
589
- const response = await this.doFetch(`/api/move`, {
590
- body: JSON.stringify({
591
- destinationPath,
592
- sessionId: targetSessionId,
593
- sourcePath,
594
- } as MoveFileRequest),
595
- headers: {
596
- "Content-Type": "application/json",
597
- },
598
- method: "POST",
599
- });
600
-
601
- if (!response.ok) {
602
- const errorData = (await response.json().catch(() => ({}))) as {
603
- error?: string;
604
- };
605
- throw new Error(
606
- errorData.error || `HTTP error! status: ${response.status}`
607
- );
608
- }
609
-
610
- const data: MoveFileResponse = await response.json();
611
- console.log(
612
- `[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}`
613
- );
614
-
615
- return data;
616
- } catch (error) {
617
- console.error("[HTTP Client] Error moving file:", error);
618
- throw error;
619
- }
620
- }
621
-
622
- async exposePort(port: number, name?: string): Promise<ExposePortResponse> {
623
- try {
624
- const response = await this.doFetch(`/api/expose-port`, {
625
- body: JSON.stringify({
626
- port,
627
- name,
628
- }),
629
- headers: {
630
- "Content-Type": "application/json",
631
- },
632
- method: "POST",
633
- });
634
-
635
- if (!response.ok) {
636
- const errorData = (await response.json().catch(() => ({}))) as {
637
- error?: string;
638
- };
639
- console.log(errorData);
640
- throw new Error(
641
- errorData.error || `HTTP error! status: ${response.status}`
642
- );
643
- }
644
-
645
- const data: ExposePortResponse = await response.json();
646
- console.log(
647
- `[HTTP Client] Port exposed: ${port}${
648
- name ? ` (${name})` : ""
649
- }, Success: ${data.success}`
650
- );
651
-
652
- return data;
653
- } catch (error) {
654
- console.error("[HTTP Client] Error exposing port:", error);
655
- throw error;
656
- }
657
- }
658
-
659
- async unexposePort(port: number): Promise<UnexposePortResponse> {
660
- try {
661
- const response = await this.doFetch(`/api/unexpose-port`, {
662
- body: JSON.stringify({
663
- port,
664
- }),
665
- headers: {
666
- "Content-Type": "application/json",
667
- },
668
- method: "DELETE",
669
- });
670
-
671
- if (!response.ok) {
672
- const errorData = (await response.json().catch(() => ({}))) as {
673
- error?: string;
674
- };
675
- throw new Error(
676
- errorData.error || `HTTP error! status: ${response.status}`
677
- );
678
- }
679
-
680
- const data: UnexposePortResponse = await response.json();
681
- console.log(
682
- `[HTTP Client] Port unexposed: ${port}, Success: ${data.success}`
683
- );
684
-
685
- return data;
686
- } catch (error) {
687
- console.error("[HTTP Client] Error unexposing port:", error);
688
- throw error;
689
- }
690
- }
691
-
692
- async getExposedPorts(): Promise<GetExposedPortsResponse> {
693
- try {
694
- const response = await this.doFetch(`/api/exposed-ports`, {
695
- headers: {
696
- "Content-Type": "application/json",
697
- },
698
- method: "GET",
699
- });
700
-
701
- if (!response.ok) {
702
- const errorData = (await response.json().catch(() => ({}))) as {
703
- error?: string;
704
- };
705
- throw new Error(
706
- errorData.error || `HTTP error! status: ${response.status}`
707
- );
708
- }
709
-
710
- const data: GetExposedPortsResponse = await response.json();
711
- console.log(`[HTTP Client] Got ${data.count} exposed ports`);
712
-
713
- return data;
714
- } catch (error) {
715
- console.error("[HTTP Client] Error getting exposed ports:", error);
716
- throw error;
717
- }
718
- }
719
-
720
- async ping(): Promise<string> {
721
- try {
722
- const response = await this.doFetch(`/api/ping`, {
723
- headers: {
724
- "Content-Type": "application/json",
725
- },
726
- method: "GET",
727
- });
728
-
729
- if (!response.ok) {
730
- throw new Error(`HTTP error! status: ${response.status}`);
731
- }
732
-
733
- const data: PingResponse = await response.json();
734
- console.log(`[HTTP Client] Ping response: ${data.message}`);
735
- return data.timestamp;
736
- } catch (error) {
737
- console.error("[HTTP Client] Error pinging server:", error);
738
- throw error;
739
- }
740
- }
741
-
742
- async getCommands(): Promise<string[]> {
743
- try {
744
- const response = await fetch(`${this.baseUrl}/api/commands`, {
745
- headers: {
746
- "Content-Type": "application/json",
747
- },
748
- method: "GET",
749
- });
750
-
751
- if (!response.ok) {
752
- throw new Error(`HTTP error! status: ${response.status}`);
753
- }
754
-
755
- const data: CommandsResponse = await response.json();
756
- console.log(
757
- `[HTTP Client] Available commands: ${data.availableCommands.length}`
758
- );
759
- return data.availableCommands;
760
- } catch (error) {
761
- console.error("[HTTP Client] Error getting commands:", error);
762
- throw error;
763
- }
764
- }
765
-
766
- getSessionId(): string | null {
767
- return this.sessionId;
768
- }
769
-
770
- setSessionId(sessionId: string): void {
771
- this.sessionId = sessionId;
772
- }
773
-
774
- clearSession(): void {
775
- this.sessionId = null;
776
- }
777
-
778
- // Process management methods
779
- async startProcess(
780
- command: string,
781
- options?: {
782
- processId?: string;
783
- sessionId?: string;
784
- timeout?: number;
785
- env?: Record<string, string>;
786
- cwd?: string;
787
- encoding?: string;
788
- autoCleanup?: boolean;
789
- }
790
- ): Promise<StartProcessResponse> {
791
- try {
792
- const targetSessionId = options?.sessionId || this.sessionId;
793
-
794
- const response = await this.doFetch("/api/process/start", {
795
- body: JSON.stringify({
796
- command,
797
- options: {
798
- ...options,
799
- sessionId: targetSessionId,
800
- },
801
- } as StartProcessRequest),
802
- headers: {
803
- "Content-Type": "application/json",
804
- },
805
- method: "POST",
806
- });
807
-
808
- if (!response.ok) {
809
- const errorData = (await response.json().catch(() => ({}))) as {
810
- error?: string;
811
- };
812
- throw new Error(
813
- errorData.error || `HTTP error! status: ${response.status}`
814
- );
815
- }
816
-
817
- const data: StartProcessResponse = await response.json();
818
- console.log(
819
- `[HTTP Client] Process started: ${command}, ID: ${data.process.id}`
820
- );
821
-
822
- return data;
823
- } catch (error) {
824
- console.error("[HTTP Client] Error starting process:", error);
825
- throw error;
826
- }
827
- }
828
-
829
- async listProcesses(): Promise<ListProcessesResponse> {
830
- try {
831
- const response = await this.doFetch("/api/process/list", {
832
- headers: {
833
- "Content-Type": "application/json",
834
- },
835
- method: "GET",
836
- });
837
-
838
- if (!response.ok) {
839
- const errorData = (await response.json().catch(() => ({}))) as {
840
- error?: string;
841
- };
842
- throw new Error(
843
- errorData.error || `HTTP error! status: ${response.status}`
844
- );
845
- }
846
-
847
- const data: ListProcessesResponse = await response.json();
848
- console.log(`[HTTP Client] Listed ${data.processes.length} processes`);
849
-
850
- return data;
851
- } catch (error) {
852
- console.error("[HTTP Client] Error listing processes:", error);
853
- throw error;
854
- }
855
- }
856
-
857
- async getProcess(processId: string): Promise<GetProcessResponse> {
858
- try {
859
- const response = await this.doFetch(`/api/process/${processId}`, {
860
- headers: {
861
- "Content-Type": "application/json",
862
- },
863
- method: "GET",
864
- });
865
-
866
- if (!response.ok) {
867
- const errorData = (await response.json().catch(() => ({}))) as {
868
- error?: string;
869
- };
870
- throw new Error(
871
- errorData.error || `HTTP error! status: ${response.status}`
872
- );
873
- }
874
-
875
- const data: GetProcessResponse = await response.json();
876
- console.log(
877
- `[HTTP Client] Got process ${processId}: ${
878
- data.process?.status || "not found"
879
- }`
880
- );
881
-
882
- return data;
883
- } catch (error) {
884
- console.error("[HTTP Client] Error getting process:", error);
885
- throw error;
886
- }
887
- }
888
-
889
- async killProcess(
890
- processId: string
891
- ): Promise<{ success: boolean; message: string }> {
892
- try {
893
- const response = await this.doFetch(`/api/process/${processId}`, {
894
- headers: {
895
- "Content-Type": "application/json",
896
- },
897
- method: "DELETE",
898
- });
899
-
900
- if (!response.ok) {
901
- const errorData = (await response.json().catch(() => ({}))) as {
902
- error?: string;
903
- };
904
- throw new Error(
905
- errorData.error || `HTTP error! status: ${response.status}`
906
- );
907
- }
908
-
909
- const data = (await response.json()) as {
910
- success: boolean;
911
- message: string;
912
- };
913
- console.log(`[HTTP Client] Killed process ${processId}`);
914
-
915
- return data;
916
- } catch (error) {
917
- console.error("[HTTP Client] Error killing process:", error);
918
- throw error;
919
- }
920
- }
921
-
922
- async killAllProcesses(): Promise<{
923
- success: boolean;
924
- killedCount: number;
925
- message: string;
926
- }> {
927
- try {
928
- const response = await this.doFetch("/api/process/kill-all", {
929
- headers: {
930
- "Content-Type": "application/json",
931
- },
932
- method: "DELETE",
933
- });
934
-
935
- if (!response.ok) {
936
- const errorData = (await response.json().catch(() => ({}))) as {
937
- error?: string;
938
- };
939
- throw new Error(
940
- errorData.error || `HTTP error! status: ${response.status}`
941
- );
942
- }
943
-
944
- const data = (await response.json()) as {
945
- success: boolean;
946
- killedCount: number;
947
- message: string;
948
- };
949
- console.log(`[HTTP Client] Killed ${data.killedCount} processes`);
950
-
951
- return data;
952
- } catch (error) {
953
- console.error("[HTTP Client] Error killing all processes:", error);
954
- throw error;
955
- }
956
- }
957
-
958
- async getProcessLogs(processId: string): Promise<GetProcessLogsResponse> {
959
- try {
960
- const response = await this.doFetch(`/api/process/${processId}/logs`, {
961
- headers: {
962
- "Content-Type": "application/json",
963
- },
964
- method: "GET",
965
- });
966
-
967
- if (!response.ok) {
968
- const errorData = (await response.json().catch(() => ({}))) as {
969
- error?: string;
970
- };
971
- throw new Error(
972
- errorData.error || `HTTP error! status: ${response.status}`
973
- );
974
- }
975
-
976
- const data: GetProcessLogsResponse = await response.json();
977
- console.log(`[HTTP Client] Got logs for process ${processId}`);
978
-
979
- return data;
980
- } catch (error) {
981
- console.error("[HTTP Client] Error getting process logs:", error);
982
- throw error;
983
- }
984
- }
985
-
986
- async streamProcessLogs(
987
- processId: string
988
- ): Promise<ReadableStream<Uint8Array>> {
989
- try {
990
- const response = await this.doFetch(`/api/process/${processId}/stream`, {
991
- headers: {
992
- Accept: "text/event-stream",
993
- "Cache-Control": "no-cache",
994
- },
995
- method: "GET",
996
- });
997
-
998
- if (!response.ok) {
999
- const errorData = (await response.json().catch(() => ({}))) as {
1000
- error?: string;
1001
- };
1002
- throw new Error(
1003
- errorData.error || `HTTP error! status: ${response.status}`
1004
- );
1005
- }
1006
-
1007
- if (!response.body) {
1008
- throw new Error("No response body for streaming request");
1009
- }
1010
-
1011
- console.log(
1012
- `[HTTP Client] Started streaming logs for process ${processId}`
1013
- );
1014
-
1015
- return response.body;
1016
- } catch (error) {
1017
- console.error("[HTTP Client] Error streaming process logs:", error);
1018
- throw error;
1019
- }
1020
- }
1021
- }