@cloudflare/sandbox 0.3.6 → 0.4.1
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 +44 -0
- package/CHANGELOG.md +6 -8
- package/Dockerfile +88 -18
- package/README.md +89 -824
- package/dist/{chunk-JTKON2SH.js → chunk-BCJ7SF3Q.js} +9 -5
- package/dist/chunk-BCJ7SF3Q.js.map +1 -0
- package/dist/chunk-BFVUNTP4.js +104 -0
- package/dist/chunk-BFVUNTP4.js.map +1 -0
- package/dist/{chunk-NNGBXDMY.js → chunk-EKSWCBCA.js} +3 -6
- package/dist/chunk-EKSWCBCA.js.map +1 -0
- package/dist/chunk-HGF554LH.js +2236 -0
- package/dist/chunk-HGF554LH.js.map +1 -0
- package/dist/{chunk-6UAWTJ5S.js → chunk-Z532A7QC.js} +13 -20
- package/dist/{chunk-6UAWTJ5S.js.map → chunk-Z532A7QC.js.map} +1 -1
- package/dist/file-stream.d.ts +16 -38
- package/dist/file-stream.js +1 -2
- package/dist/index.d.ts +6 -5
- package/dist/index.js +35 -39
- package/dist/index.js.map +1 -1
- package/dist/interpreter.d.ts +3 -3
- package/dist/interpreter.js +2 -2
- package/dist/request-handler.d.ts +4 -3
- package/dist/request-handler.js +4 -7
- package/dist/sandbox-D9K2ypln.d.ts +583 -0
- package/dist/sandbox.d.ts +3 -3
- package/dist/sandbox.js +4 -7
- package/dist/security.d.ts +4 -3
- package/dist/security.js +3 -3
- package/dist/sse-parser.js +1 -1
- package/package.json +11 -5
- package/src/clients/base-client.ts +280 -0
- package/src/clients/command-client.ts +115 -0
- package/src/clients/file-client.ts +269 -0
- package/src/clients/git-client.ts +92 -0
- package/src/clients/index.ts +63 -0
- package/src/{interpreter-client.ts → clients/interpreter-client.ts} +148 -171
- package/src/clients/port-client.ts +105 -0
- package/src/clients/process-client.ts +177 -0
- package/src/clients/sandbox-client.ts +41 -0
- package/src/clients/types.ts +84 -0
- package/src/clients/utility-client.ts +94 -0
- package/src/errors/adapter.ts +180 -0
- package/src/errors/classes.ts +469 -0
- package/src/errors/index.ts +105 -0
- package/src/file-stream.ts +119 -117
- package/src/index.ts +81 -69
- package/src/interpreter.ts +17 -8
- package/src/request-handler.ts +69 -43
- package/src/sandbox.ts +694 -533
- package/src/security.ts +14 -23
- package/src/sse-parser.ts +4 -8
- package/startup.sh +3 -0
- package/tests/base-client.test.ts +328 -0
- package/tests/command-client.test.ts +407 -0
- package/tests/file-client.test.ts +643 -0
- package/tests/file-stream.test.ts +306 -0
- package/tests/git-client.test.ts +328 -0
- package/tests/port-client.test.ts +301 -0
- package/tests/process-client.test.ts +658 -0
- package/tests/sandbox.test.ts +465 -0
- package/tests/sse-parser.test.ts +290 -0
- package/tests/utility-client.test.ts +266 -0
- package/tests/wrangler.jsonc +35 -0
- package/tsconfig.json +9 -1
- package/vitest.config.ts +31 -0
- package/container_src/bun.lock +0 -76
- package/container_src/circuit-breaker.ts +0 -121
- package/container_src/control-process.ts +0 -784
- package/container_src/handler/exec.ts +0 -185
- package/container_src/handler/file.ts +0 -457
- package/container_src/handler/git.ts +0 -130
- package/container_src/handler/ports.ts +0 -314
- package/container_src/handler/process.ts +0 -568
- package/container_src/handler/session.ts +0 -92
- package/container_src/index.ts +0 -601
- package/container_src/interpreter-service.ts +0 -276
- package/container_src/isolation.ts +0 -1213
- package/container_src/mime-processor.ts +0 -255
- package/container_src/package.json +0 -18
- package/container_src/runtime/executors/javascript/node_executor.ts +0 -123
- package/container_src/runtime/executors/python/ipython_executor.py +0 -338
- package/container_src/runtime/executors/typescript/ts_executor.ts +0 -138
- package/container_src/runtime/process-pool.ts +0 -464
- package/container_src/shell-escape.ts +0 -42
- package/container_src/startup.sh +0 -11
- package/container_src/types.ts +0 -131
- package/dist/chunk-32UDXUPC.js +0 -671
- package/dist/chunk-32UDXUPC.js.map +0 -1
- package/dist/chunk-5DILEXGY.js +0 -85
- package/dist/chunk-5DILEXGY.js.map +0 -1
- package/dist/chunk-D3U63BZP.js +0 -240
- package/dist/chunk-D3U63BZP.js.map +0 -1
- package/dist/chunk-FXYPFGOZ.js +0 -129
- package/dist/chunk-FXYPFGOZ.js.map +0 -1
- package/dist/chunk-JTKON2SH.js.map +0 -1
- package/dist/chunk-NNGBXDMY.js.map +0 -1
- package/dist/chunk-SQLJNZ3K.js +0 -674
- package/dist/chunk-SQLJNZ3K.js.map +0 -1
- package/dist/chunk-W7TVRPBG.js +0 -108
- package/dist/chunk-W7TVRPBG.js.map +0 -1
- package/dist/client-B3RUab0s.d.ts +0 -225
- package/dist/client.d.ts +0 -4
- package/dist/client.js +0 -7
- package/dist/client.js.map +0 -1
- package/dist/errors.d.ts +0 -95
- package/dist/errors.js +0 -27
- package/dist/errors.js.map +0 -1
- package/dist/interpreter-client.d.ts +0 -4
- package/dist/interpreter-client.js +0 -9
- package/dist/interpreter-client.js.map +0 -1
- package/dist/interpreter-types.d.ts +0 -259
- package/dist/interpreter-types.js +0 -9
- package/dist/interpreter-types.js.map +0 -1
- package/dist/types.d.ts +0 -453
- package/dist/types.js +0 -45
- package/dist/types.js.map +0 -1
- package/src/client.ts +0 -1048
- package/src/errors.ts +0 -219
- package/src/interpreter-types.ts +0 -390
- package/src/types.ts +0 -571
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ProcessCleanupResult,
|
|
3
|
+
ProcessInfoResult,
|
|
4
|
+
ProcessKillResult,
|
|
5
|
+
ProcessListResult,
|
|
6
|
+
ProcessLogsResult,
|
|
7
|
+
ProcessStartResult,
|
|
8
|
+
StartProcessRequest,
|
|
9
|
+
} from '@repo/shared';
|
|
10
|
+
import { BaseHttpClient } from './base-client';
|
|
11
|
+
import type { HttpClientOptions } from './types';
|
|
12
|
+
|
|
13
|
+
// Re-export for convenience
|
|
14
|
+
export type {
|
|
15
|
+
StartProcessRequest,
|
|
16
|
+
ProcessStartResult,
|
|
17
|
+
ProcessListResult,
|
|
18
|
+
ProcessInfoResult,
|
|
19
|
+
ProcessKillResult,
|
|
20
|
+
ProcessLogsResult,
|
|
21
|
+
ProcessCleanupResult,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Client for background process management
|
|
27
|
+
*/
|
|
28
|
+
export class ProcessClient extends BaseHttpClient {
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Start a background process
|
|
32
|
+
* @param command - Command to execute as a background process
|
|
33
|
+
* @param sessionId - The session ID for this operation
|
|
34
|
+
* @param options - Optional settings (processId)
|
|
35
|
+
*/
|
|
36
|
+
async startProcess(
|
|
37
|
+
command: string,
|
|
38
|
+
sessionId: string,
|
|
39
|
+
options?: { processId?: string }
|
|
40
|
+
): Promise<ProcessStartResult> {
|
|
41
|
+
try {
|
|
42
|
+
const data: StartProcessRequest = {
|
|
43
|
+
command,
|
|
44
|
+
sessionId,
|
|
45
|
+
processId: options?.processId,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const response = await this.post<ProcessStartResult>(
|
|
49
|
+
'/api/process/start',
|
|
50
|
+
data
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
this.logSuccess(
|
|
54
|
+
'Process started',
|
|
55
|
+
`${command} (ID: ${response.processId})`
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return response;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
this.logError('startProcess', error);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* List all processes (sandbox-scoped, not session-scoped)
|
|
67
|
+
*/
|
|
68
|
+
async listProcesses(): Promise<ProcessListResult> {
|
|
69
|
+
try {
|
|
70
|
+
const url = `/api/process/list`;
|
|
71
|
+
const response = await this.get<ProcessListResult>(url);
|
|
72
|
+
|
|
73
|
+
this.logSuccess('Processes listed', `${response.processes.length} processes`);
|
|
74
|
+
return response;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.logError('listProcesses', error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get information about a specific process (sandbox-scoped, not session-scoped)
|
|
83
|
+
* @param processId - ID of the process to retrieve
|
|
84
|
+
*/
|
|
85
|
+
async getProcess(processId: string): Promise<ProcessInfoResult> {
|
|
86
|
+
try {
|
|
87
|
+
const url = `/api/process/${processId}`;
|
|
88
|
+
const response = await this.get<ProcessInfoResult>(url);
|
|
89
|
+
|
|
90
|
+
this.logSuccess('Process retrieved', `ID: ${processId}`);
|
|
91
|
+
return response;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
this.logError('getProcess', error);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Kill a specific process (sandbox-scoped, not session-scoped)
|
|
100
|
+
* @param processId - ID of the process to kill
|
|
101
|
+
*/
|
|
102
|
+
async killProcess(processId: string): Promise<ProcessKillResult> {
|
|
103
|
+
try {
|
|
104
|
+
const url = `/api/process/${processId}`;
|
|
105
|
+
const response = await this.delete<ProcessKillResult>(url);
|
|
106
|
+
|
|
107
|
+
this.logSuccess('Process killed', `ID: ${processId}`);
|
|
108
|
+
return response;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
this.logError('killProcess', error);
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Kill all running processes (sandbox-scoped, not session-scoped)
|
|
117
|
+
*/
|
|
118
|
+
async killAllProcesses(): Promise<ProcessCleanupResult> {
|
|
119
|
+
try {
|
|
120
|
+
const url = `/api/process/kill-all`;
|
|
121
|
+
const response = await this.delete<ProcessCleanupResult>(url);
|
|
122
|
+
|
|
123
|
+
this.logSuccess(
|
|
124
|
+
'All processes killed',
|
|
125
|
+
`${response.cleanedCount} processes terminated`
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
return response;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
this.logError('killAllProcesses', error);
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get logs from a specific process (sandbox-scoped, not session-scoped)
|
|
137
|
+
* @param processId - ID of the process to get logs from
|
|
138
|
+
*/
|
|
139
|
+
async getProcessLogs(processId: string): Promise<ProcessLogsResult> {
|
|
140
|
+
try {
|
|
141
|
+
const url = `/api/process/${processId}/logs`;
|
|
142
|
+
const response = await this.get<ProcessLogsResult>(url);
|
|
143
|
+
|
|
144
|
+
this.logSuccess(
|
|
145
|
+
'Process logs retrieved',
|
|
146
|
+
`ID: ${processId}, stdout: ${response.stdout.length} chars, stderr: ${response.stderr.length} chars`
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
return response;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
this.logError('getProcessLogs', error);
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Stream logs from a specific process (sandbox-scoped, not session-scoped)
|
|
158
|
+
* @param processId - ID of the process to stream logs from
|
|
159
|
+
*/
|
|
160
|
+
async streamProcessLogs(processId: string): Promise<ReadableStream<Uint8Array>> {
|
|
161
|
+
try {
|
|
162
|
+
const url = `/api/process/${processId}/stream`;
|
|
163
|
+
const response = await this.doFetch(url, {
|
|
164
|
+
method: 'GET',
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const stream = await this.handleStreamResponse(response);
|
|
168
|
+
|
|
169
|
+
this.logSuccess('Process log stream started', `ID: ${processId}`);
|
|
170
|
+
|
|
171
|
+
return stream;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
this.logError('streamProcessLogs', error);
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CommandClient } from './command-client';
|
|
2
|
+
import { FileClient } from './file-client';
|
|
3
|
+
import { GitClient } from './git-client';
|
|
4
|
+
import { InterpreterClient } from './interpreter-client';
|
|
5
|
+
import { PortClient } from './port-client';
|
|
6
|
+
import { ProcessClient } from './process-client';
|
|
7
|
+
import type { HttpClientOptions } from './types';
|
|
8
|
+
import { UtilityClient } from './utility-client';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Main sandbox client that composes all domain-specific clients
|
|
12
|
+
* Provides organized access to all sandbox functionality
|
|
13
|
+
*/
|
|
14
|
+
export class SandboxClient {
|
|
15
|
+
public readonly commands: CommandClient;
|
|
16
|
+
public readonly files: FileClient;
|
|
17
|
+
public readonly processes: ProcessClient;
|
|
18
|
+
public readonly ports: PortClient;
|
|
19
|
+
public readonly git: GitClient;
|
|
20
|
+
public readonly interpreter: InterpreterClient;
|
|
21
|
+
public readonly utils: UtilityClient;
|
|
22
|
+
|
|
23
|
+
constructor(options: HttpClientOptions) {
|
|
24
|
+
// Ensure baseUrl is provided for all clients
|
|
25
|
+
const clientOptions: HttpClientOptions = {
|
|
26
|
+
baseUrl: 'http://localhost:3000',
|
|
27
|
+
...options,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Initialize all domain clients with shared options
|
|
31
|
+
this.commands = new CommandClient(clientOptions);
|
|
32
|
+
this.files = new FileClient(clientOptions);
|
|
33
|
+
this.processes = new ProcessClient(clientOptions);
|
|
34
|
+
this.ports = new PortClient(clientOptions);
|
|
35
|
+
this.git = new GitClient(clientOptions);
|
|
36
|
+
this.interpreter = new InterpreterClient(clientOptions);
|
|
37
|
+
this.utils = new UtilityClient(clientOptions);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Logger } from '@repo/shared';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal interface for container fetch functionality
|
|
5
|
+
*/
|
|
6
|
+
export interface ContainerStub {
|
|
7
|
+
containerFetch(url: string, options: RequestInit, port?: number): Promise<Response>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Shared HTTP client configuration options
|
|
12
|
+
*/
|
|
13
|
+
export interface HttpClientOptions {
|
|
14
|
+
logger?: Logger;
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
port?: number;
|
|
17
|
+
stub?: ContainerStub;
|
|
18
|
+
onCommandComplete?: (
|
|
19
|
+
success: boolean,
|
|
20
|
+
exitCode: number,
|
|
21
|
+
stdout: string,
|
|
22
|
+
stderr: string,
|
|
23
|
+
command: string
|
|
24
|
+
) => void;
|
|
25
|
+
onError?: (error: string, command?: string) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Base response interface for all API responses
|
|
30
|
+
*/
|
|
31
|
+
export interface BaseApiResponse {
|
|
32
|
+
success: boolean;
|
|
33
|
+
timestamp: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Standard error response structure - matches BaseHandler.createErrorResponse()
|
|
38
|
+
*/
|
|
39
|
+
export interface ApiErrorResponse {
|
|
40
|
+
success: false;
|
|
41
|
+
error: string;
|
|
42
|
+
code: string;
|
|
43
|
+
details?: any;
|
|
44
|
+
timestamp: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validation error response structure - matches ValidationMiddleware
|
|
49
|
+
*/
|
|
50
|
+
export interface ValidationErrorResponse {
|
|
51
|
+
error: string;
|
|
52
|
+
message: string;
|
|
53
|
+
details?: any[];
|
|
54
|
+
timestamp: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Legacy error response interface - deprecated, use ApiErrorResponse
|
|
59
|
+
*/
|
|
60
|
+
export interface ErrorResponse {
|
|
61
|
+
error: string;
|
|
62
|
+
details?: string;
|
|
63
|
+
code?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* HTTP request configuration
|
|
68
|
+
*/
|
|
69
|
+
export interface RequestConfig extends RequestInit {
|
|
70
|
+
endpoint: string;
|
|
71
|
+
data?: Record<string, any>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Typed response handler
|
|
76
|
+
*/
|
|
77
|
+
export type ResponseHandler<T> = (response: Response) => Promise<T>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Common session-aware request interface
|
|
81
|
+
*/
|
|
82
|
+
export interface SessionRequest {
|
|
83
|
+
sessionId?: string;
|
|
84
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { BaseHttpClient } from './base-client';
|
|
2
|
+
import type { BaseApiResponse, HttpClientOptions } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Response interface for ping operations
|
|
6
|
+
*/
|
|
7
|
+
export interface PingResponse extends BaseApiResponse {
|
|
8
|
+
message: string;
|
|
9
|
+
uptime?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Response interface for getting available commands
|
|
14
|
+
*/
|
|
15
|
+
export interface CommandsResponse extends BaseApiResponse {
|
|
16
|
+
availableCommands: string[];
|
|
17
|
+
count: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Request interface for creating sessions
|
|
22
|
+
*/
|
|
23
|
+
export interface CreateSessionRequest {
|
|
24
|
+
id: string;
|
|
25
|
+
env?: Record<string, string>;
|
|
26
|
+
cwd?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Response interface for creating sessions
|
|
31
|
+
*/
|
|
32
|
+
export interface CreateSessionResponse extends BaseApiResponse {
|
|
33
|
+
id: string;
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Client for health checks and utility operations
|
|
39
|
+
*/
|
|
40
|
+
export class UtilityClient extends BaseHttpClient {
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Ping the sandbox to check if it's responsive
|
|
44
|
+
*/
|
|
45
|
+
async ping(): Promise<string> {
|
|
46
|
+
try {
|
|
47
|
+
const response = await this.get<PingResponse>('/api/ping');
|
|
48
|
+
|
|
49
|
+
this.logSuccess('Ping successful', response.message);
|
|
50
|
+
return response.message;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
this.logError('ping', error);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get list of available commands in the sandbox environment
|
|
59
|
+
*/
|
|
60
|
+
async getCommands(): Promise<string[]> {
|
|
61
|
+
try {
|
|
62
|
+
const response = await this.get<CommandsResponse>('/api/commands');
|
|
63
|
+
|
|
64
|
+
this.logSuccess(
|
|
65
|
+
'Commands retrieved',
|
|
66
|
+
`${response.count} commands available`
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
return response.availableCommands;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
this.logError('getCommands', error);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a new execution session
|
|
78
|
+
* @param options - Session configuration (id, env, cwd)
|
|
79
|
+
*/
|
|
80
|
+
async createSession(options: CreateSessionRequest): Promise<CreateSessionResponse> {
|
|
81
|
+
try {
|
|
82
|
+
const response = await this.post<CreateSessionResponse>(
|
|
83
|
+
'/api/session/create',
|
|
84
|
+
options
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
this.logSuccess('Session created', `ID: ${options.id}`);
|
|
88
|
+
return response;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
this.logError('createSession', error);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error adapter that converts ErrorResponse to appropriate Error class
|
|
3
|
+
*
|
|
4
|
+
* Simple switch statement - we trust the container sends correct context
|
|
5
|
+
* No validation overhead since we control both sides
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
CodeExecutionContext,
|
|
10
|
+
CommandErrorContext,
|
|
11
|
+
CommandNotFoundContext,
|
|
12
|
+
ContextNotFoundContext,ErrorResponse,
|
|
13
|
+
FileExistsContext,
|
|
14
|
+
FileNotFoundContext,
|
|
15
|
+
FileSystemContext,
|
|
16
|
+
GitAuthFailedContext,
|
|
17
|
+
GitBranchNotFoundContext,
|
|
18
|
+
GitErrorContext,
|
|
19
|
+
GitRepositoryNotFoundContext,
|
|
20
|
+
InternalErrorContext,
|
|
21
|
+
InterpreterNotReadyContext,
|
|
22
|
+
InvalidPortContext,
|
|
23
|
+
PortAlreadyExposedContext,
|
|
24
|
+
PortErrorContext,
|
|
25
|
+
PortNotExposedContext,
|
|
26
|
+
ProcessErrorContext,
|
|
27
|
+
ProcessNotFoundContext,
|
|
28
|
+
ValidationFailedContext,} from '@repo/shared/errors';
|
|
29
|
+
import { ErrorCode } from '@repo/shared/errors';
|
|
30
|
+
|
|
31
|
+
import {
|
|
32
|
+
CodeExecutionError,
|
|
33
|
+
CommandError,
|
|
34
|
+
CommandNotFoundError,
|
|
35
|
+
ContextNotFoundError,
|
|
36
|
+
CustomDomainRequiredError,
|
|
37
|
+
FileExistsError,
|
|
38
|
+
FileNotFoundError,
|
|
39
|
+
FileSystemError,
|
|
40
|
+
GitAuthenticationError,
|
|
41
|
+
GitBranchNotFoundError,
|
|
42
|
+
GitCheckoutError,
|
|
43
|
+
GitCloneError,
|
|
44
|
+
GitError,
|
|
45
|
+
GitNetworkError,
|
|
46
|
+
GitRepositoryNotFoundError,
|
|
47
|
+
InterpreterNotReadyError,
|
|
48
|
+
InvalidGitUrlError,
|
|
49
|
+
InvalidPortError,
|
|
50
|
+
PermissionDeniedError,
|
|
51
|
+
PortAlreadyExposedError,
|
|
52
|
+
PortError,
|
|
53
|
+
PortInUseError,
|
|
54
|
+
PortNotExposedError,
|
|
55
|
+
ProcessError,
|
|
56
|
+
ProcessNotFoundError,
|
|
57
|
+
SandboxError,
|
|
58
|
+
ServiceNotRespondingError,
|
|
59
|
+
ValidationFailedError,
|
|
60
|
+
} from './classes';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Convert ErrorResponse to appropriate Error class
|
|
64
|
+
* Simple switch statement - we trust the container sends correct context
|
|
65
|
+
*/
|
|
66
|
+
export function createErrorFromResponse(errorResponse: ErrorResponse): Error {
|
|
67
|
+
// We trust the container sends correct context, use type assertions
|
|
68
|
+
switch (errorResponse.code) {
|
|
69
|
+
// File System Errors
|
|
70
|
+
case ErrorCode.FILE_NOT_FOUND:
|
|
71
|
+
return new FileNotFoundError(errorResponse as unknown as ErrorResponse<FileNotFoundContext>);
|
|
72
|
+
|
|
73
|
+
case ErrorCode.FILE_EXISTS:
|
|
74
|
+
return new FileExistsError(errorResponse as unknown as ErrorResponse<FileExistsContext>);
|
|
75
|
+
|
|
76
|
+
case ErrorCode.PERMISSION_DENIED:
|
|
77
|
+
return new PermissionDeniedError(errorResponse as unknown as ErrorResponse<FileSystemContext>);
|
|
78
|
+
|
|
79
|
+
case ErrorCode.IS_DIRECTORY:
|
|
80
|
+
case ErrorCode.NOT_DIRECTORY:
|
|
81
|
+
case ErrorCode.NO_SPACE:
|
|
82
|
+
case ErrorCode.TOO_MANY_FILES:
|
|
83
|
+
case ErrorCode.RESOURCE_BUSY:
|
|
84
|
+
case ErrorCode.READ_ONLY:
|
|
85
|
+
case ErrorCode.NAME_TOO_LONG:
|
|
86
|
+
case ErrorCode.TOO_MANY_LINKS:
|
|
87
|
+
case ErrorCode.FILESYSTEM_ERROR:
|
|
88
|
+
return new FileSystemError(errorResponse as unknown as ErrorResponse<FileSystemContext>);
|
|
89
|
+
|
|
90
|
+
// Command Errors
|
|
91
|
+
case ErrorCode.COMMAND_NOT_FOUND:
|
|
92
|
+
return new CommandNotFoundError(errorResponse as unknown as ErrorResponse<CommandNotFoundContext>);
|
|
93
|
+
|
|
94
|
+
case ErrorCode.COMMAND_PERMISSION_DENIED:
|
|
95
|
+
case ErrorCode.COMMAND_EXECUTION_ERROR:
|
|
96
|
+
case ErrorCode.INVALID_COMMAND:
|
|
97
|
+
case ErrorCode.STREAM_START_ERROR:
|
|
98
|
+
return new CommandError(errorResponse as unknown as ErrorResponse<CommandErrorContext>);
|
|
99
|
+
|
|
100
|
+
// Process Errors
|
|
101
|
+
case ErrorCode.PROCESS_NOT_FOUND:
|
|
102
|
+
return new ProcessNotFoundError(errorResponse as unknown as ErrorResponse<ProcessNotFoundContext>);
|
|
103
|
+
|
|
104
|
+
case ErrorCode.PROCESS_PERMISSION_DENIED:
|
|
105
|
+
case ErrorCode.PROCESS_ERROR:
|
|
106
|
+
return new ProcessError(errorResponse as unknown as ErrorResponse<ProcessErrorContext>);
|
|
107
|
+
|
|
108
|
+
// Port Errors
|
|
109
|
+
case ErrorCode.PORT_ALREADY_EXPOSED:
|
|
110
|
+
return new PortAlreadyExposedError(errorResponse as unknown as ErrorResponse<PortAlreadyExposedContext>);
|
|
111
|
+
|
|
112
|
+
case ErrorCode.PORT_NOT_EXPOSED:
|
|
113
|
+
return new PortNotExposedError(errorResponse as unknown as ErrorResponse<PortNotExposedContext>);
|
|
114
|
+
|
|
115
|
+
case ErrorCode.INVALID_PORT_NUMBER:
|
|
116
|
+
case ErrorCode.INVALID_PORT:
|
|
117
|
+
return new InvalidPortError(errorResponse as unknown as ErrorResponse<InvalidPortContext>);
|
|
118
|
+
|
|
119
|
+
case ErrorCode.SERVICE_NOT_RESPONDING:
|
|
120
|
+
return new ServiceNotRespondingError(errorResponse as unknown as ErrorResponse<PortErrorContext>);
|
|
121
|
+
|
|
122
|
+
case ErrorCode.PORT_IN_USE:
|
|
123
|
+
return new PortInUseError(errorResponse as unknown as ErrorResponse<PortErrorContext>);
|
|
124
|
+
|
|
125
|
+
case ErrorCode.PORT_OPERATION_ERROR:
|
|
126
|
+
return new PortError(errorResponse as unknown as ErrorResponse<PortErrorContext>);
|
|
127
|
+
|
|
128
|
+
case ErrorCode.CUSTOM_DOMAIN_REQUIRED:
|
|
129
|
+
return new CustomDomainRequiredError(errorResponse as unknown as ErrorResponse<InternalErrorContext>);
|
|
130
|
+
|
|
131
|
+
// Git Errors
|
|
132
|
+
case ErrorCode.GIT_REPOSITORY_NOT_FOUND:
|
|
133
|
+
return new GitRepositoryNotFoundError(errorResponse as unknown as ErrorResponse<GitRepositoryNotFoundContext>);
|
|
134
|
+
|
|
135
|
+
case ErrorCode.GIT_AUTH_FAILED:
|
|
136
|
+
return new GitAuthenticationError(errorResponse as unknown as ErrorResponse<GitAuthFailedContext>);
|
|
137
|
+
|
|
138
|
+
case ErrorCode.GIT_BRANCH_NOT_FOUND:
|
|
139
|
+
return new GitBranchNotFoundError(errorResponse as unknown as ErrorResponse<GitBranchNotFoundContext>);
|
|
140
|
+
|
|
141
|
+
case ErrorCode.GIT_NETWORK_ERROR:
|
|
142
|
+
return new GitNetworkError(errorResponse as unknown as ErrorResponse<GitErrorContext>);
|
|
143
|
+
|
|
144
|
+
case ErrorCode.GIT_CLONE_FAILED:
|
|
145
|
+
return new GitCloneError(errorResponse as unknown as ErrorResponse<GitErrorContext>);
|
|
146
|
+
|
|
147
|
+
case ErrorCode.GIT_CHECKOUT_FAILED:
|
|
148
|
+
return new GitCheckoutError(errorResponse as unknown as ErrorResponse<GitErrorContext>);
|
|
149
|
+
|
|
150
|
+
case ErrorCode.INVALID_GIT_URL:
|
|
151
|
+
return new InvalidGitUrlError(errorResponse as unknown as ErrorResponse<ValidationFailedContext>);
|
|
152
|
+
|
|
153
|
+
case ErrorCode.GIT_OPERATION_FAILED:
|
|
154
|
+
return new GitError(errorResponse as unknown as ErrorResponse<GitErrorContext>);
|
|
155
|
+
|
|
156
|
+
// Code Interpreter Errors
|
|
157
|
+
case ErrorCode.INTERPRETER_NOT_READY:
|
|
158
|
+
return new InterpreterNotReadyError(errorResponse as unknown as ErrorResponse<InterpreterNotReadyContext>);
|
|
159
|
+
|
|
160
|
+
case ErrorCode.CONTEXT_NOT_FOUND:
|
|
161
|
+
return new ContextNotFoundError(errorResponse as unknown as ErrorResponse<ContextNotFoundContext>);
|
|
162
|
+
|
|
163
|
+
case ErrorCode.CODE_EXECUTION_ERROR:
|
|
164
|
+
return new CodeExecutionError(errorResponse as unknown as ErrorResponse<CodeExecutionContext>);
|
|
165
|
+
|
|
166
|
+
// Validation Errors
|
|
167
|
+
case ErrorCode.VALIDATION_FAILED:
|
|
168
|
+
return new ValidationFailedError(errorResponse as unknown as ErrorResponse<ValidationFailedContext>);
|
|
169
|
+
|
|
170
|
+
// Generic Errors
|
|
171
|
+
case ErrorCode.INVALID_JSON_RESPONSE:
|
|
172
|
+
case ErrorCode.UNKNOWN_ERROR:
|
|
173
|
+
case ErrorCode.INTERNAL_ERROR:
|
|
174
|
+
return new SandboxError(errorResponse as unknown as ErrorResponse<InternalErrorContext>);
|
|
175
|
+
|
|
176
|
+
default:
|
|
177
|
+
// Fallback for unknown error codes
|
|
178
|
+
return new SandboxError(errorResponse);
|
|
179
|
+
}
|
|
180
|
+
}
|