@cloudflare/sandbox 0.4.12 → 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.
- package/.turbo/turbo-build.log +13 -47
- package/CHANGELOG.md +38 -16
- package/Dockerfile +15 -9
- package/README.md +0 -1
- package/dist/index.d.ts +1889 -9
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3144 -65
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/clients/base-client.ts +39 -24
- package/src/clients/command-client.ts +8 -8
- package/src/clients/file-client.ts +31 -26
- package/src/clients/git-client.ts +3 -4
- package/src/clients/index.ts +12 -16
- package/src/clients/interpreter-client.ts +51 -47
- package/src/clients/port-client.ts +10 -10
- package/src/clients/process-client.ts +11 -8
- package/src/clients/sandbox-client.ts +2 -4
- package/src/clients/types.ts +6 -2
- package/src/clients/utility-client.ts +10 -6
- package/src/errors/adapter.ts +90 -32
- package/src/errors/classes.ts +189 -64
- package/src/errors/index.ts +9 -5
- package/src/file-stream.ts +11 -6
- package/src/index.ts +22 -15
- package/src/interpreter.ts +50 -41
- package/src/request-handler.ts +24 -21
- package/src/sandbox.ts +339 -149
- package/src/security.ts +21 -6
- package/src/sse-parser.ts +4 -3
- package/src/version.ts +1 -1
- package/tests/base-client.test.ts +116 -80
- package/tests/command-client.test.ts +149 -112
- package/tests/file-client.test.ts +309 -197
- package/tests/file-stream.test.ts +24 -20
- package/tests/get-sandbox.test.ts +10 -10
- package/tests/git-client.test.ts +188 -101
- package/tests/port-client.test.ts +100 -108
- package/tests/process-client.test.ts +204 -179
- package/tests/request-handler.test.ts +117 -65
- package/tests/sandbox.test.ts +219 -67
- package/tests/sse-parser.test.ts +17 -16
- package/tests/utility-client.test.ts +79 -72
- package/tsdown.config.ts +12 -0
- package/vitest.config.ts +6 -6
- package/dist/chunk-BFVUNTP4.js +0 -104
- package/dist/chunk-BFVUNTP4.js.map +0 -1
- package/dist/chunk-EKSWCBCA.js +0 -86
- package/dist/chunk-EKSWCBCA.js.map +0 -1
- package/dist/chunk-JXZMAU2C.js +0 -559
- package/dist/chunk-JXZMAU2C.js.map +0 -1
- package/dist/chunk-UJ3TV4M6.js +0 -7
- package/dist/chunk-UJ3TV4M6.js.map +0 -1
- package/dist/chunk-YE265ASX.js +0 -2484
- package/dist/chunk-YE265ASX.js.map +0 -1
- package/dist/chunk-Z532A7QC.js +0 -78
- package/dist/chunk-Z532A7QC.js.map +0 -1
- package/dist/file-stream.d.ts +0 -43
- package/dist/file-stream.js +0 -9
- package/dist/file-stream.js.map +0 -1
- package/dist/interpreter.d.ts +0 -33
- package/dist/interpreter.js +0 -8
- package/dist/interpreter.js.map +0 -1
- package/dist/request-handler.d.ts +0 -18
- package/dist/request-handler.js +0 -13
- package/dist/request-handler.js.map +0 -1
- package/dist/sandbox-CLZWpfGc.d.ts +0 -613
- package/dist/sandbox.d.ts +0 -4
- package/dist/sandbox.js +0 -13
- package/dist/sandbox.js.map +0 -1
- package/dist/security.d.ts +0 -31
- package/dist/security.js +0 -13
- package/dist/security.js.map +0 -1
- package/dist/sse-parser.d.ts +0 -28
- package/dist/sse-parser.js +0 -11
- package/dist/sse-parser.js.map +0 -1
- package/dist/version.d.ts +0 -8
- package/dist/version.js +0 -7
- package/dist/version.js.map +0 -1
|
@@ -6,16 +6,20 @@ import {
|
|
|
6
6
|
type ExecutionError,
|
|
7
7
|
type OutputMessage,
|
|
8
8
|
type Result,
|
|
9
|
-
ResultImpl
|
|
9
|
+
ResultImpl
|
|
10
10
|
} from '@repo/shared';
|
|
11
11
|
import type { ErrorResponse } from '../errors';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
createErrorFromResponse,
|
|
14
|
+
ErrorCode,
|
|
15
|
+
InterpreterNotReadyError
|
|
16
|
+
} from '../errors';
|
|
13
17
|
import { BaseHttpClient } from './base-client.js';
|
|
14
18
|
import type { HttpClientOptions } from './types.js';
|
|
15
19
|
|
|
16
20
|
// Streaming execution data from the server
|
|
17
21
|
interface StreamingExecutionData {
|
|
18
|
-
type:
|
|
22
|
+
type: 'result' | 'stdout' | 'stderr' | 'error' | 'execution_complete';
|
|
19
23
|
text?: string;
|
|
20
24
|
html?: string;
|
|
21
25
|
png?: string; // base64
|
|
@@ -27,13 +31,13 @@ interface StreamingExecutionData {
|
|
|
27
31
|
json?: unknown;
|
|
28
32
|
chart?: {
|
|
29
33
|
type:
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
34
|
+
| 'line'
|
|
35
|
+
| 'bar'
|
|
36
|
+
| 'scatter'
|
|
37
|
+
| 'pie'
|
|
38
|
+
| 'histogram'
|
|
39
|
+
| 'heatmap'
|
|
40
|
+
| 'unknown';
|
|
37
41
|
data: unknown;
|
|
38
42
|
options?: unknown;
|
|
39
43
|
};
|
|
@@ -62,14 +66,14 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
62
66
|
options: CreateContextOptions = {}
|
|
63
67
|
): Promise<CodeContext> {
|
|
64
68
|
return this.executeWithRetry(async () => {
|
|
65
|
-
const response = await this.doFetch(
|
|
66
|
-
method:
|
|
67
|
-
headers: {
|
|
69
|
+
const response = await this.doFetch('/api/contexts', {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
68
72
|
body: JSON.stringify({
|
|
69
|
-
language: options.language ||
|
|
70
|
-
cwd: options.cwd ||
|
|
71
|
-
env_vars: options.envVars
|
|
72
|
-
})
|
|
73
|
+
language: options.language || 'python',
|
|
74
|
+
cwd: options.cwd || '/workspace',
|
|
75
|
+
env_vars: options.envVars
|
|
76
|
+
})
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
if (!response.ok) {
|
|
@@ -87,7 +91,7 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
87
91
|
language: data.language,
|
|
88
92
|
cwd: data.cwd || '/workspace',
|
|
89
93
|
createdAt: new Date(data.timestamp),
|
|
90
|
-
lastUsed: new Date(data.timestamp)
|
|
94
|
+
lastUsed: new Date(data.timestamp)
|
|
91
95
|
};
|
|
92
96
|
});
|
|
93
97
|
}
|
|
@@ -100,18 +104,18 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
100
104
|
timeoutMs?: number
|
|
101
105
|
): Promise<void> {
|
|
102
106
|
return this.executeWithRetry(async () => {
|
|
103
|
-
const response = await this.doFetch(
|
|
104
|
-
method:
|
|
107
|
+
const response = await this.doFetch('/api/execute/code', {
|
|
108
|
+
method: 'POST',
|
|
105
109
|
headers: {
|
|
106
|
-
|
|
107
|
-
Accept:
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
Accept: 'text/event-stream'
|
|
108
112
|
},
|
|
109
113
|
body: JSON.stringify({
|
|
110
114
|
context_id: contextId,
|
|
111
115
|
code,
|
|
112
116
|
language,
|
|
113
117
|
...(timeoutMs !== undefined && { timeout_ms: timeoutMs })
|
|
114
|
-
})
|
|
118
|
+
})
|
|
115
119
|
});
|
|
116
120
|
|
|
117
121
|
if (!response.ok) {
|
|
@@ -120,7 +124,7 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
if (!response.body) {
|
|
123
|
-
throw new Error(
|
|
127
|
+
throw new Error('No response body for streaming execution');
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
// Process streaming response
|
|
@@ -132,9 +136,9 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
132
136
|
|
|
133
137
|
async listCodeContexts(): Promise<CodeContext[]> {
|
|
134
138
|
return this.executeWithRetry(async () => {
|
|
135
|
-
const response = await this.doFetch(
|
|
136
|
-
method:
|
|
137
|
-
headers: {
|
|
139
|
+
const response = await this.doFetch('/api/contexts', {
|
|
140
|
+
method: 'GET',
|
|
141
|
+
headers: { 'Content-Type': 'application/json' }
|
|
138
142
|
});
|
|
139
143
|
|
|
140
144
|
if (!response.ok) {
|
|
@@ -152,7 +156,7 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
152
156
|
language: ctx.language,
|
|
153
157
|
cwd: ctx.cwd || '/workspace',
|
|
154
158
|
createdAt: new Date(data.timestamp),
|
|
155
|
-
lastUsed: new Date(data.timestamp)
|
|
159
|
+
lastUsed: new Date(data.timestamp)
|
|
156
160
|
}));
|
|
157
161
|
});
|
|
158
162
|
}
|
|
@@ -160,8 +164,8 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
160
164
|
async deleteCodeContext(contextId: string): Promise<void> {
|
|
161
165
|
return this.executeWithRetry(async () => {
|
|
162
166
|
const response = await this.doFetch(`/api/contexts/${contextId}`, {
|
|
163
|
-
method:
|
|
164
|
-
headers: {
|
|
167
|
+
method: 'DELETE',
|
|
168
|
+
headers: { 'Content-Type': 'application/json' }
|
|
165
169
|
});
|
|
166
170
|
|
|
167
171
|
if (!response.ok) {
|
|
@@ -201,7 +205,7 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
201
205
|
}
|
|
202
206
|
}
|
|
203
207
|
|
|
204
|
-
throw lastError || new Error(
|
|
208
|
+
throw lastError || new Error('Execution failed after retries');
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
private isRetryableError(error: unknown): boolean {
|
|
@@ -211,8 +215,8 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
211
215
|
|
|
212
216
|
if (error instanceof Error) {
|
|
213
217
|
return (
|
|
214
|
-
error.message.includes(
|
|
215
|
-
error.message.includes(
|
|
218
|
+
error.message.includes('not ready') ||
|
|
219
|
+
error.message.includes('initializing')
|
|
216
220
|
);
|
|
217
221
|
}
|
|
218
222
|
|
|
@@ -221,7 +225,7 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
221
225
|
|
|
222
226
|
private async parseErrorResponse(response: Response): Promise<Error> {
|
|
223
227
|
try {
|
|
224
|
-
const errorData = await response.json() as ErrorResponse;
|
|
228
|
+
const errorData = (await response.json()) as ErrorResponse;
|
|
225
229
|
return createErrorFromResponse(errorData);
|
|
226
230
|
} catch {
|
|
227
231
|
// Fallback if response isn't JSON
|
|
@@ -240,7 +244,7 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
240
244
|
stream: ReadableStream<Uint8Array>
|
|
241
245
|
): AsyncGenerator<string> {
|
|
242
246
|
const reader = stream.getReader();
|
|
243
|
-
let buffer =
|
|
247
|
+
let buffer = '';
|
|
244
248
|
|
|
245
249
|
try {
|
|
246
250
|
while (true) {
|
|
@@ -250,11 +254,11 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
250
254
|
}
|
|
251
255
|
if (done) break;
|
|
252
256
|
|
|
253
|
-
let newlineIdx = buffer.indexOf(
|
|
257
|
+
let newlineIdx = buffer.indexOf('\n');
|
|
254
258
|
while (newlineIdx !== -1) {
|
|
255
259
|
yield buffer.slice(0, newlineIdx);
|
|
256
260
|
buffer = buffer.slice(newlineIdx + 1);
|
|
257
|
-
newlineIdx = buffer.indexOf(
|
|
261
|
+
newlineIdx = buffer.indexOf('\n');
|
|
258
262
|
}
|
|
259
263
|
}
|
|
260
264
|
|
|
@@ -282,25 +286,25 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
282
286
|
const data = JSON.parse(jsonData) as StreamingExecutionData;
|
|
283
287
|
|
|
284
288
|
switch (data.type) {
|
|
285
|
-
case
|
|
289
|
+
case 'stdout':
|
|
286
290
|
if (callbacks.onStdout && data.text) {
|
|
287
291
|
await callbacks.onStdout({
|
|
288
292
|
text: data.text,
|
|
289
|
-
timestamp: data.timestamp || Date.now()
|
|
293
|
+
timestamp: data.timestamp || Date.now()
|
|
290
294
|
});
|
|
291
295
|
}
|
|
292
296
|
break;
|
|
293
297
|
|
|
294
|
-
case
|
|
298
|
+
case 'stderr':
|
|
295
299
|
if (callbacks.onStderr && data.text) {
|
|
296
300
|
await callbacks.onStderr({
|
|
297
301
|
text: data.text,
|
|
298
|
-
timestamp: data.timestamp || Date.now()
|
|
302
|
+
timestamp: data.timestamp || Date.now()
|
|
299
303
|
});
|
|
300
304
|
}
|
|
301
305
|
break;
|
|
302
306
|
|
|
303
|
-
case
|
|
307
|
+
case 'result':
|
|
304
308
|
if (callbacks.onResult) {
|
|
305
309
|
// Create a ResultImpl instance from the raw data
|
|
306
310
|
const result = new ResultImpl(data);
|
|
@@ -308,17 +312,17 @@ export class InterpreterClient extends BaseHttpClient {
|
|
|
308
312
|
}
|
|
309
313
|
break;
|
|
310
314
|
|
|
311
|
-
case
|
|
315
|
+
case 'error':
|
|
312
316
|
if (callbacks.onError) {
|
|
313
317
|
await callbacks.onError({
|
|
314
|
-
name: data.ename ||
|
|
315
|
-
message: data.evalue ||
|
|
316
|
-
traceback: data.traceback || []
|
|
318
|
+
name: data.ename || 'Error',
|
|
319
|
+
message: data.evalue || 'Unknown error',
|
|
320
|
+
traceback: data.traceback || []
|
|
317
321
|
});
|
|
318
322
|
}
|
|
319
323
|
break;
|
|
320
324
|
|
|
321
|
-
case
|
|
325
|
+
case 'execution_complete':
|
|
322
326
|
// Signal completion - callbacks can handle cleanup if needed
|
|
323
327
|
break;
|
|
324
328
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
PortCloseResult,
|
|
3
3
|
PortExposeResult,
|
|
4
|
-
PortListResult
|
|
4
|
+
PortListResult
|
|
5
5
|
} from '@repo/shared';
|
|
6
6
|
import { BaseHttpClient } from './base-client';
|
|
7
7
|
import type { HttpClientOptions } from './types';
|
|
8
8
|
|
|
9
9
|
// Re-export for convenience
|
|
10
|
-
export type {
|
|
11
|
-
PortExposeResult,
|
|
12
|
-
PortCloseResult,
|
|
13
|
-
PortListResult,
|
|
14
|
-
};
|
|
10
|
+
export type { PortExposeResult, PortCloseResult, PortListResult };
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* Request interface for exposing ports
|
|
@@ -32,7 +28,6 @@ export interface UnexposePortRequest {
|
|
|
32
28
|
* Client for port management and preview URL operations
|
|
33
29
|
*/
|
|
34
30
|
export class PortClient extends BaseHttpClient {
|
|
35
|
-
|
|
36
31
|
/**
|
|
37
32
|
* Expose a port and get a preview URL
|
|
38
33
|
* @param port - Port number to expose
|
|
@@ -69,9 +64,14 @@ export class PortClient extends BaseHttpClient {
|
|
|
69
64
|
* @param port - Port number to unexpose
|
|
70
65
|
* @param sessionId - The session ID for this operation
|
|
71
66
|
*/
|
|
72
|
-
async unexposePort(
|
|
67
|
+
async unexposePort(
|
|
68
|
+
port: number,
|
|
69
|
+
sessionId: string
|
|
70
|
+
): Promise<PortCloseResult> {
|
|
73
71
|
try {
|
|
74
|
-
const url = `/api/exposed-ports/${port}?session=${encodeURIComponent(
|
|
72
|
+
const url = `/api/exposed-ports/${port}?session=${encodeURIComponent(
|
|
73
|
+
sessionId
|
|
74
|
+
)}`;
|
|
75
75
|
const response = await this.delete<PortCloseResult>(url);
|
|
76
76
|
|
|
77
77
|
this.logSuccess('Port unexposed', `${port}`);
|
|
@@ -102,4 +102,4 @@ export class PortClient extends BaseHttpClient {
|
|
|
102
102
|
throw error;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
}
|
|
105
|
+
}
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ProcessListResult,
|
|
6
6
|
ProcessLogsResult,
|
|
7
7
|
ProcessStartResult,
|
|
8
|
-
StartProcessRequest
|
|
8
|
+
StartProcessRequest
|
|
9
9
|
} from '@repo/shared';
|
|
10
10
|
import { BaseHttpClient } from './base-client';
|
|
11
11
|
import type { HttpClientOptions } from './types';
|
|
@@ -18,15 +18,13 @@ export type {
|
|
|
18
18
|
ProcessInfoResult,
|
|
19
19
|
ProcessKillResult,
|
|
20
20
|
ProcessLogsResult,
|
|
21
|
-
ProcessCleanupResult
|
|
21
|
+
ProcessCleanupResult
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
/**
|
|
26
25
|
* Client for background process management
|
|
27
26
|
*/
|
|
28
27
|
export class ProcessClient extends BaseHttpClient {
|
|
29
|
-
|
|
30
28
|
/**
|
|
31
29
|
* Start a background process
|
|
32
30
|
* @param command - Command to execute as a background process
|
|
@@ -42,7 +40,7 @@ export class ProcessClient extends BaseHttpClient {
|
|
|
42
40
|
const data: StartProcessRequest = {
|
|
43
41
|
command,
|
|
44
42
|
sessionId,
|
|
45
|
-
processId: options?.processId
|
|
43
|
+
processId: options?.processId
|
|
46
44
|
};
|
|
47
45
|
|
|
48
46
|
const response = await this.post<ProcessStartResult>(
|
|
@@ -70,7 +68,10 @@ export class ProcessClient extends BaseHttpClient {
|
|
|
70
68
|
const url = `/api/process/list`;
|
|
71
69
|
const response = await this.get<ProcessListResult>(url);
|
|
72
70
|
|
|
73
|
-
this.logSuccess(
|
|
71
|
+
this.logSuccess(
|
|
72
|
+
'Processes listed',
|
|
73
|
+
`${response.processes.length} processes`
|
|
74
|
+
);
|
|
74
75
|
return response;
|
|
75
76
|
} catch (error) {
|
|
76
77
|
this.logError('listProcesses', error);
|
|
@@ -157,11 +158,13 @@ export class ProcessClient extends BaseHttpClient {
|
|
|
157
158
|
* Stream logs from a specific process (sandbox-scoped, not session-scoped)
|
|
158
159
|
* @param processId - ID of the process to stream logs from
|
|
159
160
|
*/
|
|
160
|
-
async streamProcessLogs(
|
|
161
|
+
async streamProcessLogs(
|
|
162
|
+
processId: string
|
|
163
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
161
164
|
try {
|
|
162
165
|
const url = `/api/process/${processId}/stream`;
|
|
163
166
|
const response = await this.doFetch(url, {
|
|
164
|
-
method: 'GET'
|
|
167
|
+
method: 'GET'
|
|
165
168
|
});
|
|
166
169
|
|
|
167
170
|
const stream = await this.handleStreamResponse(response);
|
|
@@ -24,7 +24,7 @@ export class SandboxClient {
|
|
|
24
24
|
// Ensure baseUrl is provided for all clients
|
|
25
25
|
const clientOptions: HttpClientOptions = {
|
|
26
26
|
baseUrl: 'http://localhost:3000',
|
|
27
|
-
...options
|
|
27
|
+
...options
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
// Initialize all domain clients with shared options
|
|
@@ -36,6 +36,4 @@ export class SandboxClient {
|
|
|
36
36
|
this.interpreter = new InterpreterClient(clientOptions);
|
|
37
37
|
this.utils = new UtilityClient(clientOptions);
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
39
|
+
}
|
package/src/clients/types.ts
CHANGED
|
@@ -4,7 +4,11 @@ import type { Logger } from '@repo/shared';
|
|
|
4
4
|
* Minimal interface for container fetch functionality
|
|
5
5
|
*/
|
|
6
6
|
export interface ContainerStub {
|
|
7
|
-
containerFetch(
|
|
7
|
+
containerFetch(
|
|
8
|
+
url: string,
|
|
9
|
+
options: RequestInit,
|
|
10
|
+
port?: number
|
|
11
|
+
): Promise<Response>;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
/**
|
|
@@ -81,4 +85,4 @@ export type ResponseHandler<T> = (response: Response) => Promise<T>;
|
|
|
81
85
|
*/
|
|
82
86
|
export interface SessionRequest {
|
|
83
87
|
sessionId?: string;
|
|
84
|
-
}
|
|
88
|
+
}
|
|
@@ -45,14 +45,13 @@ export interface CreateSessionResponse extends BaseApiResponse {
|
|
|
45
45
|
* Client for health checks and utility operations
|
|
46
46
|
*/
|
|
47
47
|
export class UtilityClient extends BaseHttpClient {
|
|
48
|
-
|
|
49
48
|
/**
|
|
50
49
|
* Ping the sandbox to check if it's responsive
|
|
51
50
|
*/
|
|
52
51
|
async ping(): Promise<string> {
|
|
53
52
|
try {
|
|
54
53
|
const response = await this.get<PingResponse>('/api/ping');
|
|
55
|
-
|
|
54
|
+
|
|
56
55
|
this.logSuccess('Ping successful', response.message);
|
|
57
56
|
return response.message;
|
|
58
57
|
} catch (error) {
|
|
@@ -67,7 +66,7 @@ export class UtilityClient extends BaseHttpClient {
|
|
|
67
66
|
async getCommands(): Promise<string[]> {
|
|
68
67
|
try {
|
|
69
68
|
const response = await this.get<CommandsResponse>('/api/commands');
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
this.logSuccess(
|
|
72
71
|
'Commands retrieved',
|
|
73
72
|
`${response.count} commands available`
|
|
@@ -84,7 +83,9 @@ export class UtilityClient extends BaseHttpClient {
|
|
|
84
83
|
* Create a new execution session
|
|
85
84
|
* @param options - Session configuration (id, env, cwd)
|
|
86
85
|
*/
|
|
87
|
-
async createSession(
|
|
86
|
+
async createSession(
|
|
87
|
+
options: CreateSessionRequest
|
|
88
|
+
): Promise<CreateSessionResponse> {
|
|
88
89
|
try {
|
|
89
90
|
const response = await this.post<CreateSessionResponse>(
|
|
90
91
|
'/api/session/create',
|
|
@@ -112,8 +113,11 @@ export class UtilityClient extends BaseHttpClient {
|
|
|
112
113
|
} catch (error) {
|
|
113
114
|
// If version endpoint doesn't exist (old container), return 'unknown'
|
|
114
115
|
// This allows for backward compatibility
|
|
115
|
-
this.logger.debug(
|
|
116
|
+
this.logger.debug(
|
|
117
|
+
'Failed to get container version (may be old container)',
|
|
118
|
+
{ error }
|
|
119
|
+
);
|
|
116
120
|
return 'unknown';
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
|
-
}
|
|
123
|
+
}
|
package/src/errors/adapter.ts
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* No validation overhead since we control both sides
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
9
|
CodeExecutionContext,
|
|
10
10
|
CommandErrorContext,
|
|
11
11
|
CommandNotFoundContext,
|
|
12
|
-
ContextNotFoundContext,
|
|
12
|
+
ContextNotFoundContext,
|
|
13
|
+
ErrorResponse,
|
|
13
14
|
FileExistsContext,
|
|
14
15
|
FileNotFoundContext,
|
|
15
16
|
FileSystemContext,
|
|
@@ -25,7 +26,8 @@ import type {
|
|
|
25
26
|
PortNotExposedContext,
|
|
26
27
|
ProcessErrorContext,
|
|
27
28
|
ProcessNotFoundContext,
|
|
28
|
-
ValidationFailedContext
|
|
29
|
+
ValidationFailedContext
|
|
30
|
+
} from '@repo/shared/errors';
|
|
29
31
|
import { ErrorCode } from '@repo/shared/errors';
|
|
30
32
|
|
|
31
33
|
import {
|
|
@@ -56,7 +58,7 @@ import {
|
|
|
56
58
|
ProcessNotFoundError,
|
|
57
59
|
SandboxError,
|
|
58
60
|
ServiceNotRespondingError,
|
|
59
|
-
ValidationFailedError
|
|
61
|
+
ValidationFailedError
|
|
60
62
|
} from './classes';
|
|
61
63
|
|
|
62
64
|
/**
|
|
@@ -68,13 +70,19 @@ export function createErrorFromResponse(errorResponse: ErrorResponse): Error {
|
|
|
68
70
|
switch (errorResponse.code) {
|
|
69
71
|
// File System Errors
|
|
70
72
|
case ErrorCode.FILE_NOT_FOUND:
|
|
71
|
-
return new FileNotFoundError(
|
|
73
|
+
return new FileNotFoundError(
|
|
74
|
+
errorResponse as unknown as ErrorResponse<FileNotFoundContext>
|
|
75
|
+
);
|
|
72
76
|
|
|
73
77
|
case ErrorCode.FILE_EXISTS:
|
|
74
|
-
return new FileExistsError(
|
|
78
|
+
return new FileExistsError(
|
|
79
|
+
errorResponse as unknown as ErrorResponse<FileExistsContext>
|
|
80
|
+
);
|
|
75
81
|
|
|
76
82
|
case ErrorCode.PERMISSION_DENIED:
|
|
77
|
-
return new PermissionDeniedError(
|
|
83
|
+
return new PermissionDeniedError(
|
|
84
|
+
errorResponse as unknown as ErrorResponse<FileSystemContext>
|
|
85
|
+
);
|
|
78
86
|
|
|
79
87
|
case ErrorCode.IS_DIRECTORY:
|
|
80
88
|
case ErrorCode.NOT_DIRECTORY:
|
|
@@ -85,93 +93,143 @@ export function createErrorFromResponse(errorResponse: ErrorResponse): Error {
|
|
|
85
93
|
case ErrorCode.NAME_TOO_LONG:
|
|
86
94
|
case ErrorCode.TOO_MANY_LINKS:
|
|
87
95
|
case ErrorCode.FILESYSTEM_ERROR:
|
|
88
|
-
return new FileSystemError(
|
|
96
|
+
return new FileSystemError(
|
|
97
|
+
errorResponse as unknown as ErrorResponse<FileSystemContext>
|
|
98
|
+
);
|
|
89
99
|
|
|
90
100
|
// Command Errors
|
|
91
101
|
case ErrorCode.COMMAND_NOT_FOUND:
|
|
92
|
-
return new CommandNotFoundError(
|
|
102
|
+
return new CommandNotFoundError(
|
|
103
|
+
errorResponse as unknown as ErrorResponse<CommandNotFoundContext>
|
|
104
|
+
);
|
|
93
105
|
|
|
94
106
|
case ErrorCode.COMMAND_PERMISSION_DENIED:
|
|
95
107
|
case ErrorCode.COMMAND_EXECUTION_ERROR:
|
|
96
108
|
case ErrorCode.INVALID_COMMAND:
|
|
97
109
|
case ErrorCode.STREAM_START_ERROR:
|
|
98
|
-
return new CommandError(
|
|
110
|
+
return new CommandError(
|
|
111
|
+
errorResponse as unknown as ErrorResponse<CommandErrorContext>
|
|
112
|
+
);
|
|
99
113
|
|
|
100
114
|
// Process Errors
|
|
101
115
|
case ErrorCode.PROCESS_NOT_FOUND:
|
|
102
|
-
return new ProcessNotFoundError(
|
|
116
|
+
return new ProcessNotFoundError(
|
|
117
|
+
errorResponse as unknown as ErrorResponse<ProcessNotFoundContext>
|
|
118
|
+
);
|
|
103
119
|
|
|
104
120
|
case ErrorCode.PROCESS_PERMISSION_DENIED:
|
|
105
121
|
case ErrorCode.PROCESS_ERROR:
|
|
106
|
-
return new ProcessError(
|
|
122
|
+
return new ProcessError(
|
|
123
|
+
errorResponse as unknown as ErrorResponse<ProcessErrorContext>
|
|
124
|
+
);
|
|
107
125
|
|
|
108
126
|
// Port Errors
|
|
109
127
|
case ErrorCode.PORT_ALREADY_EXPOSED:
|
|
110
|
-
return new PortAlreadyExposedError(
|
|
128
|
+
return new PortAlreadyExposedError(
|
|
129
|
+
errorResponse as unknown as ErrorResponse<PortAlreadyExposedContext>
|
|
130
|
+
);
|
|
111
131
|
|
|
112
132
|
case ErrorCode.PORT_NOT_EXPOSED:
|
|
113
|
-
return new PortNotExposedError(
|
|
133
|
+
return new PortNotExposedError(
|
|
134
|
+
errorResponse as unknown as ErrorResponse<PortNotExposedContext>
|
|
135
|
+
);
|
|
114
136
|
|
|
115
137
|
case ErrorCode.INVALID_PORT_NUMBER:
|
|
116
138
|
case ErrorCode.INVALID_PORT:
|
|
117
|
-
return new InvalidPortError(
|
|
139
|
+
return new InvalidPortError(
|
|
140
|
+
errorResponse as unknown as ErrorResponse<InvalidPortContext>
|
|
141
|
+
);
|
|
118
142
|
|
|
119
143
|
case ErrorCode.SERVICE_NOT_RESPONDING:
|
|
120
|
-
return new ServiceNotRespondingError(
|
|
144
|
+
return new ServiceNotRespondingError(
|
|
145
|
+
errorResponse as unknown as ErrorResponse<PortErrorContext>
|
|
146
|
+
);
|
|
121
147
|
|
|
122
148
|
case ErrorCode.PORT_IN_USE:
|
|
123
|
-
return new PortInUseError(
|
|
149
|
+
return new PortInUseError(
|
|
150
|
+
errorResponse as unknown as ErrorResponse<PortErrorContext>
|
|
151
|
+
);
|
|
124
152
|
|
|
125
153
|
case ErrorCode.PORT_OPERATION_ERROR:
|
|
126
|
-
return new PortError(
|
|
154
|
+
return new PortError(
|
|
155
|
+
errorResponse as unknown as ErrorResponse<PortErrorContext>
|
|
156
|
+
);
|
|
127
157
|
|
|
128
158
|
case ErrorCode.CUSTOM_DOMAIN_REQUIRED:
|
|
129
|
-
return new CustomDomainRequiredError(
|
|
159
|
+
return new CustomDomainRequiredError(
|
|
160
|
+
errorResponse as unknown as ErrorResponse<InternalErrorContext>
|
|
161
|
+
);
|
|
130
162
|
|
|
131
163
|
// Git Errors
|
|
132
164
|
case ErrorCode.GIT_REPOSITORY_NOT_FOUND:
|
|
133
|
-
return new GitRepositoryNotFoundError(
|
|
165
|
+
return new GitRepositoryNotFoundError(
|
|
166
|
+
errorResponse as unknown as ErrorResponse<GitRepositoryNotFoundContext>
|
|
167
|
+
);
|
|
134
168
|
|
|
135
169
|
case ErrorCode.GIT_AUTH_FAILED:
|
|
136
|
-
return new GitAuthenticationError(
|
|
170
|
+
return new GitAuthenticationError(
|
|
171
|
+
errorResponse as unknown as ErrorResponse<GitAuthFailedContext>
|
|
172
|
+
);
|
|
137
173
|
|
|
138
174
|
case ErrorCode.GIT_BRANCH_NOT_FOUND:
|
|
139
|
-
return new GitBranchNotFoundError(
|
|
175
|
+
return new GitBranchNotFoundError(
|
|
176
|
+
errorResponse as unknown as ErrorResponse<GitBranchNotFoundContext>
|
|
177
|
+
);
|
|
140
178
|
|
|
141
179
|
case ErrorCode.GIT_NETWORK_ERROR:
|
|
142
|
-
return new GitNetworkError(
|
|
180
|
+
return new GitNetworkError(
|
|
181
|
+
errorResponse as unknown as ErrorResponse<GitErrorContext>
|
|
182
|
+
);
|
|
143
183
|
|
|
144
184
|
case ErrorCode.GIT_CLONE_FAILED:
|
|
145
|
-
return new GitCloneError(
|
|
185
|
+
return new GitCloneError(
|
|
186
|
+
errorResponse as unknown as ErrorResponse<GitErrorContext>
|
|
187
|
+
);
|
|
146
188
|
|
|
147
189
|
case ErrorCode.GIT_CHECKOUT_FAILED:
|
|
148
|
-
return new GitCheckoutError(
|
|
190
|
+
return new GitCheckoutError(
|
|
191
|
+
errorResponse as unknown as ErrorResponse<GitErrorContext>
|
|
192
|
+
);
|
|
149
193
|
|
|
150
194
|
case ErrorCode.INVALID_GIT_URL:
|
|
151
|
-
return new InvalidGitUrlError(
|
|
195
|
+
return new InvalidGitUrlError(
|
|
196
|
+
errorResponse as unknown as ErrorResponse<ValidationFailedContext>
|
|
197
|
+
);
|
|
152
198
|
|
|
153
199
|
case ErrorCode.GIT_OPERATION_FAILED:
|
|
154
|
-
return new GitError(
|
|
200
|
+
return new GitError(
|
|
201
|
+
errorResponse as unknown as ErrorResponse<GitErrorContext>
|
|
202
|
+
);
|
|
155
203
|
|
|
156
204
|
// Code Interpreter Errors
|
|
157
205
|
case ErrorCode.INTERPRETER_NOT_READY:
|
|
158
|
-
return new InterpreterNotReadyError(
|
|
206
|
+
return new InterpreterNotReadyError(
|
|
207
|
+
errorResponse as unknown as ErrorResponse<InterpreterNotReadyContext>
|
|
208
|
+
);
|
|
159
209
|
|
|
160
210
|
case ErrorCode.CONTEXT_NOT_FOUND:
|
|
161
|
-
return new ContextNotFoundError(
|
|
211
|
+
return new ContextNotFoundError(
|
|
212
|
+
errorResponse as unknown as ErrorResponse<ContextNotFoundContext>
|
|
213
|
+
);
|
|
162
214
|
|
|
163
215
|
case ErrorCode.CODE_EXECUTION_ERROR:
|
|
164
|
-
return new CodeExecutionError(
|
|
216
|
+
return new CodeExecutionError(
|
|
217
|
+
errorResponse as unknown as ErrorResponse<CodeExecutionContext>
|
|
218
|
+
);
|
|
165
219
|
|
|
166
220
|
// Validation Errors
|
|
167
221
|
case ErrorCode.VALIDATION_FAILED:
|
|
168
|
-
return new ValidationFailedError(
|
|
222
|
+
return new ValidationFailedError(
|
|
223
|
+
errorResponse as unknown as ErrorResponse<ValidationFailedContext>
|
|
224
|
+
);
|
|
169
225
|
|
|
170
226
|
// Generic Errors
|
|
171
227
|
case ErrorCode.INVALID_JSON_RESPONSE:
|
|
172
228
|
case ErrorCode.UNKNOWN_ERROR:
|
|
173
229
|
case ErrorCode.INTERNAL_ERROR:
|
|
174
|
-
return new SandboxError(
|
|
230
|
+
return new SandboxError(
|
|
231
|
+
errorResponse as unknown as ErrorResponse<InternalErrorContext>
|
|
232
|
+
);
|
|
175
233
|
|
|
176
234
|
default:
|
|
177
235
|
// Fallback for unknown error codes
|