@cloudflare/sandbox 0.0.0-02ee8fe

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 (80) hide show
  1. package/CHANGELOG.md +311 -0
  2. package/Dockerfile +143 -0
  3. package/README.md +162 -0
  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-UJ3TV4M6.js +7 -0
  11. package/dist/chunk-UJ3TV4M6.js.map +1 -0
  12. package/dist/chunk-YE265ASX.js +2484 -0
  13. package/dist/chunk-YE265ASX.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-CLZWpfGc.d.ts +613 -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 +44 -0
  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 +295 -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 +93 -0
  58. package/src/interpreter.ts +159 -0
  59. package/src/request-handler.ts +180 -0
  60. package/src/sandbox.ts +1045 -0
  61. package/src/security.ts +104 -0
  62. package/src/sse-parser.ts +143 -0
  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 +719 -0
  68. package/tests/file-stream.test.ts +306 -0
  69. package/tests/get-sandbox.test.ts +149 -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/request-handler.test.ts +240 -0
  74. package/tests/sandbox.test.ts +554 -0
  75. package/tests/sse-parser.test.ts +290 -0
  76. package/tests/utility-client.test.ts +332 -0
  77. package/tests/version.test.ts +16 -0
  78. package/tests/wrangler.jsonc +35 -0
  79. package/tsconfig.json +11 -0
  80. package/vitest.config.ts +31 -0
@@ -0,0 +1,295 @@
1
+ import type {
2
+ DeleteFileResult,
3
+ FileExistsResult,
4
+ ListFilesOptions,
5
+ ListFilesResult,
6
+ MkdirResult,
7
+ MoveFileResult,
8
+ ReadFileResult,
9
+ RenameFileResult,
10
+ WriteFileResult
11
+ } from '@repo/shared';
12
+ import { BaseHttpClient } from './base-client';
13
+ import type { HttpClientOptions, SessionRequest } from './types';
14
+
15
+ /**
16
+ * Request interface for creating directories
17
+ */
18
+ export interface MkdirRequest extends SessionRequest {
19
+ path: string;
20
+ recursive?: boolean;
21
+ }
22
+
23
+ /**
24
+ * Request interface for writing files
25
+ */
26
+ export interface WriteFileRequest extends SessionRequest {
27
+ path: string;
28
+ content: string;
29
+ encoding?: string;
30
+ }
31
+
32
+ /**
33
+ * Request interface for reading files
34
+ */
35
+ export interface ReadFileRequest extends SessionRequest {
36
+ path: string;
37
+ encoding?: string;
38
+ }
39
+
40
+ /**
41
+ * Request interface for file operations (delete, rename, move)
42
+ */
43
+ export interface FileOperationRequest extends SessionRequest {
44
+ path: string;
45
+ newPath?: string; // For rename/move operations
46
+ }
47
+
48
+ /**
49
+ * Client for file system operations
50
+ */
51
+ export class FileClient extends BaseHttpClient {
52
+
53
+ /**
54
+ * Create a directory
55
+ * @param path - Directory path to create
56
+ * @param sessionId - The session ID for this operation
57
+ * @param options - Optional settings (recursive)
58
+ */
59
+ async mkdir(
60
+ path: string,
61
+ sessionId: string,
62
+ options?: { recursive?: boolean }
63
+ ): Promise<MkdirResult> {
64
+ try {
65
+ const data = {
66
+ path,
67
+ sessionId,
68
+ recursive: options?.recursive ?? false,
69
+ };
70
+
71
+ const response = await this.post<MkdirResult>('/api/mkdir', data);
72
+
73
+ this.logSuccess('Directory created', `${path} (recursive: ${data.recursive})`);
74
+ return response;
75
+ } catch (error) {
76
+ this.logError('mkdir', error);
77
+ throw error;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Write content to a file
83
+ * @param path - File path to write to
84
+ * @param content - Content to write
85
+ * @param sessionId - The session ID for this operation
86
+ * @param options - Optional settings (encoding)
87
+ */
88
+ async writeFile(
89
+ path: string,
90
+ content: string,
91
+ sessionId: string,
92
+ options?: { encoding?: string }
93
+ ): Promise<WriteFileResult> {
94
+ try {
95
+ const data = {
96
+ path,
97
+ content,
98
+ sessionId,
99
+ encoding: options?.encoding ?? 'utf8',
100
+ };
101
+
102
+ const response = await this.post<WriteFileResult>('/api/write', data);
103
+
104
+ this.logSuccess('File written', `${path} (${content.length} chars)`);
105
+ return response;
106
+ } catch (error) {
107
+ this.logError('writeFile', error);
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Read content from a file
114
+ * @param path - File path to read from
115
+ * @param sessionId - The session ID for this operation
116
+ * @param options - Optional settings (encoding)
117
+ */
118
+ async readFile(
119
+ path: string,
120
+ sessionId: string,
121
+ options?: { encoding?: string }
122
+ ): Promise<ReadFileResult> {
123
+ try {
124
+ const data = {
125
+ path,
126
+ sessionId,
127
+ encoding: options?.encoding ?? 'utf8',
128
+ };
129
+
130
+ const response = await this.post<ReadFileResult>('/api/read', data);
131
+
132
+ this.logSuccess('File read', `${path} (${response.content.length} chars)`);
133
+ return response;
134
+ } catch (error) {
135
+ this.logError('readFile', error);
136
+ throw error;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Stream a file using Server-Sent Events
142
+ * Returns a ReadableStream of SSE events containing metadata, chunks, and completion
143
+ * @param path - File path to stream
144
+ * @param sessionId - The session ID for this operation
145
+ */
146
+ async readFileStream(
147
+ path: string,
148
+ sessionId: string
149
+ ): Promise<ReadableStream<Uint8Array>> {
150
+ try {
151
+ const data = {
152
+ path,
153
+ sessionId,
154
+ };
155
+
156
+ const response = await this.doFetch('/api/read/stream', {
157
+ method: 'POST',
158
+ headers: {
159
+ 'Content-Type': 'application/json',
160
+ },
161
+ body: JSON.stringify(data),
162
+ });
163
+
164
+ const stream = await this.handleStreamResponse(response);
165
+ this.logSuccess('File stream started', path);
166
+ return stream;
167
+ } catch (error) {
168
+ this.logError('readFileStream', error);
169
+ throw error;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Delete a file
175
+ * @param path - File path to delete
176
+ * @param sessionId - The session ID for this operation
177
+ */
178
+ async deleteFile(
179
+ path: string,
180
+ sessionId: string
181
+ ): Promise<DeleteFileResult> {
182
+ try {
183
+ const data = { path, sessionId };
184
+
185
+ const response = await this.post<DeleteFileResult>('/api/delete', data);
186
+
187
+ this.logSuccess('File deleted', path);
188
+ return response;
189
+ } catch (error) {
190
+ this.logError('deleteFile', error);
191
+ throw error;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Rename a file
197
+ * @param path - Current file path
198
+ * @param newPath - New file path
199
+ * @param sessionId - The session ID for this operation
200
+ */
201
+ async renameFile(
202
+ path: string,
203
+ newPath: string,
204
+ sessionId: string
205
+ ): Promise<RenameFileResult> {
206
+ try {
207
+ const data = { oldPath: path, newPath, sessionId };
208
+
209
+ const response = await this.post<RenameFileResult>('/api/rename', data);
210
+
211
+ this.logSuccess('File renamed', `${path} -> ${newPath}`);
212
+ return response;
213
+ } catch (error) {
214
+ this.logError('renameFile', error);
215
+ throw error;
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Move a file
221
+ * @param path - Current file path
222
+ * @param newPath - Destination file path
223
+ * @param sessionId - The session ID for this operation
224
+ */
225
+ async moveFile(
226
+ path: string,
227
+ newPath: string,
228
+ sessionId: string
229
+ ): Promise<MoveFileResult> {
230
+ try {
231
+ const data = { sourcePath: path, destinationPath: newPath, sessionId };
232
+
233
+ const response = await this.post<MoveFileResult>('/api/move', data);
234
+
235
+ this.logSuccess('File moved', `${path} -> ${newPath}`);
236
+ return response;
237
+ } catch (error) {
238
+ this.logError('moveFile', error);
239
+ throw error;
240
+ }
241
+ }
242
+
243
+ /**
244
+ * List files in a directory
245
+ * @param path - Directory path to list
246
+ * @param sessionId - The session ID for this operation
247
+ * @param options - Optional settings (recursive, includeHidden)
248
+ */
249
+ async listFiles(
250
+ path: string,
251
+ sessionId: string,
252
+ options?: ListFilesOptions
253
+ ): Promise<ListFilesResult> {
254
+ try {
255
+ const data = {
256
+ path,
257
+ sessionId,
258
+ options: options || {},
259
+ };
260
+
261
+ const response = await this.post<ListFilesResult>('/api/list-files', data);
262
+
263
+ this.logSuccess('Files listed', `${path} (${response.count} files)`);
264
+ return response;
265
+ } catch (error) {
266
+ this.logError('listFiles', error);
267
+ throw error;
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Check if a file or directory exists
273
+ * @param path - Path to check
274
+ * @param sessionId - The session ID for this operation
275
+ */
276
+ async exists(
277
+ path: string,
278
+ sessionId: string
279
+ ): Promise<FileExistsResult> {
280
+ try {
281
+ const data = {
282
+ path,
283
+ sessionId,
284
+ };
285
+
286
+ const response = await this.post<FileExistsResult>('/api/exists', data);
287
+
288
+ this.logSuccess('Path existence checked', `${path} (exists: ${response.exists})`);
289
+ return response;
290
+ } catch (error) {
291
+ this.logError('exists', error);
292
+ throw error;
293
+ }
294
+ }
295
+ }
@@ -0,0 +1,92 @@
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
+
22
+ /**
23
+ * Clone a Git repository
24
+ * @param repoUrl - URL of the Git repository to clone
25
+ * @param sessionId - The session ID for this operation
26
+ * @param options - Optional settings (branch, targetDir)
27
+ */
28
+ async checkout(
29
+ repoUrl: string,
30
+ sessionId: string,
31
+ options?: {
32
+ branch?: string;
33
+ targetDir?: string;
34
+ }
35
+ ): Promise<GitCheckoutResult> {
36
+ try {
37
+ // Determine target directory - use provided path or generate from repo name
38
+ let targetDir = options?.targetDir;
39
+ if (!targetDir) {
40
+ const repoName = this.extractRepoName(repoUrl);
41
+ // Ensure absolute path in /workspace
42
+ targetDir = `/workspace/${repoName}`;
43
+ }
44
+
45
+ const data: GitCheckoutRequest = {
46
+ repoUrl,
47
+ sessionId,
48
+ targetDir,
49
+ };
50
+
51
+ // Only include branch if explicitly specified
52
+ // This allows Git to use the repository's default branch
53
+ if (options?.branch) {
54
+ data.branch = options.branch;
55
+ }
56
+
57
+ const response = await this.post<GitCheckoutResult>(
58
+ '/api/git/checkout',
59
+ data
60
+ );
61
+
62
+ this.logSuccess(
63
+ 'Repository cloned',
64
+ `${repoUrl} (branch: ${response.branch}) -> ${response.targetDir}`
65
+ );
66
+
67
+ return response;
68
+ } catch (error) {
69
+ this.logError('checkout', error);
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Extract repository name from URL for default directory name
76
+ */
77
+ private extractRepoName(repoUrl: string): string {
78
+ try {
79
+ const url = new URL(repoUrl);
80
+ const pathParts = url.pathname.split('/');
81
+ const repoName = pathParts[pathParts.length - 1];
82
+
83
+ // Remove .git extension if present
84
+ return repoName.replace(/\.git$/, '');
85
+ } catch {
86
+ // Fallback for invalid URLs
87
+ const parts = repoUrl.split('/');
88
+ const repoName = parts[parts.length - 1];
89
+ return repoName.replace(/\.git$/, '') || 'repo';
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,64 @@
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
+ VersionResponse,
63
+ } from './utility-client';
64
+ export { UtilityClient } from './utility-client';