@cloudflare/sandbox 0.0.0-46eb4e6 → 0.0.0-485cf61

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 +0 -6
  2. package/Dockerfile +82 -18
  3. package/README.md +89 -824
  4. package/dist/chunk-3NEP4CNV.js +99 -0
  5. package/dist/chunk-3NEP4CNV.js.map +1 -0
  6. package/dist/chunk-6IYG2RIN.js +117 -0
  7. package/dist/chunk-6IYG2RIN.js.map +1 -0
  8. package/dist/chunk-HB44YO2A.js +2331 -0
  9. package/dist/chunk-HB44YO2A.js.map +1 -0
  10. package/dist/chunk-KPVMMMIP.js +105 -0
  11. package/dist/chunk-KPVMMMIP.js.map +1 -0
  12. package/dist/chunk-NNGBXDMY.js +89 -0
  13. package/dist/chunk-NNGBXDMY.js.map +1 -0
  14. package/dist/file-stream.d.ts +43 -0
  15. package/dist/file-stream.js +9 -0
  16. package/dist/file-stream.js.map +1 -0
  17. package/dist/index.d.ts +9 -0
  18. package/dist/index.js +55 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/interpreter.d.ts +33 -0
  21. package/dist/interpreter.js +8 -0
  22. package/dist/interpreter.js.map +1 -0
  23. package/dist/request-handler.d.ts +18 -0
  24. package/dist/request-handler.js +12 -0
  25. package/dist/request-handler.js.map +1 -0
  26. package/dist/sandbox-CtlKjZwf.d.ts +583 -0
  27. package/dist/sandbox.d.ts +4 -0
  28. package/dist/sandbox.js +12 -0
  29. package/dist/sandbox.js.map +1 -0
  30. package/dist/security.d.ts +35 -0
  31. package/dist/security.js +15 -0
  32. package/dist/security.js.map +1 -0
  33. package/dist/sse-parser.d.ts +28 -0
  34. package/dist/sse-parser.js +11 -0
  35. package/dist/sse-parser.js.map +1 -0
  36. package/package.json +11 -5
  37. package/src/clients/base-client.ts +297 -0
  38. package/src/clients/command-client.ts +118 -0
  39. package/src/clients/file-client.ts +272 -0
  40. package/src/clients/git-client.ts +95 -0
  41. package/src/clients/index.ts +63 -0
  42. package/src/{interpreter-client.ts → clients/interpreter-client.ts} +151 -171
  43. package/src/clients/port-client.ts +108 -0
  44. package/src/clients/process-client.ts +180 -0
  45. package/src/clients/sandbox-client.ts +41 -0
  46. package/src/clients/types.ts +81 -0
  47. package/src/clients/utility-client.ts +97 -0
  48. package/src/errors/adapter.ts +180 -0
  49. package/src/errors/classes.ts +469 -0
  50. package/src/errors/index.ts +105 -0
  51. package/src/file-stream.ts +119 -117
  52. package/src/index.ts +81 -69
  53. package/src/interpreter.ts +17 -8
  54. package/src/request-handler.ts +61 -7
  55. package/src/sandbox.ts +698 -495
  56. package/src/security.ts +20 -0
  57. package/startup.sh +7 -0
  58. package/tests/base-client.test.ts +328 -0
  59. package/tests/command-client.test.ts +407 -0
  60. package/tests/file-client.test.ts +643 -0
  61. package/tests/file-stream.test.ts +306 -0
  62. package/tests/git-client.test.ts +328 -0
  63. package/tests/port-client.test.ts +301 -0
  64. package/tests/process-client.test.ts +658 -0
  65. package/tests/sandbox.test.ts +465 -0
  66. package/tests/sse-parser.test.ts +291 -0
  67. package/tests/utility-client.test.ts +266 -0
  68. package/tests/wrangler.jsonc +35 -0
  69. package/tsconfig.json +9 -1
  70. package/vitest.config.ts +31 -0
  71. package/container_src/bun.lock +0 -76
  72. package/container_src/circuit-breaker.ts +0 -121
  73. package/container_src/control-process.ts +0 -784
  74. package/container_src/handler/exec.ts +0 -185
  75. package/container_src/handler/file.ts +0 -457
  76. package/container_src/handler/git.ts +0 -130
  77. package/container_src/handler/ports.ts +0 -314
  78. package/container_src/handler/process.ts +0 -568
  79. package/container_src/handler/session.ts +0 -92
  80. package/container_src/index.ts +0 -600
  81. package/container_src/interpreter-service.ts +0 -276
  82. package/container_src/isolation.ts +0 -1213
  83. package/container_src/mime-processor.ts +0 -255
  84. package/container_src/package.json +0 -18
  85. package/container_src/runtime/executors/javascript/node_executor.ts +0 -123
  86. package/container_src/runtime/executors/python/ipython_executor.py +0 -338
  87. package/container_src/runtime/executors/typescript/ts_executor.ts +0 -138
  88. package/container_src/runtime/process-pool.ts +0 -464
  89. package/container_src/shell-escape.ts +0 -42
  90. package/container_src/startup.sh +0 -11
  91. package/container_src/types.ts +0 -131
  92. package/src/client.ts +0 -1048
  93. package/src/errors.ts +0 -219
  94. package/src/interpreter-types.ts +0 -390
  95. package/src/types.ts +0 -571
@@ -0,0 +1,272 @@
1
+ import type {
2
+ DeleteFileResult,
3
+ ListFilesOptions,
4
+ ListFilesResult,
5
+ MkdirResult,
6
+ MoveFileResult,
7
+ ReadFileResult,
8
+ RenameFileResult,
9
+ WriteFileResult
10
+ } from '@repo/shared';
11
+ import { BaseHttpClient } from './base-client';
12
+ import type { HttpClientOptions, SessionRequest } from './types';
13
+
14
+ /**
15
+ * Request interface for creating directories
16
+ */
17
+ export interface MkdirRequest extends SessionRequest {
18
+ path: string;
19
+ recursive?: boolean;
20
+ }
21
+
22
+ /**
23
+ * Request interface for writing files
24
+ */
25
+ export interface WriteFileRequest extends SessionRequest {
26
+ path: string;
27
+ content: string;
28
+ encoding?: string;
29
+ }
30
+
31
+ /**
32
+ * Request interface for reading files
33
+ */
34
+ export interface ReadFileRequest extends SessionRequest {
35
+ path: string;
36
+ encoding?: string;
37
+ }
38
+
39
+ /**
40
+ * Request interface for file operations (delete, rename, move)
41
+ */
42
+ export interface FileOperationRequest extends SessionRequest {
43
+ path: string;
44
+ newPath?: string; // For rename/move operations
45
+ }
46
+
47
+ /**
48
+ * Client for file system operations
49
+ */
50
+ export class FileClient extends BaseHttpClient {
51
+ constructor(options: HttpClientOptions = {}) {
52
+ super(options);
53
+ }
54
+
55
+ /**
56
+ * Create a directory
57
+ * @param path - Directory path to create
58
+ * @param sessionId - The session ID for this operation
59
+ * @param options - Optional settings (recursive)
60
+ */
61
+ async mkdir(
62
+ path: string,
63
+ sessionId: string,
64
+ options?: { recursive?: boolean }
65
+ ): Promise<MkdirResult> {
66
+ try {
67
+ const data = {
68
+ path,
69
+ sessionId,
70
+ recursive: options?.recursive ?? false,
71
+ };
72
+
73
+ const response = await this.post<MkdirResult>('/api/mkdir', data);
74
+
75
+ this.logSuccess('Directory created', `${path} (recursive: ${data.recursive})`);
76
+ return response;
77
+ } catch (error) {
78
+ this.logError('mkdir', error);
79
+ throw error;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Write content to a file
85
+ * @param path - File path to write to
86
+ * @param content - Content to write
87
+ * @param sessionId - The session ID for this operation
88
+ * @param options - Optional settings (encoding)
89
+ */
90
+ async writeFile(
91
+ path: string,
92
+ content: string,
93
+ sessionId: string,
94
+ options?: { encoding?: string }
95
+ ): Promise<WriteFileResult> {
96
+ try {
97
+ const data = {
98
+ path,
99
+ content,
100
+ sessionId,
101
+ encoding: options?.encoding ?? 'utf8',
102
+ };
103
+
104
+ const response = await this.post<WriteFileResult>('/api/write', data);
105
+
106
+ this.logSuccess('File written', `${path} (${content.length} chars)`);
107
+ return response;
108
+ } catch (error) {
109
+ this.logError('writeFile', error);
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Read content from a file
116
+ * @param path - File path to read from
117
+ * @param sessionId - The session ID for this operation
118
+ * @param options - Optional settings (encoding)
119
+ */
120
+ async readFile(
121
+ path: string,
122
+ sessionId: string,
123
+ options?: { encoding?: string }
124
+ ): Promise<ReadFileResult> {
125
+ try {
126
+ const data = {
127
+ path,
128
+ sessionId,
129
+ encoding: options?.encoding ?? 'utf8',
130
+ };
131
+
132
+ const response = await this.post<ReadFileResult>('/api/read', data);
133
+
134
+ this.logSuccess('File read', `${path} (${response.content.length} chars)`);
135
+ return response;
136
+ } catch (error) {
137
+ this.logError('readFile', error);
138
+ throw error;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Stream a file using Server-Sent Events
144
+ * Returns a ReadableStream of SSE events containing metadata, chunks, and completion
145
+ * @param path - File path to stream
146
+ * @param sessionId - The session ID for this operation
147
+ */
148
+ async readFileStream(
149
+ path: string,
150
+ sessionId: string
151
+ ): Promise<ReadableStream<Uint8Array>> {
152
+ try {
153
+ const data = {
154
+ path,
155
+ sessionId,
156
+ };
157
+
158
+ const response = await this.doFetch('/api/read/stream', {
159
+ method: 'POST',
160
+ headers: {
161
+ 'Content-Type': 'application/json',
162
+ },
163
+ body: JSON.stringify(data),
164
+ });
165
+
166
+ const stream = await this.handleStreamResponse(response);
167
+ this.logSuccess('File stream started', path);
168
+ return stream;
169
+ } catch (error) {
170
+ this.logError('readFileStream', error);
171
+ throw error;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Delete a file
177
+ * @param path - File path to delete
178
+ * @param sessionId - The session ID for this operation
179
+ */
180
+ async deleteFile(
181
+ path: string,
182
+ sessionId: string
183
+ ): Promise<DeleteFileResult> {
184
+ try {
185
+ const data = { path, sessionId };
186
+
187
+ const response = await this.post<DeleteFileResult>('/api/delete', data);
188
+
189
+ this.logSuccess('File deleted', path);
190
+ return response;
191
+ } catch (error) {
192
+ this.logError('deleteFile', error);
193
+ throw error;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Rename a file
199
+ * @param path - Current file path
200
+ * @param newPath - New file path
201
+ * @param sessionId - The session ID for this operation
202
+ */
203
+ async renameFile(
204
+ path: string,
205
+ newPath: string,
206
+ sessionId: string
207
+ ): Promise<RenameFileResult> {
208
+ try {
209
+ const data = { oldPath: path, newPath, sessionId };
210
+
211
+ const response = await this.post<RenameFileResult>('/api/rename', data);
212
+
213
+ this.logSuccess('File renamed', `${path} -> ${newPath}`);
214
+ return response;
215
+ } catch (error) {
216
+ this.logError('renameFile', error);
217
+ throw error;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Move a file
223
+ * @param path - Current file path
224
+ * @param newPath - Destination file path
225
+ * @param sessionId - The session ID for this operation
226
+ */
227
+ async moveFile(
228
+ path: string,
229
+ newPath: string,
230
+ sessionId: string
231
+ ): Promise<MoveFileResult> {
232
+ try {
233
+ const data = { sourcePath: path, destinationPath: newPath, sessionId };
234
+
235
+ const response = await this.post<MoveFileResult>('/api/move', data);
236
+
237
+ this.logSuccess('File moved', `${path} -> ${newPath}`);
238
+ return response;
239
+ } catch (error) {
240
+ this.logError('moveFile', error);
241
+ throw error;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * List files in a directory
247
+ * @param path - Directory path to list
248
+ * @param sessionId - The session ID for this operation
249
+ * @param options - Optional settings (recursive, includeHidden)
250
+ */
251
+ async listFiles(
252
+ path: string,
253
+ sessionId: string,
254
+ options?: ListFilesOptions
255
+ ): Promise<ListFilesResult> {
256
+ try {
257
+ const data = {
258
+ path,
259
+ sessionId,
260
+ options: options || {},
261
+ };
262
+
263
+ const response = await this.post<ListFilesResult>('/api/list-files', data);
264
+
265
+ this.logSuccess('Files listed', `${path} (${response.count} files)`);
266
+ return response;
267
+ } catch (error) {
268
+ this.logError('listFiles', error);
269
+ throw error;
270
+ }
271
+ }
272
+ }
@@ -0,0 +1,95 @@
1
+ import type { GitCheckoutResult } from '@repo/shared';
2
+ import { BaseHttpClient } from './base-client';
3
+ import type { HttpClientOptions, SessionRequest } from './types';
4
+
5
+ // Re-export for convenience
6
+ export type { GitCheckoutResult };
7
+
8
+ /**
9
+ * Request interface for Git checkout operations
10
+ */
11
+ export interface GitCheckoutRequest extends SessionRequest {
12
+ repoUrl: string;
13
+ branch?: string;
14
+ targetDir?: string;
15
+ }
16
+
17
+ /**
18
+ * Client for Git repository operations
19
+ */
20
+ export class GitClient extends BaseHttpClient {
21
+ constructor(options: HttpClientOptions = {}) {
22
+ super(options);
23
+ }
24
+
25
+ /**
26
+ * Clone a Git repository
27
+ * @param repoUrl - URL of the Git repository to clone
28
+ * @param sessionId - The session ID for this operation
29
+ * @param options - Optional settings (branch, targetDir)
30
+ */
31
+ async checkout(
32
+ repoUrl: string,
33
+ sessionId: string,
34
+ options?: {
35
+ branch?: string;
36
+ targetDir?: string;
37
+ }
38
+ ): Promise<GitCheckoutResult> {
39
+ try {
40
+ // Determine target directory - use provided path or generate from repo name
41
+ let targetDir = options?.targetDir;
42
+ if (!targetDir) {
43
+ const repoName = this.extractRepoName(repoUrl);
44
+ // Ensure absolute path in /workspace
45
+ targetDir = `/workspace/${repoName}`;
46
+ }
47
+
48
+ const data: GitCheckoutRequest = {
49
+ repoUrl,
50
+ sessionId,
51
+ targetDir,
52
+ };
53
+
54
+ // Only include branch if explicitly specified
55
+ // This allows Git to use the repository's default branch
56
+ if (options?.branch) {
57
+ data.branch = options.branch;
58
+ }
59
+
60
+ const response = await this.post<GitCheckoutResult>(
61
+ '/api/git/checkout',
62
+ data
63
+ );
64
+
65
+ this.logSuccess(
66
+ 'Repository cloned',
67
+ `${repoUrl} (branch: ${response.branch}) -> ${response.targetDir}`
68
+ );
69
+
70
+ return response;
71
+ } catch (error) {
72
+ this.logError('checkout', error);
73
+ throw error;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Extract repository name from URL for default directory name
79
+ */
80
+ private extractRepoName(repoUrl: string): string {
81
+ try {
82
+ const url = new URL(repoUrl);
83
+ const pathParts = url.pathname.split('/');
84
+ const repoName = pathParts[pathParts.length - 1];
85
+
86
+ // Remove .git extension if present
87
+ return repoName.replace(/\.git$/, '');
88
+ } catch {
89
+ // Fallback for invalid URLs
90
+ const parts = repoUrl.split('/');
91
+ const repoName = parts[parts.length - 1];
92
+ return repoName.replace(/\.git$/, '') || 'repo';
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,63 @@
1
+ // Main client exports
2
+
3
+
4
+ // Command client types
5
+ export type {
6
+ ExecuteRequest,
7
+ ExecuteResponse,
8
+ } from './command-client';
9
+
10
+ // Domain-specific clients
11
+ export { CommandClient } from './command-client';
12
+ // File client types
13
+ export type {
14
+ FileOperationRequest,
15
+ MkdirRequest,
16
+ ReadFileRequest,
17
+ WriteFileRequest,
18
+ } from './file-client';
19
+ export { FileClient } from './file-client';
20
+ // Git client types
21
+ export type {
22
+ GitCheckoutRequest,
23
+ GitCheckoutResult,
24
+ } from './git-client';
25
+ export { GitClient } from './git-client';
26
+ export { type ExecutionCallbacks, InterpreterClient } from './interpreter-client';
27
+ // Port client types
28
+ export type {
29
+ ExposePortRequest,
30
+ PortCloseResult,
31
+ PortExposeResult,
32
+ PortListResult,
33
+ UnexposePortRequest,
34
+ } from './port-client';
35
+ export { PortClient } from './port-client';
36
+ // Process client types
37
+ export type {
38
+ ProcessCleanupResult,
39
+ ProcessInfoResult,
40
+ ProcessKillResult,
41
+ ProcessListResult,
42
+ ProcessLogsResult,
43
+ ProcessStartResult,
44
+ StartProcessRequest,
45
+ } from './process-client';
46
+ export { ProcessClient } from './process-client';
47
+ export { SandboxClient } from './sandbox-client';
48
+ // Types and interfaces
49
+ export type {
50
+ BaseApiResponse,
51
+ ContainerStub,
52
+ ErrorResponse,
53
+ HttpClientOptions,
54
+ RequestConfig,
55
+ ResponseHandler,
56
+ SessionRequest,
57
+ } from './types';
58
+ // Utility client types
59
+ export type {
60
+ CommandsResponse,
61
+ PingResponse,
62
+ } from './utility-client';
63
+ export { UtilityClient } from './utility-client';