@cloudflare/sandbox 0.3.7 → 0.4.2

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 (120) hide show
  1. package/.turbo/turbo-build.log +44 -0
  2. package/CHANGELOG.md +8 -10
  3. package/Dockerfile +82 -18
  4. package/README.md +89 -824
  5. package/dist/chunk-53JFOF7F.js +2352 -0
  6. package/dist/chunk-53JFOF7F.js.map +1 -0
  7. package/dist/chunk-BFVUNTP4.js +104 -0
  8. package/dist/chunk-BFVUNTP4.js.map +1 -0
  9. package/dist/{chunk-NNGBXDMY.js → chunk-EKSWCBCA.js} +3 -6
  10. package/dist/chunk-EKSWCBCA.js.map +1 -0
  11. package/dist/chunk-JXZMAU2C.js +559 -0
  12. package/dist/chunk-JXZMAU2C.js.map +1 -0
  13. package/dist/{chunk-6UAWTJ5S.js → chunk-Z532A7QC.js} +13 -20
  14. package/dist/{chunk-6UAWTJ5S.js.map → chunk-Z532A7QC.js.map} +1 -1
  15. package/dist/file-stream.d.ts +16 -38
  16. package/dist/file-stream.js +1 -2
  17. package/dist/index.d.ts +6 -5
  18. package/dist/index.js +45 -38
  19. package/dist/interpreter.d.ts +3 -3
  20. package/dist/interpreter.js +2 -2
  21. package/dist/request-handler.d.ts +4 -3
  22. package/dist/request-handler.js +4 -7
  23. package/dist/sandbox-D9K2ypln.d.ts +583 -0
  24. package/dist/sandbox.d.ts +3 -3
  25. package/dist/sandbox.js +4 -7
  26. package/dist/security.d.ts +4 -3
  27. package/dist/security.js +3 -3
  28. package/dist/sse-parser.js +1 -1
  29. package/package.json +12 -4
  30. package/src/clients/base-client.ts +280 -0
  31. package/src/clients/command-client.ts +115 -0
  32. package/src/clients/file-client.ts +269 -0
  33. package/src/clients/git-client.ts +92 -0
  34. package/src/clients/index.ts +63 -0
  35. package/src/{interpreter-client.ts → clients/interpreter-client.ts} +148 -171
  36. package/src/clients/port-client.ts +105 -0
  37. package/src/clients/process-client.ts +177 -0
  38. package/src/clients/sandbox-client.ts +41 -0
  39. package/src/clients/types.ts +84 -0
  40. package/src/clients/utility-client.ts +94 -0
  41. package/src/errors/adapter.ts +180 -0
  42. package/src/errors/classes.ts +469 -0
  43. package/src/errors/index.ts +105 -0
  44. package/src/file-stream.ts +119 -117
  45. package/src/index.ts +81 -69
  46. package/src/interpreter.ts +17 -8
  47. package/src/request-handler.ts +69 -43
  48. package/src/sandbox.ts +694 -533
  49. package/src/security.ts +14 -23
  50. package/src/sse-parser.ts +4 -8
  51. package/startup.sh +3 -0
  52. package/tests/base-client.test.ts +328 -0
  53. package/tests/command-client.test.ts +407 -0
  54. package/tests/file-client.test.ts +643 -0
  55. package/tests/file-stream.test.ts +306 -0
  56. package/tests/git-client.test.ts +328 -0
  57. package/tests/port-client.test.ts +301 -0
  58. package/tests/process-client.test.ts +658 -0
  59. package/tests/sandbox.test.ts +465 -0
  60. package/tests/sse-parser.test.ts +290 -0
  61. package/tests/utility-client.test.ts +266 -0
  62. package/tests/wrangler.jsonc +35 -0
  63. package/tsconfig.json +9 -1
  64. package/vitest.config.ts +31 -0
  65. package/container_src/bun.lock +0 -76
  66. package/container_src/circuit-breaker.ts +0 -121
  67. package/container_src/control-process.ts +0 -784
  68. package/container_src/handler/exec.ts +0 -185
  69. package/container_src/handler/file.ts +0 -457
  70. package/container_src/handler/git.ts +0 -130
  71. package/container_src/handler/ports.ts +0 -314
  72. package/container_src/handler/process.ts +0 -568
  73. package/container_src/handler/session.ts +0 -92
  74. package/container_src/index.ts +0 -601
  75. package/container_src/interpreter-service.ts +0 -276
  76. package/container_src/isolation.ts +0 -1213
  77. package/container_src/mime-processor.ts +0 -255
  78. package/container_src/package.json +0 -18
  79. package/container_src/runtime/executors/javascript/node_executor.ts +0 -123
  80. package/container_src/runtime/executors/python/ipython_executor.py +0 -338
  81. package/container_src/runtime/executors/typescript/ts_executor.ts +0 -138
  82. package/container_src/runtime/process-pool.ts +0 -464
  83. package/container_src/shell-escape.ts +0 -42
  84. package/container_src/startup.sh +0 -11
  85. package/container_src/types.ts +0 -131
  86. package/dist/chunk-32UDXUPC.js +0 -671
  87. package/dist/chunk-32UDXUPC.js.map +0 -1
  88. package/dist/chunk-5DILEXGY.js +0 -85
  89. package/dist/chunk-5DILEXGY.js.map +0 -1
  90. package/dist/chunk-D3U63BZP.js +0 -240
  91. package/dist/chunk-D3U63BZP.js.map +0 -1
  92. package/dist/chunk-FXYPFGOZ.js +0 -129
  93. package/dist/chunk-FXYPFGOZ.js.map +0 -1
  94. package/dist/chunk-JTKON2SH.js +0 -113
  95. package/dist/chunk-JTKON2SH.js.map +0 -1
  96. package/dist/chunk-NNGBXDMY.js.map +0 -1
  97. package/dist/chunk-SQLJNZ3K.js +0 -674
  98. package/dist/chunk-SQLJNZ3K.js.map +0 -1
  99. package/dist/chunk-W7TVRPBG.js +0 -108
  100. package/dist/chunk-W7TVRPBG.js.map +0 -1
  101. package/dist/client-B3RUab0s.d.ts +0 -225
  102. package/dist/client.d.ts +0 -4
  103. package/dist/client.js +0 -7
  104. package/dist/client.js.map +0 -1
  105. package/dist/errors.d.ts +0 -95
  106. package/dist/errors.js +0 -27
  107. package/dist/errors.js.map +0 -1
  108. package/dist/interpreter-client.d.ts +0 -4
  109. package/dist/interpreter-client.js +0 -9
  110. package/dist/interpreter-client.js.map +0 -1
  111. package/dist/interpreter-types.d.ts +0 -259
  112. package/dist/interpreter-types.js +0 -9
  113. package/dist/interpreter-types.js.map +0 -1
  114. package/dist/types.d.ts +0 -453
  115. package/dist/types.js +0 -45
  116. package/dist/types.js.map +0 -1
  117. package/src/client.ts +0 -1048
  118. package/src/errors.ts +0 -219
  119. package/src/interpreter-types.ts +0 -390
  120. package/src/types.ts +0 -571
@@ -1,185 +0,0 @@
1
- import type { SessionManager } from "../isolation";
2
- import type { SessionExecRequest } from "../types";
3
-
4
- export async function handleExecuteRequest(
5
- req: Request,
6
- corsHeaders: Record<string, string>,
7
- sessionManager: SessionManager
8
- ) {
9
- try {
10
- const body = (await req.json()) as SessionExecRequest;
11
- const { id, command } = body;
12
-
13
- console.log(
14
- `[Container] Session exec request for '${id}': ${command}`
15
- );
16
-
17
- if (!id || !command) {
18
- return new Response(
19
- JSON.stringify({
20
- error: "Session ID and command are required",
21
- }),
22
- {
23
- status: 400,
24
- headers: {
25
- "Content-Type": "application/json",
26
- ...corsHeaders,
27
- },
28
- }
29
- );
30
- }
31
-
32
- const session = sessionManager.getSession(id);
33
- if (!session) {
34
- console.error(`[Container] Session '${id}' not found!`);
35
- const availableSessions = sessionManager.listSessions();
36
- console.log(
37
- `[Container] Available sessions: ${
38
- availableSessions.join(", ") || "none"
39
- }`
40
- );
41
-
42
- return new Response(
43
- JSON.stringify({
44
- error: `Session '${id}' not found`,
45
- availableSessions,
46
- }),
47
- {
48
- status: 404,
49
- headers: {
50
- "Content-Type": "application/json",
51
- ...corsHeaders,
52
- },
53
- }
54
- );
55
- }
56
-
57
- const result = await session.exec(command);
58
-
59
- return new Response(JSON.stringify(result), {
60
- headers: { "Content-Type": "application/json", ...corsHeaders },
61
- });
62
- } catch (error) {
63
- console.error("[Container] Session exec failed:", error);
64
- return new Response(
65
- JSON.stringify({
66
- error: "Command execution failed",
67
- message:
68
- error instanceof Error ? error.message : String(error),
69
- }),
70
- {
71
- status: 500,
72
- headers: {
73
- "Content-Type": "application/json",
74
- ...corsHeaders,
75
- },
76
- }
77
- );
78
- }
79
- }
80
-
81
- export async function handleStreamingExecuteRequest(
82
- req: Request,
83
- sessionManager: SessionManager,
84
- corsHeaders: Record<string, string>
85
- ) {
86
- try {
87
- const body = (await req.json()) as SessionExecRequest;
88
- const { id, command } = body;
89
-
90
- console.log(
91
- `[Container] Session streaming exec request for '${id}': ${command}`
92
- );
93
-
94
- if (!id || !command) {
95
- return new Response(
96
- JSON.stringify({
97
- error: "Session ID and command are required",
98
- }),
99
- {
100
- status: 400,
101
- headers: {
102
- "Content-Type": "application/json",
103
- ...corsHeaders,
104
- },
105
- }
106
- );
107
- }
108
-
109
- const session = sessionManager.getSession(id);
110
- if (!session) {
111
- console.error(`[Container] Session '${id}' not found!`);
112
- const availableSessions = sessionManager.listSessions();
113
-
114
- return new Response(
115
- JSON.stringify({
116
- error: `Session '${id}' not found`,
117
- availableSessions,
118
- }),
119
- {
120
- status: 404,
121
- headers: {
122
- "Content-Type": "application/json",
123
- ...corsHeaders,
124
- },
125
- }
126
- );
127
- }
128
-
129
- // Create a streaming response using the actual streaming method
130
- const stream = new ReadableStream({
131
- async start(controller) {
132
- try {
133
- // Use the streaming generator method
134
- for await (const event of session.execStream(command)) {
135
- // Forward each event as SSE
136
- controller.enqueue(
137
- new TextEncoder().encode(
138
- `data: ${JSON.stringify(event)}\n\n`
139
- )
140
- );
141
- }
142
- controller.close();
143
- } catch (error) {
144
- controller.enqueue(
145
- new TextEncoder().encode(
146
- `data: ${JSON.stringify({
147
- type: "error",
148
- message:
149
- error instanceof Error
150
- ? error.message
151
- : String(error),
152
- })}\n\n`
153
- )
154
- );
155
- controller.close();
156
- }
157
- },
158
- });
159
-
160
- return new Response(stream, {
161
- headers: {
162
- "Content-Type": "text/event-stream",
163
- "Cache-Control": "no-cache",
164
- Connection: "keep-alive",
165
- ...corsHeaders,
166
- },
167
- });
168
- } catch (error) {
169
- console.error("[Container] Session stream exec failed:", error);
170
- return new Response(
171
- JSON.stringify({
172
- error: "Stream execution failed",
173
- message:
174
- error instanceof Error ? error.message : String(error),
175
- }),
176
- {
177
- status: 500,
178
- headers: {
179
- "Content-Type": "application/json",
180
- ...corsHeaders,
181
- },
182
- }
183
- );
184
- }
185
- }
@@ -1,457 +0,0 @@
1
- import type { SessionManager } from "../isolation";
2
- import type {
3
- DeleteFileRequest,
4
- ListFilesRequest,
5
- MkdirRequest,
6
- MoveFileRequest,
7
- ReadFileRequest,
8
- RenameFileRequest,
9
- WriteFileRequest
10
- } from "../types";
11
-
12
- // Common path validation patterns
13
- const DANGEROUS_PATH_PATTERNS = [
14
- /^\/$/, // Root directory
15
- /^\/etc/, // System directories
16
- /^\/var/, // System directories
17
- /^\/usr/, // System directories
18
- /^\/bin/, // System directories
19
- /^\/sbin/, // System directories
20
- /^\/boot/, // System directories
21
- /^\/dev/, // System directories
22
- /^\/proc/, // System directories
23
- /^\/sys/, // System directories
24
- /^\/tmp\/\.\./, // Path traversal attempts
25
- /\.\./, // Path traversal attempts
26
- ];
27
-
28
- // Path validation utility
29
- function validatePath(...paths: string[]): string | null {
30
- for (const path of paths) {
31
- if (!path || typeof path !== "string") {
32
- return "Path is required and must be a string";
33
- }
34
-
35
- if (DANGEROUS_PATH_PATTERNS.some((pattern) => pattern.test(path))) {
36
- return "Dangerous path not allowed";
37
- }
38
- }
39
- return null;
40
- }
41
-
42
- // Common error response utility
43
- function createPathErrorResponse(
44
- error: string,
45
- corsHeaders: Record<string, string>
46
- ): Response {
47
- return new Response(
48
- JSON.stringify({ error }),
49
- {
50
- headers: {
51
- "Content-Type": "application/json",
52
- ...corsHeaders,
53
- },
54
- status: 400,
55
- }
56
- );
57
- }
58
-
59
- // Common server error response utility
60
- function createServerErrorResponse(
61
- operation: string,
62
- error: unknown,
63
- corsHeaders: Record<string, string>
64
- ): Response {
65
- console.error(`[Server] Error in ${operation}:`, error);
66
- return new Response(
67
- JSON.stringify({
68
- error: `Failed to ${operation.replace('handle', '').replace('Request', '').toLowerCase().replace('file', ' file')}`,
69
- message: error instanceof Error ? error.message : "Unknown error",
70
- }),
71
- {
72
- headers: {
73
- "Content-Type": "application/json",
74
- ...corsHeaders,
75
- },
76
- status: 500,
77
- }
78
- );
79
- }
80
-
81
- export async function handleMkdirRequest(
82
- req: Request,
83
- corsHeaders: Record<string, string>,
84
- sessionManager: SessionManager
85
- ): Promise<Response> {
86
- try {
87
- const body = (await req.json()) as MkdirRequest;
88
- const { path, recursive = false, sessionId } = body;
89
-
90
- // Validate path
91
- const pathError = validatePath(path);
92
- if (pathError) {
93
- return createPathErrorResponse(pathError, corsHeaders);
94
- }
95
-
96
- console.log(`[Server] Creating directory: ${path} (recursive: ${recursive})${sessionId ? ` in session: ${sessionId}` : ''}`);
97
-
98
- // Use specific session if provided, otherwise default session
99
- const result = sessionId
100
- ? await sessionManager.getSession(sessionId)?.mkdirOperation(path, recursive)
101
- : await sessionManager.mkdir(path, recursive);
102
-
103
- if (!result) {
104
- return createServerErrorResponse("handleMkdirRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
105
- }
106
-
107
- return new Response(
108
- JSON.stringify({
109
- exitCode: result.exitCode,
110
- path,
111
- recursive,
112
- stderr: "",
113
- stdout: "",
114
- success: result.success,
115
- timestamp: new Date().toISOString(),
116
- }),
117
- {
118
- headers: {
119
- "Content-Type": "application/json",
120
- ...corsHeaders,
121
- },
122
- }
123
- );
124
- } catch (error) {
125
- return createServerErrorResponse("handleMkdirRequest", error, corsHeaders);
126
- }
127
- }
128
-
129
- export async function handleWriteFileRequest(
130
- req: Request,
131
- corsHeaders: Record<string, string>,
132
- sessionManager: SessionManager
133
- ): Promise<Response> {
134
- try {
135
- const body = (await req.json()) as WriteFileRequest;
136
- const { path, content, encoding = "utf-8", sessionId } = body;
137
-
138
- // Validate path
139
- const pathError = validatePath(path);
140
- if (pathError) {
141
- return createPathErrorResponse(pathError, corsHeaders);
142
- }
143
-
144
- console.log(`[Server] Writing file: ${path} (content length: ${content.length})${sessionId ? ` in session: ${sessionId}` : ''}`);
145
-
146
- // Use specific session if provided, otherwise default session
147
- const result = sessionId
148
- ? await sessionManager.getSession(sessionId)?.writeFileOperation(path, content, encoding)
149
- : await sessionManager.writeFile(path, content, encoding);
150
-
151
- if (!result) {
152
- return createServerErrorResponse("handleWriteFileRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
153
- }
154
-
155
- return new Response(
156
- JSON.stringify({
157
- exitCode: result.exitCode,
158
- path,
159
- success: result.success,
160
- timestamp: new Date().toISOString(),
161
- }),
162
- {
163
- headers: {
164
- "Content-Type": "application/json",
165
- ...corsHeaders,
166
- },
167
- }
168
- );
169
- } catch (error) {
170
- return createServerErrorResponse("handleWriteFileRequest", error, corsHeaders);
171
- }
172
- }
173
-
174
- export async function handleReadFileRequest(
175
- req: Request,
176
- corsHeaders: Record<string, string>,
177
- sessionManager: SessionManager
178
- ): Promise<Response> {
179
- try {
180
- const body = (await req.json()) as ReadFileRequest;
181
- const { path, encoding = "utf-8", sessionId } = body;
182
-
183
- // Validate path
184
- const pathError = validatePath(path);
185
- if (pathError) {
186
- return createPathErrorResponse(pathError, corsHeaders);
187
- }
188
-
189
- console.log(`[Server] Reading file: ${path}${sessionId ? ` in session: ${sessionId}` : ''}`);
190
-
191
- // Use specific session if provided, otherwise default session
192
- const result = sessionId
193
- ? await sessionManager.getSession(sessionId)?.readFileOperation(path, encoding)
194
- : await sessionManager.readFile(path, encoding);
195
-
196
- if (!result) {
197
- return createServerErrorResponse("handleReadFileRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
198
- }
199
-
200
- return new Response(
201
- JSON.stringify({
202
- content: result.content,
203
- exitCode: result.exitCode,
204
- path,
205
- success: result.success,
206
- timestamp: new Date().toISOString(),
207
- // New metadata fields for binary file support
208
- encoding: result.encoding,
209
- isBinary: result.isBinary,
210
- mimeType: result.mimeType,
211
- size: result.size,
212
- }),
213
- {
214
- headers: {
215
- "Content-Type": "application/json",
216
- ...corsHeaders,
217
- },
218
- }
219
- );
220
- } catch (error) {
221
- return createServerErrorResponse("handleReadFileRequest", error, corsHeaders);
222
- }
223
- }
224
-
225
- export async function handleDeleteFileRequest(
226
- req: Request,
227
- corsHeaders: Record<string, string>,
228
- sessionManager: SessionManager
229
- ): Promise<Response> {
230
- try {
231
- const body = (await req.json()) as DeleteFileRequest;
232
- const { path, sessionId } = body;
233
-
234
- // Validate path
235
- const pathError = validatePath(path);
236
- if (pathError) {
237
- return createPathErrorResponse(pathError, corsHeaders);
238
- }
239
-
240
- console.log(`[Server] Deleting file: ${path}${sessionId ? ` in session: ${sessionId}` : ''}`);
241
-
242
- // Use specific session if provided, otherwise default session
243
- const result = sessionId
244
- ? await sessionManager.getSession(sessionId)?.deleteFileOperation(path)
245
- : await sessionManager.deleteFile(path);
246
-
247
- if (!result) {
248
- return createServerErrorResponse("handleDeleteFileRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
249
- }
250
-
251
- return new Response(
252
- JSON.stringify({
253
- exitCode: result.exitCode,
254
- path,
255
- success: result.success,
256
- timestamp: new Date().toISOString(),
257
- }),
258
- {
259
- headers: {
260
- "Content-Type": "application/json",
261
- ...corsHeaders,
262
- },
263
- }
264
- );
265
- } catch (error) {
266
- return createServerErrorResponse("handleDeleteFileRequest", error, corsHeaders);
267
- }
268
- }
269
-
270
- export async function handleRenameFileRequest(
271
- req: Request,
272
- corsHeaders: Record<string, string>,
273
- sessionManager: SessionManager
274
- ): Promise<Response> {
275
- try {
276
- const body = (await req.json()) as RenameFileRequest;
277
- const { oldPath, newPath, sessionId } = body;
278
-
279
- // Validate paths
280
- const pathError = validatePath(oldPath, newPath);
281
- if (pathError) {
282
- return createPathErrorResponse(pathError, corsHeaders);
283
- }
284
-
285
- console.log(`[Server] Renaming file: ${oldPath} -> ${newPath}${sessionId ? ` in session: ${sessionId}` : ''}`);
286
-
287
- // Use specific session if provided, otherwise default session
288
- const result = sessionId
289
- ? await sessionManager.getSession(sessionId)?.renameFileOperation(oldPath, newPath)
290
- : await sessionManager.renameFile(oldPath, newPath);
291
-
292
- if (!result) {
293
- return createServerErrorResponse("handleRenameFileRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
294
- }
295
-
296
- return new Response(
297
- JSON.stringify({
298
- exitCode: result.exitCode,
299
- newPath,
300
- oldPath,
301
- success: result.success,
302
- timestamp: new Date().toISOString(),
303
- }),
304
- {
305
- headers: {
306
- "Content-Type": "application/json",
307
- ...corsHeaders,
308
- },
309
- }
310
- );
311
- } catch (error) {
312
- return createServerErrorResponse("handleRenameFileRequest", error, corsHeaders);
313
- }
314
- }
315
-
316
- export async function handleMoveFileRequest(
317
- req: Request,
318
- corsHeaders: Record<string, string>,
319
- sessionManager: SessionManager
320
- ): Promise<Response> {
321
- try {
322
- const body = (await req.json()) as MoveFileRequest;
323
- const { sourcePath, destinationPath, sessionId } = body;
324
-
325
- // Validate paths
326
- const pathError = validatePath(sourcePath, destinationPath);
327
- if (pathError) {
328
- return createPathErrorResponse(pathError, corsHeaders);
329
- }
330
-
331
- console.log(`[Server] Moving file: ${sourcePath} -> ${destinationPath}${sessionId ? ` in session: ${sessionId}` : ''}`);
332
-
333
- // Use specific session if provided, otherwise default session
334
- const result = sessionId
335
- ? await sessionManager.getSession(sessionId)?.moveFileOperation(sourcePath, destinationPath)
336
- : await sessionManager.moveFile(sourcePath, destinationPath);
337
-
338
- if (!result) {
339
- return createServerErrorResponse("handleMoveFileRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
340
- }
341
-
342
- return new Response(
343
- JSON.stringify({
344
- destinationPath,
345
- exitCode: result.exitCode,
346
- sourcePath,
347
- success: result.success,
348
- timestamp: new Date().toISOString(),
349
- }),
350
- {
351
- headers: {
352
- "Content-Type": "application/json",
353
- ...corsHeaders,
354
- },
355
- }
356
- );
357
- } catch (error) {
358
- return createServerErrorResponse("handleMoveFileRequest", error, corsHeaders);
359
- }
360
- }
361
-
362
- export async function handleListFilesRequest(
363
- req: Request,
364
- corsHeaders: Record<string, string>,
365
- sessionManager: SessionManager
366
- ): Promise<Response> {
367
- try {
368
- const body = (await req.json()) as ListFilesRequest;
369
- const { path, options, sessionId } = body;
370
-
371
- // Validate path (note: listFiles allows root directory listing)
372
- const pathError = validatePath(path);
373
- if (pathError && pathError !== "Dangerous path not allowed") {
374
- return createPathErrorResponse(pathError, corsHeaders);
375
- }
376
-
377
- // For listFiles, we allow root directory but still check other dangerous patterns
378
- if (path !== "/" && DANGEROUS_PATH_PATTERNS.slice(1).some((pattern) => pattern.test(path))) {
379
- return createPathErrorResponse("Dangerous path not allowed", corsHeaders);
380
- }
381
-
382
- console.log(`[Server] Listing files in: ${path}${sessionId ? ` in session: ${sessionId}` : ''}`);
383
-
384
- // Use specific session if provided, otherwise default session
385
- const result = sessionId
386
- ? await sessionManager.getSession(sessionId)?.listFilesOperation(path, options)
387
- : await sessionManager.listFiles(path, options);
388
-
389
- if (!result) {
390
- return createServerErrorResponse("handleListFilesRequest", new Error(`Session '${sessionId}' not found`), corsHeaders);
391
- }
392
-
393
- return new Response(
394
- JSON.stringify({
395
- exitCode: result.exitCode,
396
- files: result.files,
397
- path,
398
- success: result.success,
399
- timestamp: new Date().toISOString(),
400
- }),
401
- {
402
- headers: {
403
- "Content-Type": "application/json",
404
- ...corsHeaders,
405
- },
406
- }
407
- );
408
- } catch (error) {
409
- return createServerErrorResponse("handleListFilesRequest", error, corsHeaders);
410
- }
411
- }
412
-
413
- export async function handleReadFileStreamRequest(
414
- req: Request,
415
- corsHeaders: Record<string, string>,
416
- sessionManager: SessionManager
417
- ): Promise<Response> {
418
- try {
419
- const body = (await req.json()) as ReadFileRequest;
420
- const { path, sessionId } = body;
421
-
422
- // Validate path
423
- const pathError = validatePath(path);
424
- if (pathError) {
425
- return createPathErrorResponse(pathError, corsHeaders);
426
- }
427
-
428
- console.log(`[Server] Streaming file: ${path}${sessionId ? ` in session: ${sessionId}` : ''}`);
429
-
430
- // Get the appropriate session
431
- const session = sessionId
432
- ? sessionManager.getSession(sessionId)
433
- : await sessionManager.getOrCreateDefaultSession();
434
-
435
- if (!session) {
436
- return createServerErrorResponse(
437
- "handleReadFileStreamRequest",
438
- new Error(`Session '${sessionId}' not found`),
439
- corsHeaders
440
- );
441
- }
442
-
443
- // Create SSE stream
444
- const stream = await session.readFileStreamOperation(path);
445
-
446
- return new Response(stream, {
447
- headers: {
448
- "Content-Type": "text/event-stream",
449
- "Cache-Control": "no-cache",
450
- "Connection": "keep-alive",
451
- ...corsHeaders,
452
- },
453
- });
454
- } catch (error) {
455
- return createServerErrorResponse("handleReadFileStreamRequest", error, corsHeaders);
456
- }
457
- }