@cloudflare/sandbox 0.0.0-603d05f → 0.0.0-66cc85b
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 +36 -0
- package/Dockerfile +23 -24
- package/README.md +59 -6
- package/container_src/bun.lock +31 -77
- package/container_src/control-process.ts +1 -1
- package/container_src/handler/exec.ts +2 -2
- package/container_src/handler/file.ts +51 -0
- package/container_src/handler/session.ts +2 -2
- package/container_src/index.ts +43 -43
- package/container_src/interpreter-service.ts +276 -0
- package/container_src/isolation.ts +207 -33
- package/container_src/mime-processor.ts +1 -1
- package/container_src/package.json +4 -4
- package/container_src/runtime/executors/javascript/node_executor.ts +123 -0
- package/container_src/runtime/executors/python/ipython_executor.py +338 -0
- package/container_src/runtime/executors/typescript/ts_executor.ts +138 -0
- package/container_src/runtime/process-pool.ts +464 -0
- package/container_src/startup.sh +6 -79
- package/package.json +2 -2
- package/src/client.ts +39 -0
- package/src/errors.ts +15 -14
- package/src/file-stream.ts +162 -0
- package/src/index.ts +22 -5
- package/src/{jupyter-client.ts → interpreter-client.ts} +6 -3
- package/src/interpreter-types.ts +102 -95
- package/src/interpreter.ts +8 -8
- package/src/sandbox.ts +18 -5
- package/src/types.ts +69 -0
- package/container_src/jupyter-server.ts +0 -579
- package/container_src/jupyter-service.ts +0 -461
- package/container_src/jupyter_config.py +0 -48
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File streaming utilities for reading binary and text files
|
|
3
|
+
* Provides simple AsyncIterable API over SSE stream with automatic base64 decoding
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { parseSSEStream } from './sse-parser';
|
|
7
|
+
import type { FileChunk, FileMetadata, FileStreamEvent } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Convert ReadableStream of SSE file events to AsyncIterable of file chunks
|
|
11
|
+
* Automatically decodes base64 for binary files and provides metadata
|
|
12
|
+
*
|
|
13
|
+
* @param stream - The SSE ReadableStream from readFileStream()
|
|
14
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
15
|
+
* @returns AsyncIterable that yields file chunks (string for text, Uint8Array for binary)
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const stream = await sandbox.readFileStream('/path/to/file.png');
|
|
20
|
+
*
|
|
21
|
+
* for await (const chunk of streamFile(stream)) {
|
|
22
|
+
* if (chunk instanceof Uint8Array) {
|
|
23
|
+
* // Binary chunk - already decoded from base64
|
|
24
|
+
* console.log('Binary chunk:', chunk.byteLength, 'bytes');
|
|
25
|
+
* } else {
|
|
26
|
+
* // Text chunk
|
|
27
|
+
* console.log('Text chunk:', chunk);
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* // Access metadata
|
|
32
|
+
* const iter = streamFile(stream);
|
|
33
|
+
* for await (const chunk of iter) {
|
|
34
|
+
* console.log('MIME type:', iter.metadata?.mimeType);
|
|
35
|
+
* // process chunk...
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export async function* streamFile(
|
|
40
|
+
stream: ReadableStream<Uint8Array>,
|
|
41
|
+
signal?: AbortSignal
|
|
42
|
+
): AsyncGenerator<FileChunk, void, undefined> {
|
|
43
|
+
let metadata: FileMetadata | undefined;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
for await (const event of parseSSEStream<FileStreamEvent>(stream, signal)) {
|
|
47
|
+
switch (event.type) {
|
|
48
|
+
case 'metadata':
|
|
49
|
+
// Store metadata for access via iterator
|
|
50
|
+
metadata = {
|
|
51
|
+
mimeType: event.mimeType,
|
|
52
|
+
size: event.size,
|
|
53
|
+
isBinary: event.isBinary,
|
|
54
|
+
encoding: event.encoding,
|
|
55
|
+
};
|
|
56
|
+
// Store on generator function for external access
|
|
57
|
+
(streamFile as any).metadata = metadata;
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
case 'chunk':
|
|
61
|
+
// Auto-decode base64 for binary files
|
|
62
|
+
if (metadata?.isBinary && metadata?.encoding === 'base64') {
|
|
63
|
+
// Decode base64 to Uint8Array
|
|
64
|
+
const binaryString = atob(event.data);
|
|
65
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
66
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
67
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
68
|
+
}
|
|
69
|
+
yield bytes;
|
|
70
|
+
} else {
|
|
71
|
+
// Text file - yield as-is
|
|
72
|
+
yield event.data;
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
|
|
76
|
+
case 'complete':
|
|
77
|
+
// Stream completed successfully
|
|
78
|
+
console.log(`[streamFile] File streaming complete: ${event.bytesRead} bytes read`);
|
|
79
|
+
return;
|
|
80
|
+
|
|
81
|
+
case 'error':
|
|
82
|
+
// Stream error
|
|
83
|
+
throw new Error(`File streaming error: ${event.error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('[streamFile] Error streaming file:', error);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Helper to collect entire file from stream into memory
|
|
94
|
+
* Useful for smaller files where you want the complete content at once
|
|
95
|
+
*
|
|
96
|
+
* @param stream - The SSE ReadableStream from readFileStream()
|
|
97
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
98
|
+
* @returns Object with content (string or Uint8Array) and metadata
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const stream = await sandbox.readFileStream('/path/to/image.png');
|
|
103
|
+
* const { content, metadata } = await collectFile(stream);
|
|
104
|
+
*
|
|
105
|
+
* if (content instanceof Uint8Array) {
|
|
106
|
+
* console.log('Binary file:', metadata.mimeType, content.byteLength, 'bytes');
|
|
107
|
+
* } else {
|
|
108
|
+
* console.log('Text file:', metadata.mimeType, content.length, 'chars');
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export async function collectFile(
|
|
113
|
+
stream: ReadableStream<Uint8Array>,
|
|
114
|
+
signal?: AbortSignal
|
|
115
|
+
): Promise<{ content: string | Uint8Array; metadata: FileMetadata }> {
|
|
116
|
+
let metadata: FileMetadata | undefined;
|
|
117
|
+
const chunks: FileChunk[] = [];
|
|
118
|
+
|
|
119
|
+
for await (const chunk of streamFile(stream, signal)) {
|
|
120
|
+
chunks.push(chunk);
|
|
121
|
+
// Capture metadata from first iteration
|
|
122
|
+
if (!metadata && (streamFile as any).metadata) {
|
|
123
|
+
metadata = (streamFile as any).metadata;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!metadata) {
|
|
128
|
+
throw new Error('No metadata received from file stream');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Combine chunks based on type
|
|
132
|
+
if (chunks.length === 0) {
|
|
133
|
+
// Empty file
|
|
134
|
+
return {
|
|
135
|
+
content: metadata.isBinary ? new Uint8Array(0) : '',
|
|
136
|
+
metadata,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check if binary or text based on first chunk
|
|
141
|
+
if (chunks[0] instanceof Uint8Array) {
|
|
142
|
+
// Binary file - concatenate Uint8Arrays
|
|
143
|
+
const totalLength = chunks.reduce((sum, chunk) => {
|
|
144
|
+
return sum + (chunk as Uint8Array).byteLength;
|
|
145
|
+
}, 0);
|
|
146
|
+
|
|
147
|
+
const result = new Uint8Array(totalLength);
|
|
148
|
+
let offset = 0;
|
|
149
|
+
for (const chunk of chunks) {
|
|
150
|
+
result.set(chunk as Uint8Array, offset);
|
|
151
|
+
offset += (chunk as Uint8Array).byteLength;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { content: result, metadata };
|
|
155
|
+
} else {
|
|
156
|
+
// Text file - concatenate strings
|
|
157
|
+
return {
|
|
158
|
+
content: chunks.join(''),
|
|
159
|
+
metadata,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
|
-
//
|
|
1
|
+
// biome-ignore-start assist/source/organizeImports: Need separate exports for deprecation warnings to work properly
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Use `InterpreterNotReadyError` instead. Will be removed in a future version.
|
|
4
|
+
*/
|
|
5
|
+
export { InterpreterNotReadyError as JupyterNotReadyError } from "./errors";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Use `isInterpreterNotReadyError` instead. Will be removed in a future version.
|
|
9
|
+
*/
|
|
10
|
+
export { isInterpreterNotReadyError as isJupyterNotReadyError } from "./errors";
|
|
11
|
+
// biome-ignore-end assist/source/organizeImports: Need separate exports for deprecation warnings to work properly
|
|
2
12
|
|
|
3
|
-
// Export
|
|
13
|
+
// Export API response types
|
|
4
14
|
export {
|
|
5
15
|
CodeExecutionError,
|
|
6
16
|
ContainerNotReadyError,
|
|
7
17
|
ContextNotFoundError,
|
|
8
|
-
|
|
18
|
+
InterpreterNotReadyError,
|
|
19
|
+
isInterpreterNotReadyError,
|
|
9
20
|
isRetryableError,
|
|
10
21
|
isSandboxError,
|
|
11
|
-
JupyterNotReadyError,
|
|
12
22
|
parseErrorResponse,
|
|
13
23
|
SandboxError,
|
|
14
24
|
type SandboxErrorResponse,
|
|
15
25
|
SandboxNetworkError,
|
|
16
26
|
ServiceUnavailableError,
|
|
17
27
|
} from "./errors";
|
|
28
|
+
|
|
18
29
|
// Export code interpreter types
|
|
19
30
|
export type {
|
|
20
31
|
ChartData,
|
|
@@ -41,6 +52,8 @@ export {
|
|
|
41
52
|
parseSSEStream,
|
|
42
53
|
responseToAsyncIterable,
|
|
43
54
|
} from "./sse-parser";
|
|
55
|
+
// Export file streaming utilities
|
|
56
|
+
export { streamFile, collectFile } from "./file-stream";
|
|
44
57
|
export type {
|
|
45
58
|
DeleteFileResponse,
|
|
46
59
|
ExecEvent,
|
|
@@ -48,6 +61,10 @@ export type {
|
|
|
48
61
|
ExecResult,
|
|
49
62
|
ExecuteResponse,
|
|
50
63
|
ExecutionSession,
|
|
64
|
+
FileChunk,
|
|
65
|
+
FileMetadata,
|
|
66
|
+
FileStream,
|
|
67
|
+
FileStreamEvent,
|
|
51
68
|
GitCheckoutResponse,
|
|
52
69
|
ISandbox,
|
|
53
70
|
ListFilesResponse,
|
|
@@ -60,5 +77,5 @@ export type {
|
|
|
60
77
|
ReadFileResponse,
|
|
61
78
|
RenameFileResponse,
|
|
62
79
|
StreamOptions,
|
|
63
|
-
WriteFileResponse
|
|
80
|
+
WriteFileResponse,
|
|
64
81
|
} from "./types";
|
|
@@ -62,7 +62,7 @@ export interface ExecutionCallbacks {
|
|
|
62
62
|
onError?: (error: ExecutionError) => void | Promise<void>;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export class
|
|
65
|
+
export class InterpreterClient extends HttpClient {
|
|
66
66
|
private readonly maxRetries = 3;
|
|
67
67
|
private readonly retryDelayMs = 1000;
|
|
68
68
|
|
|
@@ -239,7 +239,10 @@ export class JupyterClient extends HttpClient {
|
|
|
239
239
|
break;
|
|
240
240
|
}
|
|
241
241
|
} catch (error) {
|
|
242
|
-
console.error(
|
|
242
|
+
console.error(
|
|
243
|
+
"[InterpreterClient] Error parsing execution result:",
|
|
244
|
+
error
|
|
245
|
+
);
|
|
243
246
|
}
|
|
244
247
|
}
|
|
245
248
|
|
|
@@ -295,7 +298,7 @@ export class JupyterClient extends HttpClient {
|
|
|
295
298
|
} catch (error) {
|
|
296
299
|
lastError = error as Error;
|
|
297
300
|
|
|
298
|
-
// Check if it's a retryable error (circuit breaker or
|
|
301
|
+
// Check if it's a retryable error (circuit breaker or interpreter not ready)
|
|
299
302
|
if (this.isRetryableError(error)) {
|
|
300
303
|
// Don't retry on the last attempt
|
|
301
304
|
if (attempt < this.maxRetries - 1) {
|
package/src/interpreter-types.ts
CHANGED
|
@@ -4,19 +4,19 @@ export interface CreateContextOptions {
|
|
|
4
4
|
* Programming language for the context
|
|
5
5
|
* @default 'python'
|
|
6
6
|
*/
|
|
7
|
-
language?:
|
|
8
|
-
|
|
7
|
+
language?: "python" | "javascript" | "typescript";
|
|
8
|
+
|
|
9
9
|
/**
|
|
10
10
|
* Working directory for the context
|
|
11
11
|
* @default '/workspace'
|
|
12
12
|
*/
|
|
13
13
|
cwd?: string;
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
/**
|
|
16
16
|
* Environment variables for the context
|
|
17
17
|
*/
|
|
18
18
|
envVars?: Record<string, string>;
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
/**
|
|
21
21
|
* Request timeout in milliseconds
|
|
22
22
|
* @default 30000
|
|
@@ -29,22 +29,22 @@ export interface CodeContext {
|
|
|
29
29
|
* Unique identifier for the context
|
|
30
30
|
*/
|
|
31
31
|
readonly id: string;
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
/**
|
|
34
34
|
* Programming language of the context
|
|
35
35
|
*/
|
|
36
36
|
readonly language: string;
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
/**
|
|
39
39
|
* Current working directory
|
|
40
40
|
*/
|
|
41
41
|
readonly cwd: string;
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
/**
|
|
44
44
|
* When the context was created
|
|
45
45
|
*/
|
|
46
46
|
readonly createdAt: Date;
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
/**
|
|
49
49
|
* When the context was last used
|
|
50
50
|
*/
|
|
@@ -57,44 +57,44 @@ export interface RunCodeOptions {
|
|
|
57
57
|
* Context to run the code in. If not provided, uses default context for the language
|
|
58
58
|
*/
|
|
59
59
|
context?: CodeContext;
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
/**
|
|
62
62
|
* Language to use if context is not provided
|
|
63
63
|
* @default 'python'
|
|
64
64
|
*/
|
|
65
|
-
language?:
|
|
66
|
-
|
|
65
|
+
language?: "python" | "javascript" | "typescript";
|
|
66
|
+
|
|
67
67
|
/**
|
|
68
68
|
* Environment variables for this execution
|
|
69
69
|
*/
|
|
70
70
|
envVars?: Record<string, string>;
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
/**
|
|
73
73
|
* Execution timeout in milliseconds
|
|
74
74
|
* @default 60000
|
|
75
75
|
*/
|
|
76
76
|
timeout?: number;
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
/**
|
|
79
79
|
* AbortSignal for cancelling execution
|
|
80
80
|
*/
|
|
81
81
|
signal?: AbortSignal;
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
/**
|
|
84
84
|
* Callback for stdout output
|
|
85
85
|
*/
|
|
86
86
|
onStdout?: (output: OutputMessage) => void | Promise<void>;
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
/**
|
|
89
89
|
* Callback for stderr output
|
|
90
90
|
*/
|
|
91
91
|
onStderr?: (output: OutputMessage) => void | Promise<void>;
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
/**
|
|
94
94
|
* Callback for execution results (charts, tables, etc)
|
|
95
95
|
*/
|
|
96
96
|
onResult?: (result: Result) => void | Promise<void>;
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
/**
|
|
99
99
|
* Callback for execution errors
|
|
100
100
|
*/
|
|
@@ -107,7 +107,7 @@ export interface OutputMessage {
|
|
|
107
107
|
* The output text
|
|
108
108
|
*/
|
|
109
109
|
text: string;
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
/**
|
|
112
112
|
* Timestamp of the output
|
|
113
113
|
*/
|
|
@@ -120,57 +120,57 @@ export interface Result {
|
|
|
120
120
|
* Plain text representation
|
|
121
121
|
*/
|
|
122
122
|
text?: string;
|
|
123
|
-
|
|
123
|
+
|
|
124
124
|
/**
|
|
125
125
|
* HTML representation (tables, formatted output)
|
|
126
126
|
*/
|
|
127
127
|
html?: string;
|
|
128
|
-
|
|
128
|
+
|
|
129
129
|
/**
|
|
130
130
|
* PNG image data (base64 encoded)
|
|
131
131
|
*/
|
|
132
132
|
png?: string;
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
/**
|
|
135
135
|
* JPEG image data (base64 encoded)
|
|
136
136
|
*/
|
|
137
137
|
jpeg?: string;
|
|
138
|
-
|
|
138
|
+
|
|
139
139
|
/**
|
|
140
140
|
* SVG image data
|
|
141
141
|
*/
|
|
142
142
|
svg?: string;
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
/**
|
|
145
145
|
* LaTeX representation
|
|
146
146
|
*/
|
|
147
147
|
latex?: string;
|
|
148
|
-
|
|
148
|
+
|
|
149
149
|
/**
|
|
150
150
|
* Markdown representation
|
|
151
151
|
*/
|
|
152
152
|
markdown?: string;
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
/**
|
|
155
155
|
* JavaScript code to execute
|
|
156
156
|
*/
|
|
157
157
|
javascript?: string;
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
/**
|
|
160
160
|
* JSON data
|
|
161
161
|
*/
|
|
162
162
|
json?: any;
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
/**
|
|
165
165
|
* Chart data if the result is a visualization
|
|
166
166
|
*/
|
|
167
167
|
chart?: ChartData;
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
/**
|
|
170
170
|
* Raw data object
|
|
171
171
|
*/
|
|
172
172
|
data?: any;
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
/**
|
|
175
175
|
* Available output formats
|
|
176
176
|
*/
|
|
@@ -182,33 +182,40 @@ export interface ChartData {
|
|
|
182
182
|
/**
|
|
183
183
|
* Type of chart
|
|
184
184
|
*/
|
|
185
|
-
type:
|
|
186
|
-
|
|
185
|
+
type:
|
|
186
|
+
| "line"
|
|
187
|
+
| "bar"
|
|
188
|
+
| "scatter"
|
|
189
|
+
| "pie"
|
|
190
|
+
| "histogram"
|
|
191
|
+
| "heatmap"
|
|
192
|
+
| "unknown";
|
|
193
|
+
|
|
187
194
|
/**
|
|
188
195
|
* Chart title
|
|
189
196
|
*/
|
|
190
197
|
title?: string;
|
|
191
|
-
|
|
198
|
+
|
|
192
199
|
/**
|
|
193
200
|
* Chart data (format depends on library)
|
|
194
201
|
*/
|
|
195
202
|
data: any;
|
|
196
|
-
|
|
203
|
+
|
|
197
204
|
/**
|
|
198
205
|
* Chart layout/configuration
|
|
199
206
|
*/
|
|
200
207
|
layout?: any;
|
|
201
|
-
|
|
208
|
+
|
|
202
209
|
/**
|
|
203
210
|
* Additional configuration
|
|
204
211
|
*/
|
|
205
212
|
config?: any;
|
|
206
|
-
|
|
213
|
+
|
|
207
214
|
/**
|
|
208
215
|
* Library that generated the chart
|
|
209
216
|
*/
|
|
210
|
-
library?:
|
|
211
|
-
|
|
217
|
+
library?: "matplotlib" | "plotly" | "altair" | "seaborn" | "unknown";
|
|
218
|
+
|
|
212
219
|
/**
|
|
213
220
|
* Base64 encoded image if available
|
|
214
221
|
*/
|
|
@@ -221,17 +228,17 @@ export interface ExecutionError {
|
|
|
221
228
|
* Error name/type (e.g., 'NameError', 'SyntaxError')
|
|
222
229
|
*/
|
|
223
230
|
name: string;
|
|
224
|
-
|
|
231
|
+
|
|
225
232
|
/**
|
|
226
233
|
* Error message
|
|
227
234
|
*/
|
|
228
235
|
value: string;
|
|
229
|
-
|
|
236
|
+
|
|
230
237
|
/**
|
|
231
238
|
* Stack trace
|
|
232
239
|
*/
|
|
233
240
|
traceback: string[];
|
|
234
|
-
|
|
241
|
+
|
|
235
242
|
/**
|
|
236
243
|
* Line number where error occurred
|
|
237
244
|
*/
|
|
@@ -268,30 +275,30 @@ export class Execution {
|
|
|
268
275
|
* All results from the execution
|
|
269
276
|
*/
|
|
270
277
|
public results: Result[] = [];
|
|
271
|
-
|
|
278
|
+
|
|
272
279
|
/**
|
|
273
280
|
* Accumulated stdout and stderr
|
|
274
281
|
*/
|
|
275
282
|
public logs = {
|
|
276
283
|
stdout: [] as string[],
|
|
277
|
-
stderr: [] as string[]
|
|
284
|
+
stderr: [] as string[],
|
|
278
285
|
};
|
|
279
|
-
|
|
286
|
+
|
|
280
287
|
/**
|
|
281
288
|
* Execution error if any
|
|
282
289
|
*/
|
|
283
290
|
public error?: ExecutionError;
|
|
284
|
-
|
|
291
|
+
|
|
285
292
|
/**
|
|
286
|
-
* Execution count (for
|
|
293
|
+
* Execution count (for interpreter)
|
|
287
294
|
*/
|
|
288
295
|
public executionCount?: number;
|
|
289
|
-
|
|
296
|
+
|
|
290
297
|
constructor(
|
|
291
298
|
public readonly code: string,
|
|
292
299
|
public readonly context: CodeContext
|
|
293
300
|
) {}
|
|
294
|
-
|
|
301
|
+
|
|
295
302
|
/**
|
|
296
303
|
* Convert to a plain object for serialization
|
|
297
304
|
*/
|
|
@@ -301,7 +308,7 @@ export class Execution {
|
|
|
301
308
|
logs: this.logs,
|
|
302
309
|
error: this.error,
|
|
303
310
|
executionCount: this.executionCount,
|
|
304
|
-
results: this.results.map(result => ({
|
|
311
|
+
results: this.results.map((result) => ({
|
|
305
312
|
text: result.text,
|
|
306
313
|
html: result.html,
|
|
307
314
|
png: result.png,
|
|
@@ -312,8 +319,8 @@ export class Execution {
|
|
|
312
319
|
javascript: result.javascript,
|
|
313
320
|
json: result.json,
|
|
314
321
|
chart: result.chart,
|
|
315
|
-
data: result.data
|
|
316
|
-
}))
|
|
322
|
+
data: result.data,
|
|
323
|
+
})),
|
|
317
324
|
};
|
|
318
325
|
}
|
|
319
326
|
}
|
|
@@ -321,63 +328,63 @@ export class Execution {
|
|
|
321
328
|
// Implementation of Result
|
|
322
329
|
export class ResultImpl implements Result {
|
|
323
330
|
constructor(private raw: any) {}
|
|
324
|
-
|
|
325
|
-
get text(): string | undefined {
|
|
326
|
-
return this.raw.text || this.raw.data?.[
|
|
331
|
+
|
|
332
|
+
get text(): string | undefined {
|
|
333
|
+
return this.raw.text || this.raw.data?.["text/plain"];
|
|
327
334
|
}
|
|
328
|
-
|
|
329
|
-
get html(): string | undefined {
|
|
330
|
-
return this.raw.html || this.raw.data?.[
|
|
335
|
+
|
|
336
|
+
get html(): string | undefined {
|
|
337
|
+
return this.raw.html || this.raw.data?.["text/html"];
|
|
331
338
|
}
|
|
332
|
-
|
|
333
|
-
get png(): string | undefined {
|
|
334
|
-
return this.raw.png || this.raw.data?.[
|
|
339
|
+
|
|
340
|
+
get png(): string | undefined {
|
|
341
|
+
return this.raw.png || this.raw.data?.["image/png"];
|
|
335
342
|
}
|
|
336
|
-
|
|
337
|
-
get jpeg(): string | undefined {
|
|
338
|
-
return this.raw.jpeg || this.raw.data?.[
|
|
343
|
+
|
|
344
|
+
get jpeg(): string | undefined {
|
|
345
|
+
return this.raw.jpeg || this.raw.data?.["image/jpeg"];
|
|
339
346
|
}
|
|
340
|
-
|
|
341
|
-
get svg(): string | undefined {
|
|
342
|
-
return this.raw.svg || this.raw.data?.[
|
|
347
|
+
|
|
348
|
+
get svg(): string | undefined {
|
|
349
|
+
return this.raw.svg || this.raw.data?.["image/svg+xml"];
|
|
343
350
|
}
|
|
344
|
-
|
|
345
|
-
get latex(): string | undefined {
|
|
346
|
-
return this.raw.latex || this.raw.data?.[
|
|
351
|
+
|
|
352
|
+
get latex(): string | undefined {
|
|
353
|
+
return this.raw.latex || this.raw.data?.["text/latex"];
|
|
347
354
|
}
|
|
348
|
-
|
|
349
|
-
get markdown(): string | undefined {
|
|
350
|
-
return this.raw.markdown || this.raw.data?.[
|
|
355
|
+
|
|
356
|
+
get markdown(): string | undefined {
|
|
357
|
+
return this.raw.markdown || this.raw.data?.["text/markdown"];
|
|
351
358
|
}
|
|
352
|
-
|
|
353
|
-
get javascript(): string | undefined {
|
|
354
|
-
return this.raw.javascript || this.raw.data?.[
|
|
359
|
+
|
|
360
|
+
get javascript(): string | undefined {
|
|
361
|
+
return this.raw.javascript || this.raw.data?.["application/javascript"];
|
|
355
362
|
}
|
|
356
|
-
|
|
357
|
-
get json(): any {
|
|
358
|
-
return this.raw.json || this.raw.data?.[
|
|
363
|
+
|
|
364
|
+
get json(): any {
|
|
365
|
+
return this.raw.json || this.raw.data?.["application/json"];
|
|
359
366
|
}
|
|
360
|
-
|
|
361
|
-
get chart(): ChartData | undefined {
|
|
362
|
-
return this.raw.chart;
|
|
367
|
+
|
|
368
|
+
get chart(): ChartData | undefined {
|
|
369
|
+
return this.raw.chart;
|
|
363
370
|
}
|
|
364
|
-
|
|
365
|
-
get data(): any {
|
|
366
|
-
return this.raw.data;
|
|
371
|
+
|
|
372
|
+
get data(): any {
|
|
373
|
+
return this.raw.data;
|
|
367
374
|
}
|
|
368
|
-
|
|
375
|
+
|
|
369
376
|
formats(): string[] {
|
|
370
377
|
const formats: string[] = [];
|
|
371
|
-
if (this.text) formats.push(
|
|
372
|
-
if (this.html) formats.push(
|
|
373
|
-
if (this.png) formats.push(
|
|
374
|
-
if (this.jpeg) formats.push(
|
|
375
|
-
if (this.svg) formats.push(
|
|
376
|
-
if (this.latex) formats.push(
|
|
377
|
-
if (this.markdown) formats.push(
|
|
378
|
-
if (this.javascript) formats.push(
|
|
379
|
-
if (this.json) formats.push(
|
|
380
|
-
if (this.chart) formats.push(
|
|
378
|
+
if (this.text) formats.push("text");
|
|
379
|
+
if (this.html) formats.push("html");
|
|
380
|
+
if (this.png) formats.push("png");
|
|
381
|
+
if (this.jpeg) formats.push("jpeg");
|
|
382
|
+
if (this.svg) formats.push("svg");
|
|
383
|
+
if (this.latex) formats.push("latex");
|
|
384
|
+
if (this.markdown) formats.push("markdown");
|
|
385
|
+
if (this.javascript) formats.push("javascript");
|
|
386
|
+
if (this.json) formats.push("json");
|
|
387
|
+
if (this.chart) formats.push("chart");
|
|
381
388
|
return formats;
|
|
382
389
|
}
|
|
383
|
-
}
|
|
390
|
+
}
|