@cloudflare/sandbox 0.0.0-6a2c669 → 0.0.0-6c54d07
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/CHANGELOG.md +215 -0
- package/Dockerfile +118 -55
- package/README.md +162 -0
- package/dist/chunk-BFVUNTP4.js +104 -0
- package/dist/chunk-BFVUNTP4.js.map +1 -0
- package/dist/chunk-EKSWCBCA.js +86 -0
- package/dist/chunk-EKSWCBCA.js.map +1 -0
- package/dist/chunk-JXZMAU2C.js +559 -0
- package/dist/chunk-JXZMAU2C.js.map +1 -0
- package/dist/chunk-KWOEDJUN.js +7 -0
- package/dist/chunk-KWOEDJUN.js.map +1 -0
- package/dist/chunk-Y52QYTSM.js +2420 -0
- package/dist/chunk-Y52QYTSM.js.map +1 -0
- package/dist/chunk-Z532A7QC.js +78 -0
- package/dist/chunk-Z532A7QC.js.map +1 -0
- package/dist/file-stream.d.ts +43 -0
- package/dist/file-stream.js +9 -0
- package/dist/file-stream.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/interpreter.d.ts +33 -0
- package/dist/interpreter.js +8 -0
- package/dist/interpreter.js.map +1 -0
- package/dist/request-handler.d.ts +18 -0
- package/dist/request-handler.js +13 -0
- package/dist/request-handler.js.map +1 -0
- package/dist/sandbox-DMlNr93l.d.ts +596 -0
- package/dist/sandbox.d.ts +4 -0
- package/dist/sandbox.js +13 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/security.d.ts +31 -0
- package/dist/security.js +13 -0
- package/dist/security.js.map +1 -0
- package/dist/sse-parser.d.ts +28 -0
- package/dist/sse-parser.js +11 -0
- package/dist/sse-parser.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +13 -4
- 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 +64 -0
- package/src/clients/interpreter-client.ts +329 -0
- 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 +119 -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 +164 -0
- package/src/index.ts +85 -12
- package/src/interpreter.ts +159 -0
- package/src/request-handler.ts +69 -43
- package/src/sandbox.ts +642 -290
- package/src/security.ts +14 -23
- package/src/sse-parser.ts +4 -8
- package/src/version.ts +6 -0
- 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/get-sandbox.test.ts +110 -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 +332 -0
- package/tests/version.test.ts +16 -0
- package/tests/wrangler.jsonc +35 -0
- package/tsconfig.json +9 -1
- package/vitest.config.ts +31 -0
- package/container_src/handler/exec.ts +0 -337
- package/container_src/handler/file.ts +0 -844
- package/container_src/handler/git.ts +0 -182
- package/container_src/handler/ports.ts +0 -314
- package/container_src/handler/process.ts +0 -640
- package/container_src/index.ts +0 -361
- package/container_src/package.json +0 -9
- package/container_src/types.ts +0 -103
- package/src/client.ts +0 -1038
- package/src/types.ts +0 -386
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/file-stream.ts"],"sourcesContent":["import type { FileChunk, FileMetadata, FileStreamEvent } from '@repo/shared';\n\n/**\n * Parse SSE (Server-Sent Events) lines from a stream\n */\nasync function* parseSSE(stream: ReadableStream<Uint8Array>): AsyncGenerator<FileStreamEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in the buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6); // Remove 'data: ' prefix\n try {\n const event = JSON.parse(data) as FileStreamEvent;\n yield event;\n } catch {\n // Skip invalid JSON events and continue processing\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Stream a file from the sandbox with automatic base64 decoding for binary files\n *\n * @param stream - The ReadableStream from readFileStream()\n * @returns AsyncGenerator that yields FileChunk (string for text, Uint8Array for binary)\n *\n * @example\n * ```ts\n * const stream = await sandbox.readFileStream('/path/to/file.png');\n * for await (const chunk of streamFile(stream)) {\n * if (chunk instanceof Uint8Array) {\n * // Binary chunk\n * console.log('Binary chunk:', chunk.length, 'bytes');\n * } else {\n * // Text chunk\n * console.log('Text chunk:', chunk);\n * }\n * }\n * ```\n */\nexport async function* streamFile(stream: ReadableStream<Uint8Array>): AsyncGenerator<FileChunk, FileMetadata> {\n let metadata: FileMetadata | null = null;\n\n for await (const event of parseSSE(stream)) {\n switch (event.type) {\n case 'metadata':\n metadata = {\n mimeType: event.mimeType,\n size: event.size,\n isBinary: event.isBinary,\n encoding: event.encoding,\n };\n break;\n\n case 'chunk':\n if (!metadata) {\n throw new Error('Received chunk before metadata');\n }\n\n if (metadata.isBinary && metadata.encoding === 'base64') {\n // Decode base64 to Uint8Array for binary files\n const binaryString = atob(event.data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n yield bytes;\n } else {\n // Text files - yield as-is\n yield event.data;\n }\n break;\n\n case 'complete':\n if (!metadata) {\n throw new Error('Stream completed without metadata');\n }\n return metadata;\n\n case 'error':\n throw new Error(`File streaming error: ${event.error}`);\n }\n }\n\n throw new Error('Stream ended unexpectedly');\n}\n\n/**\n * Collect an entire file into memory from a stream\n *\n * @param stream - The ReadableStream from readFileStream()\n * @returns Object containing the file content and metadata\n *\n * @example\n * ```ts\n * const stream = await sandbox.readFileStream('/path/to/file.txt');\n * const { content, metadata } = await collectFile(stream);\n * console.log('Content:', content);\n * console.log('MIME type:', metadata.mimeType);\n * ```\n */\nexport async function collectFile(stream: ReadableStream<Uint8Array>): Promise<{\n content: string | Uint8Array;\n metadata: FileMetadata;\n}> {\n const chunks: Array<string | Uint8Array> = [];\n\n // Iterate through the generator and get the return value (metadata)\n const generator = streamFile(stream);\n let result = await generator.next();\n\n while (!result.done) {\n chunks.push(result.value);\n result = await generator.next();\n }\n\n const metadata = result.value;\n\n if (!metadata) {\n throw new Error('Failed to get file metadata');\n }\n\n // Combine chunks based on type\n if (metadata.isBinary) {\n // Binary file - combine Uint8Arrays\n const totalLength = chunks.reduce((sum, chunk) =>\n sum + (chunk instanceof Uint8Array ? chunk.length : 0), 0\n );\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n if (chunk instanceof Uint8Array) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n }\n return { content: combined, metadata };\n } else {\n // Text file - combine strings\n const combined = chunks.filter(c => typeof c === 'string').join('');\n return { content: combined, metadata };\n }\n}\n"],"mappings":";AAKA,gBAAgB,SAAS,QAAqE;AAC5F,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,MAAM;AACR;AAAA,MACF;AAEA,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,YAAM,QAAQ,OAAO,MAAM,IAAI;AAG/B,eAAS,MAAM,IAAI,KAAK;AAExB,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,gBAAM,OAAO,KAAK,MAAM,CAAC;AACzB,cAAI;AACF,kBAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,kBAAM;AAAA,UACR,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AAsBA,gBAAuB,WAAW,QAA6E;AAC7G,MAAI,WAAgC;AAEpC,mBAAiB,SAAS,SAAS,MAAM,GAAG;AAC1C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,mBAAW;AAAA,UACT,UAAU,MAAM;AAAA,UAChB,MAAM,MAAM;AAAA,UACZ,UAAU,MAAM;AAAA,UAChB,UAAU,MAAM;AAAA,QAClB;AACA;AAAA,MAEF,KAAK;AACH,YAAI,CAAC,UAAU;AACb,gBAAM,IAAI,MAAM,gCAAgC;AAAA,QAClD;AAEA,YAAI,SAAS,YAAY,SAAS,aAAa,UAAU;AAEvD,gBAAM,eAAe,KAAK,MAAM,IAAI;AACpC,gBAAM,QAAQ,IAAI,WAAW,aAAa,MAAM;AAChD,mBAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,kBAAM,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,UACtC;AACA,gBAAM;AAAA,QACR,OAAO;AAEL,gBAAM,MAAM;AAAA,QACd;AACA;AAAA,MAEF,KAAK;AACH,YAAI,CAAC,UAAU;AACb,gBAAM,IAAI,MAAM,mCAAmC;AAAA,QACrD;AACA,eAAO;AAAA,MAET,KAAK;AACH,cAAM,IAAI,MAAM,yBAAyB,MAAM,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,2BAA2B;AAC7C;AAgBA,eAAsB,YAAY,QAG/B;AACD,QAAM,SAAqC,CAAC;AAG5C,QAAM,YAAY,WAAW,MAAM;AACnC,MAAI,SAAS,MAAM,UAAU,KAAK;AAElC,SAAO,CAAC,OAAO,MAAM;AACnB,WAAO,KAAK,OAAO,KAAK;AACxB,aAAS,MAAM,UAAU,KAAK;AAAA,EAChC;AAEA,QAAM,WAAW,OAAO;AAExB,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AAGA,MAAI,SAAS,UAAU;AAErB,UAAM,cAAc,OAAO;AAAA,MAAO,CAAC,KAAK,UACtC,OAAO,iBAAiB,aAAa,MAAM,SAAS;AAAA,MAAI;AAAA,IAC1D;AACA,UAAM,WAAW,IAAI,WAAW,WAAW;AAC3C,QAAI,SAAS;AACb,eAAW,SAAS,QAAQ;AAC1B,UAAI,iBAAiB,YAAY;AAC/B,iBAAS,IAAI,OAAO,MAAM;AAC1B,kBAAU,MAAM;AAAA,MAClB;AAAA,IACF;AACA,WAAO,EAAE,SAAS,UAAU,SAAS;AAAA,EACvC,OAAO;AAEL,UAAM,WAAW,OAAO,OAAO,OAAK,OAAO,MAAM,QAAQ,EAAE,KAAK,EAAE;AAClE,WAAO,EAAE,SAAS,UAAU,SAAS;AAAA,EACvC;AACF;","names":[]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// src/sse-parser.ts
|
|
2
|
+
async function* parseSSEStream(stream, signal) {
|
|
3
|
+
const reader = stream.getReader();
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
let buffer = "";
|
|
6
|
+
try {
|
|
7
|
+
while (true) {
|
|
8
|
+
if (signal?.aborted) {
|
|
9
|
+
throw new Error("Operation was aborted");
|
|
10
|
+
}
|
|
11
|
+
const { done, value } = await reader.read();
|
|
12
|
+
if (done) break;
|
|
13
|
+
buffer += decoder.decode(value, { stream: true });
|
|
14
|
+
const lines = buffer.split("\n");
|
|
15
|
+
buffer = lines.pop() || "";
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
if (line.trim() === "") continue;
|
|
18
|
+
if (line.startsWith("data: ")) {
|
|
19
|
+
const data = line.substring(6);
|
|
20
|
+
if (data === "[DONE]" || data.trim() === "") continue;
|
|
21
|
+
try {
|
|
22
|
+
const event = JSON.parse(data);
|
|
23
|
+
yield event;
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (buffer.trim() && buffer.startsWith("data: ")) {
|
|
30
|
+
const data = buffer.substring(6);
|
|
31
|
+
if (data !== "[DONE]" && data.trim()) {
|
|
32
|
+
try {
|
|
33
|
+
const event = JSON.parse(data);
|
|
34
|
+
yield event;
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} finally {
|
|
40
|
+
reader.releaseLock();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function* responseToAsyncIterable(response, signal) {
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`Response not ok: ${response.status} ${response.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
if (!response.body) {
|
|
48
|
+
throw new Error("No response body");
|
|
49
|
+
}
|
|
50
|
+
yield* parseSSEStream(response.body, signal);
|
|
51
|
+
}
|
|
52
|
+
function asyncIterableToSSEStream(events, options) {
|
|
53
|
+
const encoder = new TextEncoder();
|
|
54
|
+
const serialize = options?.serialize || JSON.stringify;
|
|
55
|
+
return new ReadableStream({
|
|
56
|
+
async start(controller) {
|
|
57
|
+
try {
|
|
58
|
+
for await (const event of events) {
|
|
59
|
+
if (options?.signal?.aborted) {
|
|
60
|
+
controller.error(new Error("Operation was aborted"));
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
const data = serialize(event);
|
|
64
|
+
const sseEvent = `data: ${data}
|
|
65
|
+
|
|
66
|
+
`;
|
|
67
|
+
controller.enqueue(encoder.encode(sseEvent));
|
|
68
|
+
}
|
|
69
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
controller.error(error);
|
|
72
|
+
} finally {
|
|
73
|
+
controller.close();
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
cancel() {
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
parseSSEStream,
|
|
83
|
+
responseToAsyncIterable,
|
|
84
|
+
asyncIterableToSSEStream
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=chunk-EKSWCBCA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sse-parser.ts"],"sourcesContent":["/**\n * Server-Sent Events (SSE) parser for streaming responses\n * Converts ReadableStream<Uint8Array> to typed AsyncIterable<T>\n */\n\n/**\n * Parse a ReadableStream of SSE events into typed AsyncIterable\n * @param stream - The ReadableStream from fetch response\n * @param signal - Optional AbortSignal for cancellation\n */\nexport async function* parseSSEStream<T>(\n stream: ReadableStream<Uint8Array>,\n signal?: AbortSignal\n): AsyncIterable<T> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n // Check for cancellation\n if (signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n const { done, value } = await reader.read();\n if (done) break;\n\n // Decode chunk and add to buffer\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events in buffer\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n // Skip empty lines\n if (line.trim() === '') continue;\n\n // Process SSE data lines\n if (line.startsWith('data: ')) {\n const data = line.substring(6);\n\n // Skip [DONE] markers or empty data\n if (data === '[DONE]' || data.trim() === '') continue;\n\n try {\n const event = JSON.parse(data) as T;\n yield event;\n } catch {\n // Skip invalid JSON events and continue processing\n }\n }\n // Handle other SSE fields if needed (event:, id:, retry:)\n // For now, we only care about data: lines\n }\n }\n\n // Process any remaining data in buffer\n if (buffer.trim() && buffer.startsWith('data: ')) {\n const data = buffer.substring(6);\n if (data !== '[DONE]' && data.trim()) {\n try {\n const event = JSON.parse(data) as T;\n yield event;\n } catch {\n // Skip invalid JSON in final event\n }\n }\n }\n } finally {\n // Clean up resources\n reader.releaseLock();\n }\n}\n\n\n/**\n * Helper to convert a Response with SSE stream directly to AsyncIterable\n * @param response - Response object with SSE stream\n * @param signal - Optional AbortSignal for cancellation\n */\nexport async function* responseToAsyncIterable<T>(\n response: Response,\n signal?: AbortSignal\n): AsyncIterable<T> {\n if (!response.ok) {\n throw new Error(`Response not ok: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n yield* parseSSEStream<T>(response.body, signal);\n}\n\n/**\n * Create an SSE-formatted ReadableStream from an AsyncIterable\n * (Useful for Worker endpoints that need to forward AsyncIterable as SSE)\n * @param events - AsyncIterable of events\n * @param options - Stream options\n */\nexport function asyncIterableToSSEStream<T>(\n events: AsyncIterable<T>,\n options?: {\n signal?: AbortSignal;\n serialize?: (event: T) => string;\n }\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const serialize = options?.serialize || JSON.stringify;\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const event of events) {\n if (options?.signal?.aborted) {\n controller.error(new Error('Operation was aborted'));\n break;\n }\n\n const data = serialize(event);\n const sseEvent = `data: ${data}\\n\\n`;\n controller.enqueue(encoder.encode(sseEvent));\n }\n\n // Send completion marker\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'));\n } catch (error) {\n controller.error(error);\n } finally {\n controller.close();\n }\n },\n\n cancel() {\n // Handle stream cancellation\n }\n });\n}"],"mappings":";AAUA,gBAAuB,eACrB,QACA,QACkB;AAClB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,MAAI;AACF,WAAO,MAAM;AAEX,UAAI,QAAQ,SAAS;AACnB,cAAM,IAAI,MAAM,uBAAuB;AAAA,MACzC;AAEA,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AAGV,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAGhD,YAAM,QAAQ,OAAO,MAAM,IAAI;AAG/B,eAAS,MAAM,IAAI,KAAK;AAExB,iBAAW,QAAQ,OAAO;AAExB,YAAI,KAAK,KAAK,MAAM,GAAI;AAGxB,YAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,gBAAM,OAAO,KAAK,UAAU,CAAC;AAG7B,cAAI,SAAS,YAAY,KAAK,KAAK,MAAM,GAAI;AAE7C,cAAI;AACF,kBAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,kBAAM;AAAA,UACR,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MAGF;AAAA,IACF;AAGA,QAAI,OAAO,KAAK,KAAK,OAAO,WAAW,QAAQ,GAAG;AAChD,YAAM,OAAO,OAAO,UAAU,CAAC;AAC/B,UAAI,SAAS,YAAY,KAAK,KAAK,GAAG;AACpC,YAAI;AACF,gBAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,gBAAM;AAAA,QACR,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AAEA,WAAO,YAAY;AAAA,EACrB;AACF;AAQA,gBAAuB,wBACrB,UACA,QACkB;AAClB,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,oBAAoB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EAC9E;AAEA,MAAI,CAAC,SAAS,MAAM;AAClB,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AAEA,SAAO,eAAkB,SAAS,MAAM,MAAM;AAChD;AAQO,SAAS,yBACd,QACA,SAI4B;AAC5B,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,YAAY,SAAS,aAAa,KAAK;AAE7C,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM,MAAM,YAAY;AACtB,UAAI;AACF,yBAAiB,SAAS,QAAQ;AAChC,cAAI,SAAS,QAAQ,SAAS;AAC5B,uBAAW,MAAM,IAAI,MAAM,uBAAuB,CAAC;AACnD;AAAA,UACF;AAEA,gBAAM,OAAO,UAAU,KAAK;AAC5B,gBAAM,WAAW,SAAS,IAAI;AAAA;AAAA;AAC9B,qBAAW,QAAQ,QAAQ,OAAO,QAAQ,CAAC;AAAA,QAC7C;AAGA,mBAAW,QAAQ,QAAQ,OAAO,kBAAkB,CAAC;AAAA,MACvD,SAAS,OAAO;AACd,mBAAW,MAAM,KAAK;AAAA,MACxB,UAAE;AACA,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,IAEA,SAAS;AAAA,IAET;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateLanguage
|
|
3
|
+
} from "./chunk-Z532A7QC.js";
|
|
4
|
+
|
|
5
|
+
// ../shared/dist/interpreter-types.js
|
|
6
|
+
var Execution = class {
|
|
7
|
+
code;
|
|
8
|
+
context;
|
|
9
|
+
/**
|
|
10
|
+
* All results from the execution
|
|
11
|
+
*/
|
|
12
|
+
results = [];
|
|
13
|
+
/**
|
|
14
|
+
* Accumulated stdout and stderr
|
|
15
|
+
*/
|
|
16
|
+
logs = {
|
|
17
|
+
stdout: [],
|
|
18
|
+
stderr: []
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Execution error if any
|
|
22
|
+
*/
|
|
23
|
+
error;
|
|
24
|
+
/**
|
|
25
|
+
* Execution count (for interpreter)
|
|
26
|
+
*/
|
|
27
|
+
executionCount;
|
|
28
|
+
constructor(code, context) {
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.context = context;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Convert to a plain object for serialization
|
|
34
|
+
*/
|
|
35
|
+
toJSON() {
|
|
36
|
+
return {
|
|
37
|
+
code: this.code,
|
|
38
|
+
logs: this.logs,
|
|
39
|
+
error: this.error,
|
|
40
|
+
executionCount: this.executionCount,
|
|
41
|
+
results: this.results.map((result) => ({
|
|
42
|
+
text: result.text,
|
|
43
|
+
html: result.html,
|
|
44
|
+
png: result.png,
|
|
45
|
+
jpeg: result.jpeg,
|
|
46
|
+
svg: result.svg,
|
|
47
|
+
latex: result.latex,
|
|
48
|
+
markdown: result.markdown,
|
|
49
|
+
javascript: result.javascript,
|
|
50
|
+
json: result.json,
|
|
51
|
+
chart: result.chart,
|
|
52
|
+
data: result.data
|
|
53
|
+
}))
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var ResultImpl = class {
|
|
58
|
+
raw;
|
|
59
|
+
constructor(raw) {
|
|
60
|
+
this.raw = raw;
|
|
61
|
+
}
|
|
62
|
+
get text() {
|
|
63
|
+
return this.raw.text || this.raw.data?.["text/plain"];
|
|
64
|
+
}
|
|
65
|
+
get html() {
|
|
66
|
+
return this.raw.html || this.raw.data?.["text/html"];
|
|
67
|
+
}
|
|
68
|
+
get png() {
|
|
69
|
+
return this.raw.png || this.raw.data?.["image/png"];
|
|
70
|
+
}
|
|
71
|
+
get jpeg() {
|
|
72
|
+
return this.raw.jpeg || this.raw.data?.["image/jpeg"];
|
|
73
|
+
}
|
|
74
|
+
get svg() {
|
|
75
|
+
return this.raw.svg || this.raw.data?.["image/svg+xml"];
|
|
76
|
+
}
|
|
77
|
+
get latex() {
|
|
78
|
+
return this.raw.latex || this.raw.data?.["text/latex"];
|
|
79
|
+
}
|
|
80
|
+
get markdown() {
|
|
81
|
+
return this.raw.markdown || this.raw.data?.["text/markdown"];
|
|
82
|
+
}
|
|
83
|
+
get javascript() {
|
|
84
|
+
return this.raw.javascript || this.raw.data?.["application/javascript"];
|
|
85
|
+
}
|
|
86
|
+
get json() {
|
|
87
|
+
return this.raw.json || this.raw.data?.["application/json"];
|
|
88
|
+
}
|
|
89
|
+
get chart() {
|
|
90
|
+
return this.raw.chart;
|
|
91
|
+
}
|
|
92
|
+
get data() {
|
|
93
|
+
return this.raw.data;
|
|
94
|
+
}
|
|
95
|
+
formats() {
|
|
96
|
+
const formats = [];
|
|
97
|
+
if (this.text)
|
|
98
|
+
formats.push("text");
|
|
99
|
+
if (this.html)
|
|
100
|
+
formats.push("html");
|
|
101
|
+
if (this.png)
|
|
102
|
+
formats.push("png");
|
|
103
|
+
if (this.jpeg)
|
|
104
|
+
formats.push("jpeg");
|
|
105
|
+
if (this.svg)
|
|
106
|
+
formats.push("svg");
|
|
107
|
+
if (this.latex)
|
|
108
|
+
formats.push("latex");
|
|
109
|
+
if (this.markdown)
|
|
110
|
+
formats.push("markdown");
|
|
111
|
+
if (this.javascript)
|
|
112
|
+
formats.push("javascript");
|
|
113
|
+
if (this.json)
|
|
114
|
+
formats.push("json");
|
|
115
|
+
if (this.chart)
|
|
116
|
+
formats.push("chart");
|
|
117
|
+
return formats;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// ../shared/dist/logger/index.js
|
|
122
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
123
|
+
|
|
124
|
+
// ../shared/dist/logger/types.js
|
|
125
|
+
var LogLevel;
|
|
126
|
+
(function(LogLevel2) {
|
|
127
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
128
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
129
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
130
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
131
|
+
})(LogLevel || (LogLevel = {}));
|
|
132
|
+
|
|
133
|
+
// ../shared/dist/logger/logger.js
|
|
134
|
+
var COLORS = {
|
|
135
|
+
reset: "\x1B[0m",
|
|
136
|
+
debug: "\x1B[36m",
|
|
137
|
+
// Cyan
|
|
138
|
+
info: "\x1B[32m",
|
|
139
|
+
// Green
|
|
140
|
+
warn: "\x1B[33m",
|
|
141
|
+
// Yellow
|
|
142
|
+
error: "\x1B[31m",
|
|
143
|
+
// Red
|
|
144
|
+
dim: "\x1B[2m"
|
|
145
|
+
// Dim
|
|
146
|
+
};
|
|
147
|
+
var CloudflareLogger = class _CloudflareLogger {
|
|
148
|
+
baseContext;
|
|
149
|
+
minLevel;
|
|
150
|
+
pretty;
|
|
151
|
+
/**
|
|
152
|
+
* Create a new CloudflareLogger
|
|
153
|
+
*
|
|
154
|
+
* @param baseContext Base context included in all log entries
|
|
155
|
+
* @param minLevel Minimum log level to output (default: INFO)
|
|
156
|
+
* @param pretty Enable pretty printing for human-readable output (default: false)
|
|
157
|
+
*/
|
|
158
|
+
constructor(baseContext, minLevel = LogLevel.INFO, pretty = false) {
|
|
159
|
+
this.baseContext = baseContext;
|
|
160
|
+
this.minLevel = minLevel;
|
|
161
|
+
this.pretty = pretty;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Log debug-level message
|
|
165
|
+
*/
|
|
166
|
+
debug(message, context) {
|
|
167
|
+
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
168
|
+
const logData = this.buildLogData("debug", message, context);
|
|
169
|
+
this.output(console.log, logData);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Log info-level message
|
|
174
|
+
*/
|
|
175
|
+
info(message, context) {
|
|
176
|
+
if (this.shouldLog(LogLevel.INFO)) {
|
|
177
|
+
const logData = this.buildLogData("info", message, context);
|
|
178
|
+
this.output(console.log, logData);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Log warning-level message
|
|
183
|
+
*/
|
|
184
|
+
warn(message, context) {
|
|
185
|
+
if (this.shouldLog(LogLevel.WARN)) {
|
|
186
|
+
const logData = this.buildLogData("warn", message, context);
|
|
187
|
+
this.output(console.warn, logData);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Log error-level message
|
|
192
|
+
*/
|
|
193
|
+
error(message, error, context) {
|
|
194
|
+
if (this.shouldLog(LogLevel.ERROR)) {
|
|
195
|
+
const logData = this.buildLogData("error", message, context, error);
|
|
196
|
+
this.output(console.error, logData);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Create a child logger with additional context
|
|
201
|
+
*/
|
|
202
|
+
child(context) {
|
|
203
|
+
return new _CloudflareLogger({ ...this.baseContext, ...context }, this.minLevel, this.pretty);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if a log level should be output
|
|
207
|
+
*/
|
|
208
|
+
shouldLog(level) {
|
|
209
|
+
return level >= this.minLevel;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Build log data object
|
|
213
|
+
*/
|
|
214
|
+
buildLogData(level, message, context, error) {
|
|
215
|
+
const logData = {
|
|
216
|
+
level,
|
|
217
|
+
msg: message,
|
|
218
|
+
...this.baseContext,
|
|
219
|
+
...context,
|
|
220
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
221
|
+
};
|
|
222
|
+
if (error) {
|
|
223
|
+
logData.error = {
|
|
224
|
+
message: error.message,
|
|
225
|
+
stack: error.stack,
|
|
226
|
+
name: error.name
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return logData;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Output log data to console (pretty or JSON)
|
|
233
|
+
*/
|
|
234
|
+
output(consoleFn, data) {
|
|
235
|
+
if (this.pretty) {
|
|
236
|
+
this.outputPretty(consoleFn, data);
|
|
237
|
+
} else {
|
|
238
|
+
this.outputJson(consoleFn, data);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Output as JSON (production)
|
|
243
|
+
*/
|
|
244
|
+
outputJson(consoleFn, data) {
|
|
245
|
+
consoleFn(JSON.stringify(data));
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Output as pretty-printed, colored text (development)
|
|
249
|
+
*
|
|
250
|
+
* Format: LEVEL [component] message (trace: tr_...) {context}
|
|
251
|
+
* Example: INFO [sandbox-do] Command started (trace: tr_7f3a9b2c) {commandId: "cmd-123"}
|
|
252
|
+
*/
|
|
253
|
+
outputPretty(consoleFn, data) {
|
|
254
|
+
const { level, msg, timestamp, traceId, component, sandboxId, sessionId, processId, commandId, operation, duration, error, ...rest } = data;
|
|
255
|
+
const levelStr = String(level || "INFO").toUpperCase();
|
|
256
|
+
const levelColor = this.getLevelColor(levelStr);
|
|
257
|
+
const componentBadge = component ? `[${component}]` : "";
|
|
258
|
+
const traceIdShort = traceId ? String(traceId).substring(0, 12) : "";
|
|
259
|
+
let logLine = `${levelColor}${levelStr.padEnd(5)}${COLORS.reset} ${componentBadge} ${msg}`;
|
|
260
|
+
if (traceIdShort) {
|
|
261
|
+
logLine += ` ${COLORS.dim}(trace: ${traceIdShort})${COLORS.reset}`;
|
|
262
|
+
}
|
|
263
|
+
const contextFields = [];
|
|
264
|
+
if (operation)
|
|
265
|
+
contextFields.push(`operation: ${operation}`);
|
|
266
|
+
if (commandId)
|
|
267
|
+
contextFields.push(`commandId: ${String(commandId).substring(0, 12)}`);
|
|
268
|
+
if (sandboxId)
|
|
269
|
+
contextFields.push(`sandboxId: ${sandboxId}`);
|
|
270
|
+
if (sessionId)
|
|
271
|
+
contextFields.push(`sessionId: ${String(sessionId).substring(0, 12)}`);
|
|
272
|
+
if (processId)
|
|
273
|
+
contextFields.push(`processId: ${processId}`);
|
|
274
|
+
if (duration !== void 0)
|
|
275
|
+
contextFields.push(`duration: ${duration}ms`);
|
|
276
|
+
if (contextFields.length > 0) {
|
|
277
|
+
logLine += ` ${COLORS.dim}{${contextFields.join(", ")}}${COLORS.reset}`;
|
|
278
|
+
}
|
|
279
|
+
consoleFn(logLine);
|
|
280
|
+
if (error && typeof error === "object") {
|
|
281
|
+
const errorObj = error;
|
|
282
|
+
if (errorObj.message) {
|
|
283
|
+
consoleFn(` ${COLORS.error}Error: ${errorObj.message}${COLORS.reset}`);
|
|
284
|
+
}
|
|
285
|
+
if (errorObj.stack) {
|
|
286
|
+
consoleFn(` ${COLORS.dim}${errorObj.stack}${COLORS.reset}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (Object.keys(rest).length > 0) {
|
|
290
|
+
consoleFn(` ${COLORS.dim}${JSON.stringify(rest, null, 2)}${COLORS.reset}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get ANSI color code for log level
|
|
295
|
+
*/
|
|
296
|
+
getLevelColor(level) {
|
|
297
|
+
const levelLower = level.toLowerCase();
|
|
298
|
+
switch (levelLower) {
|
|
299
|
+
case "debug":
|
|
300
|
+
return COLORS.debug;
|
|
301
|
+
case "info":
|
|
302
|
+
return COLORS.info;
|
|
303
|
+
case "warn":
|
|
304
|
+
return COLORS.warn;
|
|
305
|
+
case "error":
|
|
306
|
+
return COLORS.error;
|
|
307
|
+
default:
|
|
308
|
+
return COLORS.reset;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// ../shared/dist/logger/trace-context.js
|
|
314
|
+
var TraceContext = class _TraceContext {
|
|
315
|
+
/**
|
|
316
|
+
* HTTP header name for trace ID propagation
|
|
317
|
+
*/
|
|
318
|
+
static TRACE_HEADER = "X-Trace-Id";
|
|
319
|
+
/**
|
|
320
|
+
* Generate a new trace ID
|
|
321
|
+
*
|
|
322
|
+
* Format: "tr_" + 16 random hex characters
|
|
323
|
+
* Example: "tr_7f3a9b2c4e5d6f1a"
|
|
324
|
+
*
|
|
325
|
+
* @returns Newly generated trace ID
|
|
326
|
+
*/
|
|
327
|
+
static generate() {
|
|
328
|
+
const randomHex = crypto.randomUUID().replace(/-/g, "").substring(0, 16);
|
|
329
|
+
return `tr_${randomHex}`;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Extract trace ID from HTTP request headers
|
|
333
|
+
*
|
|
334
|
+
* @param headers Request headers
|
|
335
|
+
* @returns Trace ID if present, null otherwise
|
|
336
|
+
*/
|
|
337
|
+
static fromHeaders(headers) {
|
|
338
|
+
return headers.get(_TraceContext.TRACE_HEADER);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Create headers object with trace ID for outgoing requests
|
|
342
|
+
*
|
|
343
|
+
* @param traceId Trace ID to include
|
|
344
|
+
* @returns Headers object with X-Trace-Id set
|
|
345
|
+
*/
|
|
346
|
+
static toHeaders(traceId) {
|
|
347
|
+
return { [_TraceContext.TRACE_HEADER]: traceId };
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Get the header name used for trace ID propagation
|
|
351
|
+
*
|
|
352
|
+
* @returns Header name ("X-Trace-Id")
|
|
353
|
+
*/
|
|
354
|
+
static getHeaderName() {
|
|
355
|
+
return _TraceContext.TRACE_HEADER;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// ../shared/dist/logger/index.js
|
|
360
|
+
function createNoOpLogger() {
|
|
361
|
+
return {
|
|
362
|
+
debug: () => {
|
|
363
|
+
},
|
|
364
|
+
info: () => {
|
|
365
|
+
},
|
|
366
|
+
warn: () => {
|
|
367
|
+
},
|
|
368
|
+
error: () => {
|
|
369
|
+
},
|
|
370
|
+
child: () => createNoOpLogger()
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
var loggerStorage = new AsyncLocalStorage();
|
|
374
|
+
function getLogger() {
|
|
375
|
+
const logger = loggerStorage.getStore();
|
|
376
|
+
if (!logger) {
|
|
377
|
+
throw new Error("Logger not initialized in async context. Ensure runWithLogger() is called at the entry point (e.g., fetch handler).");
|
|
378
|
+
}
|
|
379
|
+
return logger;
|
|
380
|
+
}
|
|
381
|
+
function runWithLogger(logger, fn) {
|
|
382
|
+
return loggerStorage.run(logger, fn);
|
|
383
|
+
}
|
|
384
|
+
function createLogger(context) {
|
|
385
|
+
const minLevel = getLogLevelFromEnv();
|
|
386
|
+
const pretty = isPrettyPrintEnabled();
|
|
387
|
+
const baseContext = {
|
|
388
|
+
...context,
|
|
389
|
+
traceId: context.traceId || TraceContext.generate(),
|
|
390
|
+
component: context.component
|
|
391
|
+
};
|
|
392
|
+
return new CloudflareLogger(baseContext, minLevel, pretty);
|
|
393
|
+
}
|
|
394
|
+
function getLogLevelFromEnv() {
|
|
395
|
+
const envLevel = getEnvVar("SANDBOX_LOG_LEVEL") || "info";
|
|
396
|
+
switch (envLevel.toLowerCase()) {
|
|
397
|
+
case "debug":
|
|
398
|
+
return LogLevel.DEBUG;
|
|
399
|
+
case "info":
|
|
400
|
+
return LogLevel.INFO;
|
|
401
|
+
case "warn":
|
|
402
|
+
return LogLevel.WARN;
|
|
403
|
+
case "error":
|
|
404
|
+
return LogLevel.ERROR;
|
|
405
|
+
default:
|
|
406
|
+
return LogLevel.INFO;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function isPrettyPrintEnabled() {
|
|
410
|
+
const format = getEnvVar("SANDBOX_LOG_FORMAT");
|
|
411
|
+
if (format) {
|
|
412
|
+
return format.toLowerCase() === "pretty";
|
|
413
|
+
}
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
function getEnvVar(name) {
|
|
417
|
+
if (typeof process !== "undefined" && process.env) {
|
|
418
|
+
return process.env[name];
|
|
419
|
+
}
|
|
420
|
+
if (typeof Bun !== "undefined") {
|
|
421
|
+
const bunEnv = Bun.env;
|
|
422
|
+
if (bunEnv) {
|
|
423
|
+
return bunEnv[name];
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return void 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// ../shared/dist/types.js
|
|
430
|
+
function isExecResult(value) {
|
|
431
|
+
return value && typeof value.success === "boolean" && typeof value.exitCode === "number" && typeof value.stdout === "string" && typeof value.stderr === "string";
|
|
432
|
+
}
|
|
433
|
+
function isProcess(value) {
|
|
434
|
+
return value && typeof value.id === "string" && typeof value.command === "string" && typeof value.status === "string";
|
|
435
|
+
}
|
|
436
|
+
function isProcessStatus(value) {
|
|
437
|
+
return ["starting", "running", "completed", "failed", "killed", "error"].includes(value);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/interpreter.ts
|
|
441
|
+
var CodeInterpreter = class {
|
|
442
|
+
interpreterClient;
|
|
443
|
+
contexts = /* @__PURE__ */ new Map();
|
|
444
|
+
constructor(sandbox) {
|
|
445
|
+
this.interpreterClient = sandbox.client.interpreter;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Create a new code execution context
|
|
449
|
+
*/
|
|
450
|
+
async createCodeContext(options = {}) {
|
|
451
|
+
validateLanguage(options.language);
|
|
452
|
+
const context = await this.interpreterClient.createCodeContext(options);
|
|
453
|
+
this.contexts.set(context.id, context);
|
|
454
|
+
return context;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Run code with optional context
|
|
458
|
+
*/
|
|
459
|
+
async runCode(code, options = {}) {
|
|
460
|
+
let context = options.context;
|
|
461
|
+
if (!context) {
|
|
462
|
+
const language = options.language || "python";
|
|
463
|
+
context = await this.getOrCreateDefaultContext(language);
|
|
464
|
+
}
|
|
465
|
+
const execution = new Execution(code, context);
|
|
466
|
+
await this.interpreterClient.runCodeStream(context.id, code, options.language, {
|
|
467
|
+
onStdout: (output) => {
|
|
468
|
+
execution.logs.stdout.push(output.text);
|
|
469
|
+
if (options.onStdout) return options.onStdout(output);
|
|
470
|
+
},
|
|
471
|
+
onStderr: (output) => {
|
|
472
|
+
execution.logs.stderr.push(output.text);
|
|
473
|
+
if (options.onStderr) return options.onStderr(output);
|
|
474
|
+
},
|
|
475
|
+
onResult: async (result) => {
|
|
476
|
+
execution.results.push(new ResultImpl(result));
|
|
477
|
+
if (options.onResult) return options.onResult(result);
|
|
478
|
+
},
|
|
479
|
+
onError: (error) => {
|
|
480
|
+
execution.error = error;
|
|
481
|
+
if (options.onError) return options.onError(error);
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
return execution;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Run code and return a streaming response
|
|
488
|
+
*/
|
|
489
|
+
async runCodeStream(code, options = {}) {
|
|
490
|
+
let context = options.context;
|
|
491
|
+
if (!context) {
|
|
492
|
+
const language = options.language || "python";
|
|
493
|
+
context = await this.getOrCreateDefaultContext(language);
|
|
494
|
+
}
|
|
495
|
+
const response = await this.interpreterClient.doFetch("/api/execute/code", {
|
|
496
|
+
method: "POST",
|
|
497
|
+
headers: {
|
|
498
|
+
"Content-Type": "application/json",
|
|
499
|
+
Accept: "text/event-stream"
|
|
500
|
+
},
|
|
501
|
+
body: JSON.stringify({
|
|
502
|
+
context_id: context.id,
|
|
503
|
+
code,
|
|
504
|
+
language: options.language
|
|
505
|
+
})
|
|
506
|
+
});
|
|
507
|
+
if (!response.ok) {
|
|
508
|
+
const errorData = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
509
|
+
throw new Error(
|
|
510
|
+
errorData.error || `Failed to execute code: ${response.status}`
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
if (!response.body) {
|
|
514
|
+
throw new Error("No response body for streaming execution");
|
|
515
|
+
}
|
|
516
|
+
return response.body;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* List all code contexts
|
|
520
|
+
*/
|
|
521
|
+
async listCodeContexts() {
|
|
522
|
+
const contexts = await this.interpreterClient.listCodeContexts();
|
|
523
|
+
for (const context of contexts) {
|
|
524
|
+
this.contexts.set(context.id, context);
|
|
525
|
+
}
|
|
526
|
+
return contexts;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Delete a code context
|
|
530
|
+
*/
|
|
531
|
+
async deleteCodeContext(contextId) {
|
|
532
|
+
await this.interpreterClient.deleteCodeContext(contextId);
|
|
533
|
+
this.contexts.delete(contextId);
|
|
534
|
+
}
|
|
535
|
+
async getOrCreateDefaultContext(language) {
|
|
536
|
+
for (const context of this.contexts.values()) {
|
|
537
|
+
if (context.language === language) {
|
|
538
|
+
return context;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return this.createCodeContext({ language });
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
export {
|
|
546
|
+
Execution,
|
|
547
|
+
ResultImpl,
|
|
548
|
+
LogLevel,
|
|
549
|
+
TraceContext,
|
|
550
|
+
createNoOpLogger,
|
|
551
|
+
getLogger,
|
|
552
|
+
runWithLogger,
|
|
553
|
+
createLogger,
|
|
554
|
+
isExecResult,
|
|
555
|
+
isProcess,
|
|
556
|
+
isProcessStatus,
|
|
557
|
+
CodeInterpreter
|
|
558
|
+
};
|
|
559
|
+
//# sourceMappingURL=chunk-JXZMAU2C.js.map
|