@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
@@ -7,7 +7,7 @@ vi.mock('../src/sandbox', () => {
7
7
  const mockFn = vi.fn();
8
8
  return {
9
9
  getSandbox: mockFn,
10
- Sandbox: vi.fn(),
10
+ Sandbox: vi.fn()
11
11
  };
12
12
  });
13
13
 
@@ -25,11 +25,11 @@ describe('proxyToSandbox - WebSocket Support', () => {
25
25
  mockSandbox = {
26
26
  validatePortToken: vi.fn().mockResolvedValue(true),
27
27
  fetch: vi.fn().mockResolvedValue(new Response('WebSocket response')),
28
- containerFetch: vi.fn().mockResolvedValue(new Response('HTTP response')),
28
+ containerFetch: vi.fn().mockResolvedValue(new Response('HTTP response'))
29
29
  };
30
30
 
31
31
  mockEnv = {
32
- Sandbox: {} as any,
32
+ Sandbox: {} as any
33
33
  };
34
34
 
35
35
  vi.mocked(getSandbox).mockReturnValue(mockSandbox as Sandbox);
@@ -37,12 +37,15 @@ describe('proxyToSandbox - WebSocket Support', () => {
37
37
 
38
38
  describe('WebSocket detection and routing', () => {
39
39
  it('should detect WebSocket upgrade header (case-insensitive)', async () => {
40
- const request = new Request('https://8080-sandbox-token12345678901.example.com/ws', {
41
- headers: {
42
- 'Upgrade': 'websocket',
43
- 'Connection': 'Upgrade',
44
- },
45
- });
40
+ const request = new Request(
41
+ 'https://8080-sandbox-token12345678901.example.com/ws',
42
+ {
43
+ headers: {
44
+ Upgrade: 'websocket',
45
+ Connection: 'Upgrade'
46
+ }
47
+ }
48
+ );
46
49
 
47
50
  await proxyToSandbox(request, mockEnv);
48
51
 
@@ -52,32 +55,40 @@ describe('proxyToSandbox - WebSocket Support', () => {
52
55
  });
53
56
 
54
57
  it('should set cf-container-target-port header for WebSocket', async () => {
55
- const request = new Request('https://8080-sandbox-token12345678901.example.com/ws', {
56
- headers: {
57
- 'Upgrade': 'websocket',
58
- },
59
- });
58
+ const request = new Request(
59
+ 'https://8080-sandbox-token12345678901.example.com/ws',
60
+ {
61
+ headers: {
62
+ Upgrade: 'websocket'
63
+ }
64
+ }
65
+ );
60
66
 
61
67
  await proxyToSandbox(request, mockEnv);
62
68
 
63
69
  expect(mockSandbox.fetch).toHaveBeenCalledTimes(1);
64
- const fetchCall = vi.mocked(mockSandbox.fetch as any).mock.calls[0][0] as Request;
70
+ const fetchCall = vi.mocked(mockSandbox.fetch as any).mock
71
+ .calls[0][0] as Request;
65
72
  expect(fetchCall.headers.get('cf-container-target-port')).toBe('8080');
66
73
  });
67
74
 
68
75
  it('should preserve original headers for WebSocket', async () => {
69
- const request = new Request('https://8080-sandbox-token12345678901.example.com/ws', {
70
- headers: {
71
- 'Upgrade': 'websocket',
72
- 'Sec-WebSocket-Key': 'test-key-123',
73
- 'Sec-WebSocket-Version': '13',
74
- 'User-Agent': 'test-client',
75
- },
76
- });
76
+ const request = new Request(
77
+ 'https://8080-sandbox-token12345678901.example.com/ws',
78
+ {
79
+ headers: {
80
+ Upgrade: 'websocket',
81
+ 'Sec-WebSocket-Key': 'test-key-123',
82
+ 'Sec-WebSocket-Version': '13',
83
+ 'User-Agent': 'test-client'
84
+ }
85
+ }
86
+ );
77
87
 
78
88
  await proxyToSandbox(request, mockEnv);
79
89
 
80
- const fetchCall = vi.mocked(mockSandbox.fetch as any).mock.calls[0][0] as Request;
90
+ const fetchCall = vi.mocked(mockSandbox.fetch as any).mock
91
+ .calls[0][0] as Request;
81
92
  expect(fetchCall.headers.get('Upgrade')).toBe('websocket');
82
93
  expect(fetchCall.headers.get('Sec-WebSocket-Key')).toBe('test-key-123');
83
94
  expect(fetchCall.headers.get('Sec-WebSocket-Version')).toBe('13');
@@ -87,9 +98,12 @@ describe('proxyToSandbox - WebSocket Support', () => {
87
98
 
88
99
  describe('HTTP routing (existing behavior)', () => {
89
100
  it('should route HTTP requests through containerFetch', async () => {
90
- const request = new Request('https://8080-sandbox-token12345678901.example.com/api/data', {
91
- method: 'GET',
92
- });
101
+ const request = new Request(
102
+ 'https://8080-sandbox-token12345678901.example.com/api/data',
103
+ {
104
+ method: 'GET'
105
+ }
106
+ );
93
107
 
94
108
  await proxyToSandbox(request, mockEnv);
95
109
 
@@ -99,13 +113,16 @@ describe('proxyToSandbox - WebSocket Support', () => {
99
113
  });
100
114
 
101
115
  it('should route POST requests through containerFetch', async () => {
102
- const request = new Request('https://8080-sandbox-token12345678901.example.com/api/data', {
103
- method: 'POST',
104
- body: JSON.stringify({ data: 'test' }),
105
- headers: {
106
- 'Content-Type': 'application/json',
107
- },
108
- });
116
+ const request = new Request(
117
+ 'https://8080-sandbox-token12345678901.example.com/api/data',
118
+ {
119
+ method: 'POST',
120
+ body: JSON.stringify({ data: 'test' }),
121
+ headers: {
122
+ 'Content-Type': 'application/json'
123
+ }
124
+ }
125
+ );
109
126
 
110
127
  await proxyToSandbox(request, mockEnv);
111
128
 
@@ -114,11 +131,14 @@ describe('proxyToSandbox - WebSocket Support', () => {
114
131
  });
115
132
 
116
133
  it('should not detect SSE as WebSocket', async () => {
117
- const request = new Request('https://8080-sandbox-token12345678901.example.com/events', {
118
- headers: {
119
- 'Accept': 'text/event-stream',
120
- },
121
- });
134
+ const request = new Request(
135
+ 'https://8080-sandbox-token12345678901.example.com/events',
136
+ {
137
+ headers: {
138
+ Accept: 'text/event-stream'
139
+ }
140
+ }
141
+ );
122
142
 
123
143
  await proxyToSandbox(request, mockEnv);
124
144
 
@@ -130,26 +150,40 @@ describe('proxyToSandbox - WebSocket Support', () => {
130
150
 
131
151
  describe('Token validation', () => {
132
152
  it('should validate token for both WebSocket and HTTP requests', async () => {
133
- const wsRequest = new Request('https://8080-sandbox-token12345678901.example.com/ws', {
134
- headers: { 'Upgrade': 'websocket' },
135
- });
153
+ const wsRequest = new Request(
154
+ 'https://8080-sandbox-token12345678901.example.com/ws',
155
+ {
156
+ headers: { Upgrade: 'websocket' }
157
+ }
158
+ );
136
159
 
137
160
  await proxyToSandbox(wsRequest, mockEnv);
138
- expect(mockSandbox.validatePortToken).toHaveBeenCalledWith(8080, 'token12345678901');
161
+ expect(mockSandbox.validatePortToken).toHaveBeenCalledWith(
162
+ 8080,
163
+ 'token12345678901'
164
+ );
139
165
 
140
166
  vi.clearAllMocks();
141
167
 
142
- const httpRequest = new Request('https://8080-sandbox-token12345678901.example.com/api');
168
+ const httpRequest = new Request(
169
+ 'https://8080-sandbox-token12345678901.example.com/api'
170
+ );
143
171
  await proxyToSandbox(httpRequest, mockEnv);
144
- expect(mockSandbox.validatePortToken).toHaveBeenCalledWith(8080, 'token12345678901');
172
+ expect(mockSandbox.validatePortToken).toHaveBeenCalledWith(
173
+ 8080,
174
+ 'token12345678901'
175
+ );
145
176
  });
146
177
 
147
178
  it('should reject requests with invalid token', async () => {
148
179
  vi.mocked(mockSandbox.validatePortToken as any).mockResolvedValue(false);
149
180
 
150
- const request = new Request('https://8080-sandbox-invalidtoken1234.example.com/ws', {
151
- headers: { 'Upgrade': 'websocket' },
152
- });
181
+ const request = new Request(
182
+ 'https://8080-sandbox-invalidtoken1234.example.com/ws',
183
+ {
184
+ headers: { Upgrade: 'websocket' }
185
+ }
186
+ );
153
187
 
154
188
  const response = await proxyToSandbox(request, mockEnv);
155
189
 
@@ -159,15 +193,18 @@ describe('proxyToSandbox - WebSocket Support', () => {
159
193
  const body = await response?.json();
160
194
  expect(body).toMatchObject({
161
195
  error: 'Access denied: Invalid token or port not exposed',
162
- code: 'INVALID_TOKEN',
196
+ code: 'INVALID_TOKEN'
163
197
  });
164
198
  });
165
199
 
166
200
  it('should reject reserved port 3000', async () => {
167
201
  // Port 3000 is reserved as control plane port and rejected by validatePort()
168
- const request = new Request('https://3000-sandbox-anytoken12345678.example.com/status', {
169
- method: 'GET',
170
- });
202
+ const request = new Request(
203
+ 'https://3000-sandbox-anytoken12345678.example.com/status',
204
+ {
205
+ method: 'GET'
206
+ }
207
+ );
171
208
 
172
209
  const response = await proxyToSandbox(request, mockEnv);
173
210
 
@@ -180,13 +217,19 @@ describe('proxyToSandbox - WebSocket Support', () => {
180
217
 
181
218
  describe('Port routing', () => {
182
219
  it('should route to correct port from subdomain', async () => {
183
- const request = new Request('https://9000-sandbox-token12345678901.example.com/api', {
184
- method: 'GET',
185
- });
220
+ const request = new Request(
221
+ 'https://9000-sandbox-token12345678901.example.com/api',
222
+ {
223
+ method: 'GET'
224
+ }
225
+ );
186
226
 
187
227
  await proxyToSandbox(request, mockEnv);
188
228
 
189
- expect(mockSandbox.validatePortToken).toHaveBeenCalledWith(9000, 'token12345678901');
229
+ expect(mockSandbox.validatePortToken).toHaveBeenCalledWith(
230
+ 9000,
231
+ 'token12345678901'
232
+ );
190
233
  });
191
234
  });
192
235
 
@@ -212,13 +255,18 @@ describe('proxyToSandbox - WebSocket Support', () => {
212
255
 
213
256
  describe('Error handling', () => {
214
257
  it('should handle errors during WebSocket routing', async () => {
215
- (mockSandbox.fetch as any).mockImplementation(() => Promise.reject(new Error('Connection failed')));
216
-
217
- const request = new Request('https://8080-sandbox-token12345678901.example.com/ws', {
218
- headers: {
219
- 'Upgrade': 'websocket',
220
- },
221
- });
258
+ (mockSandbox.fetch as any).mockImplementation(() =>
259
+ Promise.reject(new Error('Connection failed'))
260
+ );
261
+
262
+ const request = new Request(
263
+ 'https://8080-sandbox-token12345678901.example.com/ws',
264
+ {
265
+ headers: {
266
+ Upgrade: 'websocket'
267
+ }
268
+ }
269
+ );
222
270
 
223
271
  const response = await proxyToSandbox(request, mockEnv);
224
272
 
@@ -228,9 +276,13 @@ describe('proxyToSandbox - WebSocket Support', () => {
228
276
  });
229
277
 
230
278
  it('should handle errors during HTTP routing', async () => {
231
- (mockSandbox.containerFetch as any).mockImplementation(() => Promise.reject(new Error('Service error')));
279
+ (mockSandbox.containerFetch as any).mockImplementation(() =>
280
+ Promise.reject(new Error('Service error'))
281
+ );
232
282
 
233
- const request = new Request('https://8080-sandbox-token12345678901.example.com/api');
283
+ const request = new Request(
284
+ 'https://8080-sandbox-token12345678901.example.com/api'
285
+ );
234
286
 
235
287
  const response = await proxyToSandbox(request, mockEnv);
236
288