@cloudflare/sandbox 0.2.1 → 0.2.2

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.
@@ -1,44 +1,52 @@
1
- import { HttpClient } from './client.js';
2
- import type {
3
- CodeContext,
4
- CreateContextOptions,
5
- ExecutionError,
1
+ import { HttpClient } from "./client.js";
2
+ import { isRetryableError, parseErrorResponse } from "./errors.js";
3
+ import type {
4
+ CodeContext,
5
+ CreateContextOptions,
6
+ ExecutionError,
6
7
  OutputMessage,
7
- Result
8
- } from './interpreter-types.js';
8
+ Result,
9
+ } from "./interpreter-types.js";
9
10
 
10
11
  // API Response types
11
12
  interface ContextResponse {
12
13
  id: string;
13
14
  language: string;
14
15
  cwd: string;
15
- createdAt: string; // ISO date string from JSON
16
- lastUsed: string; // ISO date string from JSON
16
+ createdAt: string; // ISO date string from JSON
17
+ lastUsed: string; // ISO date string from JSON
17
18
  }
18
19
 
19
20
  interface ContextListResponse {
20
21
  contexts: ContextResponse[];
21
22
  }
22
23
 
23
- interface ErrorResponse {
24
- error: string;
25
- }
26
-
27
24
  // Streaming execution data from the server
28
25
  interface StreamingExecutionData {
29
- type: 'result' | 'stdout' | 'stderr' | 'error' | 'execution_complete';
26
+ type: "result" | "stdout" | "stderr" | "error" | "execution_complete";
30
27
  text?: string;
31
28
  html?: string;
32
- png?: string; // base64
33
- jpeg?: string; // base64
29
+ png?: string; // base64
30
+ jpeg?: string; // base64
34
31
  svg?: string;
35
32
  latex?: string;
36
33
  markdown?: string;
37
34
  javascript?: string;
38
- json?: any;
39
- chart?: any;
40
- data?: any;
41
- metadata?: any;
35
+ json?: unknown;
36
+ chart?: {
37
+ type:
38
+ | "line"
39
+ | "bar"
40
+ | "scatter"
41
+ | "pie"
42
+ | "histogram"
43
+ | "heatmap"
44
+ | "unknown";
45
+ data: unknown;
46
+ options?: unknown;
47
+ };
48
+ data?: unknown;
49
+ metadata?: Record<string, unknown>;
42
50
  execution_count?: number;
43
51
  ename?: string;
44
52
  evalue?: string;
@@ -55,70 +63,79 @@ export interface ExecutionCallbacks {
55
63
  }
56
64
 
57
65
  export class JupyterClient extends HttpClient {
58
- async createCodeContext(options: CreateContextOptions = {}): Promise<CodeContext> {
59
- const response = await this.doFetch('/api/contexts', {
60
- method: 'POST',
61
- headers: { 'Content-Type': 'application/json' },
62
- body: JSON.stringify({
63
- language: options.language || 'python',
64
- cwd: options.cwd || '/workspace',
65
- env_vars: options.envVars
66
- }),
66
+ private readonly maxRetries = 3;
67
+ private readonly retryDelayMs = 1000;
68
+
69
+ async createCodeContext(
70
+ options: CreateContextOptions = {}
71
+ ): Promise<CodeContext> {
72
+ return this.executeWithRetry(async () => {
73
+ const response = await this.doFetch("/api/contexts", {
74
+ method: "POST",
75
+ headers: { "Content-Type": "application/json" },
76
+ body: JSON.stringify({
77
+ language: options.language || "python",
78
+ cwd: options.cwd || "/workspace",
79
+ env_vars: options.envVars,
80
+ }),
81
+ });
82
+
83
+ if (!response.ok) {
84
+ throw await parseErrorResponse(response);
85
+ }
86
+
87
+ const data = (await response.json()) as ContextResponse;
88
+ return {
89
+ id: data.id,
90
+ language: data.language,
91
+ cwd: data.cwd,
92
+ createdAt: new Date(data.createdAt),
93
+ lastUsed: new Date(data.lastUsed),
94
+ };
67
95
  });
68
-
69
- if (!response.ok) {
70
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;
71
- throw new Error(errorData.error || `Failed to create context: ${response.status}`);
72
- }
73
-
74
- const data = await response.json() as ContextResponse;
75
- return {
76
- id: data.id,
77
- language: data.language,
78
- cwd: data.cwd,
79
- createdAt: new Date(data.createdAt),
80
- lastUsed: new Date(data.lastUsed)
81
- };
82
96
  }
83
-
97
+
84
98
  async runCodeStream(
85
- contextId: string | undefined,
86
- code: string,
99
+ contextId: string | undefined,
100
+ code: string,
87
101
  language: string | undefined,
88
102
  callbacks: ExecutionCallbacks
89
103
  ): Promise<void> {
90
- const response = await this.doFetch('/api/execute/code', {
91
- method: 'POST',
92
- headers: {
93
- 'Content-Type': 'application/json',
94
- 'Accept': 'text/event-stream'
95
- },
96
- body: JSON.stringify({
97
- context_id: contextId,
98
- code,
99
- language
100
- }),
104
+ return this.executeWithRetry(async () => {
105
+ const response = await this.doFetch("/api/execute/code", {
106
+ method: "POST",
107
+ headers: {
108
+ "Content-Type": "application/json",
109
+ Accept: "text/event-stream",
110
+ },
111
+ body: JSON.stringify({
112
+ context_id: contextId,
113
+ code,
114
+ language,
115
+ }),
116
+ });
117
+
118
+ if (!response.ok) {
119
+ throw await parseErrorResponse(response);
120
+ }
121
+
122
+ if (!response.body) {
123
+ throw new Error("No response body for streaming execution");
124
+ }
125
+
126
+ // Process streaming response
127
+ for await (const chunk of this.readLines(response.body)) {
128
+ await this.parseExecutionResult(chunk, callbacks);
129
+ }
101
130
  });
102
-
103
- if (!response.ok) {
104
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;
105
- throw new Error(errorData.error || `Failed to execute code: ${response.status}`);
106
- }
107
-
108
- if (!response.body) {
109
- throw new Error('No response body for streaming execution');
110
- }
111
-
112
- // Process streaming response
113
- for await (const chunk of this.readLines(response.body)) {
114
- await this.parseExecutionResult(chunk, callbacks);
115
- }
116
131
  }
117
-
118
- private async *readLines(stream: ReadableStream<Uint8Array>): AsyncGenerator<string> {
132
+
133
+ private async *readLines(
134
+ stream: ReadableStream<Uint8Array>
135
+ ): AsyncGenerator<string> {
119
136
  const reader = stream.getReader();
120
- let buffer = '';
121
-
137
+ let buffer = "";
138
+
122
139
  try {
123
140
  while (true) {
124
141
  const { done, value } = await reader.read();
@@ -126,15 +143,15 @@ export class JupyterClient extends HttpClient {
126
143
  buffer += new TextDecoder().decode(value);
127
144
  }
128
145
  if (done) break;
129
-
130
- let newlineIdx = buffer.indexOf('\n');
146
+
147
+ let newlineIdx = buffer.indexOf("\n");
131
148
  while (newlineIdx !== -1) {
132
149
  yield buffer.slice(0, newlineIdx);
133
150
  buffer = buffer.slice(newlineIdx + 1);
134
- newlineIdx = buffer.indexOf('\n');
151
+ newlineIdx = buffer.indexOf("\n");
135
152
  }
136
153
  }
137
-
154
+
138
155
  // Yield any remaining data
139
156
  if (buffer.length > 0) {
140
157
  yield buffer;
@@ -143,33 +160,36 @@ export class JupyterClient extends HttpClient {
143
160
  reader.releaseLock();
144
161
  }
145
162
  }
146
-
147
- private async parseExecutionResult(line: string, callbacks: ExecutionCallbacks) {
163
+
164
+ private async parseExecutionResult(
165
+ line: string,
166
+ callbacks: ExecutionCallbacks
167
+ ) {
148
168
  if (!line.trim()) return;
149
-
169
+
150
170
  try {
151
171
  const data = JSON.parse(line) as StreamingExecutionData;
152
-
172
+
153
173
  switch (data.type) {
154
- case 'stdout':
174
+ case "stdout":
155
175
  if (callbacks.onStdout && data.text) {
156
176
  await callbacks.onStdout({
157
177
  text: data.text,
158
- timestamp: data.timestamp || Date.now()
178
+ timestamp: data.timestamp || Date.now(),
159
179
  });
160
180
  }
161
181
  break;
162
-
163
- case 'stderr':
182
+
183
+ case "stderr":
164
184
  if (callbacks.onStderr && data.text) {
165
185
  await callbacks.onStderr({
166
186
  text: data.text,
167
- timestamp: data.timestamp || Date.now()
187
+ timestamp: data.timestamp || Date.now(),
168
188
  });
169
189
  }
170
190
  break;
171
-
172
- case 'result':
191
+
192
+ case "result":
173
193
  if (callbacks.onResult) {
174
194
  // Convert raw result to Result interface
175
195
  const result: Result = {
@@ -186,81 +206,144 @@ export class JupyterClient extends HttpClient {
186
206
  data: data.data,
187
207
  formats: () => {
188
208
  const formats: string[] = [];
189
- if (data.text) formats.push('text');
190
- if (data.html) formats.push('html');
191
- if (data.png) formats.push('png');
192
- if (data.jpeg) formats.push('jpeg');
193
- if (data.svg) formats.push('svg');
194
- if (data.latex) formats.push('latex');
195
- if (data.markdown) formats.push('markdown');
196
- if (data.javascript) formats.push('javascript');
197
- if (data.json) formats.push('json');
198
- if (data.chart) formats.push('chart');
209
+ if (data.text) formats.push("text");
210
+ if (data.html) formats.push("html");
211
+ if (data.png) formats.push("png");
212
+ if (data.jpeg) formats.push("jpeg");
213
+ if (data.svg) formats.push("svg");
214
+ if (data.latex) formats.push("latex");
215
+ if (data.markdown) formats.push("markdown");
216
+ if (data.javascript) formats.push("javascript");
217
+ if (data.json) formats.push("json");
218
+ if (data.chart) formats.push("chart");
199
219
  return formats;
200
- }
220
+ },
201
221
  };
202
222
  await callbacks.onResult(result);
203
223
  }
204
224
  break;
205
-
206
- case 'error':
225
+
226
+ case "error":
207
227
  if (callbacks.onError) {
208
228
  await callbacks.onError({
209
- name: data.ename || 'Error',
210
- value: data.evalue || data.text || 'Unknown error',
229
+ name: data.ename || "Error",
230
+ value: data.evalue || data.text || "Unknown error",
211
231
  traceback: data.traceback || [],
212
- lineNumber: data.lineNumber
232
+ lineNumber: data.lineNumber,
213
233
  });
214
234
  }
215
235
  break;
216
-
217
- case 'execution_complete':
236
+
237
+ case "execution_complete":
218
238
  // Execution completed successfully
219
239
  break;
220
240
  }
221
241
  } catch (error) {
222
- console.error('[JupyterClient] Error parsing execution result:', error);
242
+ console.error("[JupyterClient] Error parsing execution result:", error);
223
243
  }
224
244
  }
225
-
245
+
226
246
  async listCodeContexts(): Promise<CodeContext[]> {
227
- const response = await this.doFetch('/api/contexts', {
228
- method: 'GET',
229
- headers: { 'Content-Type': 'application/json' }
247
+ return this.executeWithRetry(async () => {
248
+ const response = await this.doFetch("/api/contexts", {
249
+ method: "GET",
250
+ headers: { "Content-Type": "application/json" },
251
+ });
252
+
253
+ if (!response.ok) {
254
+ throw await parseErrorResponse(response);
255
+ }
256
+
257
+ const data = (await response.json()) as ContextListResponse;
258
+ return data.contexts.map((ctx) => ({
259
+ id: ctx.id,
260
+ language: ctx.language,
261
+ cwd: ctx.cwd,
262
+ createdAt: new Date(ctx.createdAt),
263
+ lastUsed: new Date(ctx.lastUsed),
264
+ }));
230
265
  });
231
-
232
- if (!response.ok) {
233
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;
234
- throw new Error(errorData.error || `Failed to list contexts: ${response.status}`);
235
- }
236
-
237
- const data = await response.json() as ContextListResponse;
238
- return data.contexts.map((ctx) => ({
239
- id: ctx.id,
240
- language: ctx.language,
241
- cwd: ctx.cwd,
242
- createdAt: new Date(ctx.createdAt),
243
- lastUsed: new Date(ctx.lastUsed)
244
- }));
245
266
  }
246
-
267
+
247
268
  async deleteCodeContext(contextId: string): Promise<void> {
248
- const response = await this.doFetch(`/api/contexts/${contextId}`, {
249
- method: 'DELETE',
250
- headers: { 'Content-Type': 'application/json' }
269
+ return this.executeWithRetry(async () => {
270
+ const response = await this.doFetch(`/api/contexts/${contextId}`, {
271
+ method: "DELETE",
272
+ headers: { "Content-Type": "application/json" },
273
+ });
274
+
275
+ if (!response.ok) {
276
+ throw await parseErrorResponse(response);
277
+ }
251
278
  });
252
-
253
- if (!response.ok) {
254
- const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;
255
- throw new Error(errorData.error || `Failed to delete context: ${response.status}`);
256
- }
257
279
  }
258
-
280
+
259
281
  // Override parent doFetch to be public for this class
260
- public async doFetch(
261
- path: string,
262
- options?: RequestInit
263
- ): Promise<Response> {
282
+ public async doFetch(path: string, options?: RequestInit): Promise<Response> {
264
283
  return super.doFetch(path, options);
265
284
  }
266
- }
285
+
286
+ /**
287
+ * Execute an operation with automatic retry for transient errors
288
+ */
289
+ private async executeWithRetry<T>(operation: () => Promise<T>): Promise<T> {
290
+ let lastError: Error | undefined;
291
+
292
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
293
+ try {
294
+ return await operation();
295
+ } catch (error) {
296
+ lastError = error as Error;
297
+
298
+ // Check if it's a retryable error (circuit breaker or Jupyter not ready)
299
+ if (this.isRetryableError(error)) {
300
+ // Don't retry on the last attempt
301
+ if (attempt < this.maxRetries - 1) {
302
+ // Exponential backoff with jitter
303
+ const delay =
304
+ this.retryDelayMs * 2 ** attempt + Math.random() * 1000;
305
+ await new Promise((resolve) => setTimeout(resolve, delay));
306
+ continue;
307
+ }
308
+ }
309
+
310
+ // Non-retryable error or last attempt - throw immediately
311
+ throw error;
312
+ }
313
+ }
314
+
315
+ // All retries exhausted - throw a clean error without implementation details
316
+ if (lastError?.message.includes("Code execution")) {
317
+ // If the error already has a clean message about code execution, use it
318
+ throw lastError;
319
+ }
320
+
321
+ // Otherwise, throw a generic but user-friendly error
322
+ throw new Error("Unable to execute code at this time");
323
+ }
324
+
325
+ /**
326
+ * Check if an error is retryable
327
+ */
328
+ private isRetryableError(error: unknown): boolean {
329
+ // Use the SDK's built-in retryable check
330
+ if (isRetryableError(error)) {
331
+ return true;
332
+ }
333
+
334
+ // Also check for circuit breaker specific errors
335
+ if (error instanceof Error) {
336
+ // Circuit breaker errors (from the container's response)
337
+ if (error.message.includes("Circuit breaker is open")) {
338
+ return true;
339
+ }
340
+
341
+ // Check if error has a status property
342
+ if ("status" in error && error.status === "circuit_open") {
343
+ return true;
344
+ }
345
+ }
346
+
347
+ return false;
348
+ }
349
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/jupyter-client.ts"],"sourcesContent":["import { HttpClient } from './client.js';\nimport type { \n CodeContext, \n CreateContextOptions, \n ExecutionError, \n OutputMessage,\n Result\n} from './interpreter-types.js';\n\n// API Response types\ninterface ContextResponse {\n id: string;\n language: string;\n cwd: string;\n createdAt: string; // ISO date string from JSON\n lastUsed: string; // ISO date string from JSON\n}\n\ninterface ContextListResponse {\n contexts: ContextResponse[];\n}\n\ninterface ErrorResponse {\n error: string;\n}\n\n// Streaming execution data from the server\ninterface StreamingExecutionData {\n type: 'result' | 'stdout' | 'stderr' | 'error' | 'execution_complete';\n text?: string;\n html?: string;\n png?: string; // base64\n jpeg?: string; // base64\n svg?: string;\n latex?: string;\n markdown?: string;\n javascript?: string;\n json?: any;\n chart?: any;\n data?: any;\n metadata?: any;\n execution_count?: number;\n ename?: string;\n evalue?: string;\n traceback?: string[];\n lineNumber?: number;\n timestamp?: number;\n}\n\nexport interface ExecutionCallbacks {\n onStdout?: (output: OutputMessage) => void | Promise<void>;\n onStderr?: (output: OutputMessage) => void | Promise<void>;\n onResult?: (result: Result) => void | Promise<void>;\n onError?: (error: ExecutionError) => void | Promise<void>;\n}\n\nexport class JupyterClient extends HttpClient {\n async createCodeContext(options: CreateContextOptions = {}): Promise<CodeContext> {\n const response = await this.doFetch('/api/contexts', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n language: options.language || 'python',\n cwd: options.cwd || '/workspace',\n env_vars: options.envVars\n }),\n });\n \n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;\n throw new Error(errorData.error || `Failed to create context: ${response.status}`);\n }\n \n const data = await response.json() as ContextResponse;\n return {\n id: data.id,\n language: data.language,\n cwd: data.cwd,\n createdAt: new Date(data.createdAt),\n lastUsed: new Date(data.lastUsed)\n };\n }\n \n async runCodeStream(\n contextId: string | undefined, \n code: string, \n language: string | undefined,\n callbacks: ExecutionCallbacks\n ): Promise<void> {\n const response = await this.doFetch('/api/execute/code', {\n method: 'POST',\n headers: { \n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream'\n },\n body: JSON.stringify({ \n context_id: contextId, \n code,\n language \n }),\n });\n \n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;\n throw new Error(errorData.error || `Failed to execute code: ${response.status}`);\n }\n \n if (!response.body) {\n throw new Error('No response body for streaming execution');\n }\n \n // Process streaming response\n for await (const chunk of this.readLines(response.body)) {\n await this.parseExecutionResult(chunk, callbacks);\n }\n }\n \n private async *readLines(stream: ReadableStream<Uint8Array>): AsyncGenerator<string> {\n const reader = stream.getReader();\n let buffer = '';\n \n try {\n while (true) {\n const { done, value } = await reader.read();\n if (value) {\n buffer += new TextDecoder().decode(value);\n }\n if (done) break;\n \n let newlineIdx = buffer.indexOf('\\n');\n while (newlineIdx !== -1) {\n yield buffer.slice(0, newlineIdx);\n buffer = buffer.slice(newlineIdx + 1);\n newlineIdx = buffer.indexOf('\\n');\n }\n }\n \n // Yield any remaining data\n if (buffer.length > 0) {\n yield buffer;\n }\n } finally {\n reader.releaseLock();\n }\n }\n \n private async parseExecutionResult(line: string, callbacks: ExecutionCallbacks) {\n if (!line.trim()) return;\n \n try {\n const data = JSON.parse(line) as StreamingExecutionData;\n \n switch (data.type) {\n case 'stdout':\n if (callbacks.onStdout && data.text) {\n await callbacks.onStdout({\n text: data.text,\n timestamp: data.timestamp || Date.now()\n });\n }\n break;\n \n case 'stderr':\n if (callbacks.onStderr && data.text) {\n await callbacks.onStderr({\n text: data.text,\n timestamp: data.timestamp || Date.now()\n });\n }\n break;\n \n case 'result':\n if (callbacks.onResult) {\n // Convert raw result to Result interface\n const result: Result = {\n text: data.text,\n html: data.html,\n png: data.png,\n jpeg: data.jpeg,\n svg: data.svg,\n latex: data.latex,\n markdown: data.markdown,\n javascript: data.javascript,\n json: data.json,\n chart: data.chart,\n data: data.data,\n formats: () => {\n const formats: string[] = [];\n if (data.text) formats.push('text');\n if (data.html) formats.push('html');\n if (data.png) formats.push('png');\n if (data.jpeg) formats.push('jpeg');\n if (data.svg) formats.push('svg');\n if (data.latex) formats.push('latex');\n if (data.markdown) formats.push('markdown');\n if (data.javascript) formats.push('javascript');\n if (data.json) formats.push('json');\n if (data.chart) formats.push('chart');\n return formats;\n }\n };\n await callbacks.onResult(result);\n }\n break;\n \n case 'error':\n if (callbacks.onError) {\n await callbacks.onError({\n name: data.ename || 'Error',\n value: data.evalue || data.text || 'Unknown error',\n traceback: data.traceback || [],\n lineNumber: data.lineNumber\n });\n }\n break;\n \n case 'execution_complete':\n // Execution completed successfully\n break;\n }\n } catch (error) {\n console.error('[JupyterClient] Error parsing execution result:', error);\n }\n }\n \n async listCodeContexts(): Promise<CodeContext[]> {\n const response = await this.doFetch('/api/contexts', {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' }\n });\n \n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;\n throw new Error(errorData.error || `Failed to list contexts: ${response.status}`);\n }\n \n const data = await response.json() as ContextListResponse;\n return data.contexts.map((ctx) => ({\n id: ctx.id,\n language: ctx.language,\n cwd: ctx.cwd,\n createdAt: new Date(ctx.createdAt),\n lastUsed: new Date(ctx.lastUsed)\n }));\n }\n \n async deleteCodeContext(contextId: string): Promise<void> {\n const response = await this.doFetch(`/api/contexts/${contextId}`, {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' }\n });\n \n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as ErrorResponse;\n throw new Error(errorData.error || `Failed to delete context: ${response.status}`);\n }\n }\n \n // Override parent doFetch to be public for this class\n public async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n return super.doFetch(path, options);\n }\n}"],"mappings":"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","names":[]}