@ebowwa/sandbox 0.1.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.
Files changed (108) hide show
  1. package/dist/compilers/index.d.ts +24 -0
  2. package/dist/compilers/index.d.ts.map +1 -0
  3. package/dist/compilers/index.js +42 -0
  4. package/dist/compilers/index.js.map +1 -0
  5. package/dist/compilers/javascript.d.ts +117 -0
  6. package/dist/compilers/javascript.d.ts.map +1 -0
  7. package/dist/compilers/javascript.js +462 -0
  8. package/dist/compilers/javascript.js.map +1 -0
  9. package/dist/compilers/python.d.ts +140 -0
  10. package/dist/compilers/python.d.ts.map +1 -0
  11. package/dist/compilers/python.js +650 -0
  12. package/dist/compilers/python.js.map +1 -0
  13. package/dist/compilers/typescript.d.ts +99 -0
  14. package/dist/compilers/typescript.d.ts.map +1 -0
  15. package/dist/compilers/typescript.js +323 -0
  16. package/dist/compilers/typescript.js.map +1 -0
  17. package/dist/core/cell.d.ts +160 -0
  18. package/dist/core/cell.d.ts.map +1 -0
  19. package/dist/core/cell.js +319 -0
  20. package/dist/core/cell.js.map +1 -0
  21. package/dist/core/compiler.d.ts +126 -0
  22. package/dist/core/compiler.d.ts.map +1 -0
  23. package/dist/core/compiler.js +123 -0
  24. package/dist/core/compiler.js.map +1 -0
  25. package/dist/core/index.d.ts +19 -0
  26. package/dist/core/index.d.ts.map +1 -0
  27. package/dist/core/index.js +14 -0
  28. package/dist/core/index.js.map +1 -0
  29. package/dist/core/limits.d.ts +173 -0
  30. package/dist/core/limits.d.ts.map +1 -0
  31. package/dist/core/limits.js +440 -0
  32. package/dist/core/limits.js.map +1 -0
  33. package/dist/core/permissions.d.ts +103 -0
  34. package/dist/core/permissions.d.ts.map +1 -0
  35. package/dist/core/permissions.js +341 -0
  36. package/dist/core/permissions.js.map +1 -0
  37. package/dist/core/runtime.d.ts +127 -0
  38. package/dist/core/runtime.d.ts.map +1 -0
  39. package/dist/core/runtime.js +325 -0
  40. package/dist/core/runtime.js.map +1 -0
  41. package/dist/core/types.d.ts +380 -0
  42. package/dist/core/types.d.ts.map +1 -0
  43. package/dist/core/types.js +67 -0
  44. package/dist/core/types.js.map +1 -0
  45. package/dist/index.d.ts +145 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +279 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/multi/index.d.ts +9 -0
  50. package/dist/multi/index.d.ts.map +1 -0
  51. package/dist/multi/index.js +7 -0
  52. package/dist/multi/index.js.map +1 -0
  53. package/dist/multi/polyglot.d.ts +179 -0
  54. package/dist/multi/polyglot.d.ts.map +1 -0
  55. package/dist/multi/polyglot.js +319 -0
  56. package/dist/multi/polyglot.js.map +1 -0
  57. package/dist/runtimes/docker.d.ts +97 -0
  58. package/dist/runtimes/docker.d.ts.map +1 -0
  59. package/dist/runtimes/docker.js +368 -0
  60. package/dist/runtimes/docker.js.map +1 -0
  61. package/dist/runtimes/index.d.ts +11 -0
  62. package/dist/runtimes/index.d.ts.map +1 -0
  63. package/dist/runtimes/index.js +9 -0
  64. package/dist/runtimes/index.js.map +1 -0
  65. package/dist/runtimes/process.d.ts +47 -0
  66. package/dist/runtimes/process.d.ts.map +1 -0
  67. package/dist/runtimes/process.js +230 -0
  68. package/dist/runtimes/process.js.map +1 -0
  69. package/dist/session/index.d.ts +12 -0
  70. package/dist/session/index.d.ts.map +1 -0
  71. package/dist/session/index.js +9 -0
  72. package/dist/session/index.js.map +1 -0
  73. package/dist/session/kernel.d.ts +199 -0
  74. package/dist/session/kernel.d.ts.map +1 -0
  75. package/dist/session/kernel.js +400 -0
  76. package/dist/session/kernel.js.map +1 -0
  77. package/dist/session/notebook.d.ts +168 -0
  78. package/dist/session/notebook.d.ts.map +1 -0
  79. package/dist/session/notebook.js +499 -0
  80. package/dist/session/notebook.js.map +1 -0
  81. package/dist/session/repl.d.ts +159 -0
  82. package/dist/session/repl.d.ts.map +1 -0
  83. package/dist/session/repl.js +409 -0
  84. package/dist/session/repl.js.map +1 -0
  85. package/package.json +142 -0
  86. package/src/compilers/index.ts +80 -0
  87. package/src/compilers/javascript.ts +571 -0
  88. package/src/compilers/python.ts +785 -0
  89. package/src/compilers/typescript.ts +442 -0
  90. package/src/core/cell.ts +439 -0
  91. package/src/core/compiler.ts +250 -0
  92. package/src/core/index.ts +123 -0
  93. package/src/core/limits.ts +508 -0
  94. package/src/core/permissions.ts +409 -0
  95. package/src/core/runtime.ts +499 -0
  96. package/src/core/types.ts +528 -0
  97. package/src/global.d.ts +59 -0
  98. package/src/index.ts +515 -0
  99. package/src/multi/index.ts +22 -0
  100. package/src/multi/polyglot.ts +461 -0
  101. package/src/runtimes/docker.ts +501 -0
  102. package/src/runtimes/index.ts +21 -0
  103. package/src/runtimes/process.ts +316 -0
  104. package/src/session/index.ts +41 -0
  105. package/src/session/kernel.ts +553 -0
  106. package/src/session/notebook.ts +635 -0
  107. package/src/session/repl.ts +521 -0
  108. package/src/wasm2wasm.d.ts +35 -0
@@ -0,0 +1,635 @@
1
+ /**
2
+ * Notebook Primitive
3
+ *
4
+ * Multi-cell, multi-language document with sequential execution.
5
+ * Jupyter-style notebook with cell dependencies and state sharing.
6
+ */
7
+
8
+ import type {
9
+ Language,
10
+ Notebook,
11
+ NotebookMetadata,
12
+ NotebookRunOptions,
13
+ NotebookResult,
14
+ Cell,
15
+ ExecutionResult,
16
+ ExecutionOptions,
17
+ Permissions,
18
+ Limits,
19
+ } from "../core/types.js";
20
+ import { CellRegistry, CellBuilder } from "../core/cell.js";
21
+ import type { ExecutableCell, CellState } from "../core/cell.js";
22
+ import { BaseKernel, KernelManager } from "./kernel.js";
23
+ import type { KernelOptions } from "./kernel.js";
24
+ import { createPermissions } from "../core/permissions.js";
25
+ import { v4 as uuid } from "uuid";
26
+
27
+ /**
28
+ * Notebook options
29
+ */
30
+ export interface NotebookOptions {
31
+ /** Notebook ID */
32
+ id?: string;
33
+ /** Notebook name */
34
+ name?: string;
35
+ /** Default language */
36
+ defaultLanguage?: Language;
37
+ /** Initial cells */
38
+ cells?: Cell[];
39
+ /** Permissions */
40
+ permissions?: Permissions;
41
+ /** Resource limits */
42
+ limits?: Limits;
43
+ /** Kernel manager to use */
44
+ kernelManager?: KernelManager;
45
+ /** Kernel factory */
46
+ kernelFactory?: (language: Language) => Promise<BaseKernel>;
47
+ }
48
+
49
+ /**
50
+ * Notebook state
51
+ */
52
+ export type NotebookState =
53
+ | "idle"
54
+ | "running"
55
+ | "error"
56
+ | "cancelled";
57
+
58
+ /**
59
+ * Notebook events
60
+ */
61
+ export interface NotebookEvents {
62
+ onCellStart?: (cellId: string, cell: ExecutableCell) => void;
63
+ onCellComplete?: (cellId: string, result: ExecutionResult) => void;
64
+ onCellError?: (cellId: string, error: Error) => void;
65
+ onNotebookComplete?: (results: NotebookResult[]) => void;
66
+ onNotebookError?: (error: Error) => void;
67
+ onProgress?: (completed: number, total: number) => void;
68
+ }
69
+
70
+ /**
71
+ * Base Notebook Implementation
72
+ */
73
+ export class BaseNotebook implements Notebook {
74
+ readonly id: string;
75
+ readonly metadata: NotebookMetadata;
76
+
77
+ private registry: CellRegistry;
78
+ private kernelManager: KernelManager;
79
+ private kernelFactory?: (language: Language) => Promise<BaseKernel>;
80
+ private kernels = new Map<Language, BaseKernel>();
81
+ private permissions: Permissions;
82
+ private limits: Limits;
83
+ private state: NotebookState = "idle";
84
+ private executionCount = 0;
85
+ private events: NotebookEvents = {};
86
+ private abortController?: AbortController;
87
+
88
+ constructor(options: NotebookOptions) {
89
+ this.id = options.id ?? uuid();
90
+ this.registry = new CellRegistry();
91
+ this.kernelManager = options.kernelManager ?? new KernelManager();
92
+ this.kernelFactory = options.kernelFactory;
93
+ this.permissions = options.permissions ?? {};
94
+ this.limits = options.limits ?? {};
95
+
96
+ this.metadata = {
97
+ name: options.name ?? "Untitled",
98
+ language: options.defaultLanguage ?? "javascript",
99
+ created: new Date(),
100
+ modified: new Date(),
101
+ };
102
+
103
+ // Add initial cells
104
+ if (options.cells) {
105
+ for (const cell of options.cells) {
106
+ this.addCell(cell);
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Get current state
113
+ */
114
+ getState(): NotebookState {
115
+ return this.state;
116
+ }
117
+
118
+ /**
119
+ * Set event handlers
120
+ */
121
+ setEvents(events: NotebookEvents): void {
122
+ this.events = { ...this.events, ...events };
123
+ }
124
+
125
+ /**
126
+ * Get all cells
127
+ */
128
+ get cells(): ExecutableCell[] {
129
+ return this.registry.getAll();
130
+ }
131
+
132
+ /**
133
+ * Add cell
134
+ */
135
+ addCell(cell: Omit<Cell, "id">): Cell {
136
+ const executableCell: ExecutableCell = {
137
+ ...cell,
138
+ id: uuid(),
139
+ state: "idle",
140
+ metadata: {
141
+ ...cell.metadata,
142
+ index: this.registry.count,
143
+ },
144
+ };
145
+
146
+ this.registry.add(executableCell);
147
+ this.metadata.modified = new Date();
148
+
149
+ return executableCell;
150
+ }
151
+
152
+ /**
153
+ * Remove cell
154
+ */
155
+ removeCell(cellId: string): void {
156
+ this.registry.remove(cellId);
157
+ this.metadata.modified = new Date();
158
+ }
159
+
160
+ /**
161
+ * Move cell
162
+ */
163
+ moveCell(cellId: string, newIndex: number): void {
164
+ const cell = this.registry.get(cellId);
165
+ if (!cell) return;
166
+
167
+ cell.metadata = { ...cell.metadata, index: newIndex };
168
+ this.metadata.modified = new Date();
169
+ }
170
+
171
+ /**
172
+ * Get cell by ID
173
+ */
174
+ getCell(cellId: string): Cell | undefined {
175
+ return this.registry.get(cellId);
176
+ }
177
+
178
+ /**
179
+ * Update cell source
180
+ */
181
+ updateCell(cellId: string, source: string): void {
182
+ const cell = this.registry.get(cellId);
183
+ if (!cell) return;
184
+
185
+ cell.source = source;
186
+ cell.state = "idle"; // Reset state on edit
187
+ cell.result = undefined;
188
+ this.metadata.modified = new Date();
189
+ }
190
+
191
+ /**
192
+ * Get or create kernel for language
193
+ */
194
+ private async getKernel(language: Language): Promise<BaseKernel> {
195
+ let kernel = this.kernels.get(language);
196
+
197
+ if (!kernel) {
198
+ if (this.kernelFactory) {
199
+ kernel = await this.kernelFactory(language);
200
+ } else {
201
+ // Create a basic kernel - would need proper compiler/runtime
202
+ throw new Error(`No kernel available for language: ${language}`);
203
+ }
204
+
205
+ this.kernels.set(language, kernel);
206
+ }
207
+
208
+ return kernel;
209
+ }
210
+
211
+ /**
212
+ * Execute all cells
213
+ */
214
+ async runAll(options?: NotebookRunOptions): Promise<NotebookResult[]> {
215
+ if (this.state === "running") {
216
+ throw new Error("Notebook is already running");
217
+ }
218
+
219
+ this.state = "running";
220
+ this.abortController = new AbortController();
221
+ const results: NotebookResult[] = [];
222
+ const executionOrder = this.registry.getExecutionOrder();
223
+ const total = executionOrder.length;
224
+ let completed = 0;
225
+
226
+ // Find start index
227
+ let startIndex = 0;
228
+ if (options?.continueFrom) {
229
+ startIndex = executionOrder.indexOf(options.continueFrom);
230
+ if (startIndex === -1) startIndex = 0;
231
+ }
232
+
233
+ try {
234
+ for (let i = startIndex; i < executionOrder.length; i++) {
235
+ // Check for abort
236
+ if (this.abortController.signal.aborted) {
237
+ this.state = "cancelled";
238
+ break;
239
+ }
240
+
241
+ const cellId = executionOrder[i];
242
+ const result = await this.runCell(cellId, {
243
+ signal: this.abortController.signal,
244
+ });
245
+
246
+ results.push(result);
247
+ completed++;
248
+ this.events.onProgress?.(completed, total);
249
+
250
+ // Stop on error
251
+ if (!result.result.success && options?.stopOnError !== false) {
252
+ this.state = "error";
253
+ break;
254
+ }
255
+ }
256
+
257
+ if (this.state === "running") {
258
+ this.state = "idle";
259
+ }
260
+
261
+ this.events.onNotebookComplete?.(results);
262
+ return results;
263
+ } catch (error) {
264
+ this.state = "error";
265
+ this.events.onNotebookError?.(error instanceof Error ? error : new Error(String(error)));
266
+ throw error;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Execute single cell
272
+ */
273
+ async runCell(
274
+ cellId: string,
275
+ options?: ExecutionOptions
276
+ ): Promise<NotebookResult> {
277
+ const cell = this.registry.get(cellId);
278
+ if (!cell) {
279
+ throw new Error(`Cell not found: ${cellId}`);
280
+ }
281
+
282
+ cell.state = "queued";
283
+ this.events.onCellStart?.(cellId, cell);
284
+
285
+ try {
286
+ // Get kernel for language
287
+ const kernel = await this.getKernel(cell.language);
288
+
289
+ // Execute
290
+ cell.state = "running";
291
+ const result = await kernel.execute(cell.source, options);
292
+
293
+ // Update cell
294
+ cell.result = result;
295
+ cell.state = result.success ? "success" : "error";
296
+ cell.executionCount = ++this.executionCount;
297
+ cell.lastRun = new Date();
298
+
299
+ this.events.onCellComplete?.(cellId, result);
300
+
301
+ return {
302
+ cellId,
303
+ executionCount: cell.executionCount,
304
+ result,
305
+ timestamp: new Date(),
306
+ };
307
+ } catch (error) {
308
+ cell.state = "error";
309
+ const err = error instanceof Error ? error : new Error(String(error));
310
+ this.events.onCellError?.(cellId, err);
311
+
312
+ const result: ExecutionResult = {
313
+ success: false,
314
+ error: {
315
+ message: err.message,
316
+ type: "runtime",
317
+ },
318
+ metrics: { duration: 0, memoryUsed: 0 },
319
+ output: { stdout: [], stderr: [], displays: [] },
320
+ };
321
+
322
+ cell.result = result;
323
+
324
+ return {
325
+ cellId,
326
+ executionCount: ++this.executionCount,
327
+ result,
328
+ timestamp: new Date(),
329
+ };
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Execute cells from index
335
+ */
336
+ async runFrom(startIndex: number): Promise<NotebookResult[]> {
337
+ const cells = this.registry
338
+ .getAll()
339
+ .sort((a, b) => ((a.metadata?.index as number) ?? 0) - ((b.metadata?.index as number) ?? 0));
340
+
341
+ if (startIndex >= cells.length) {
342
+ return [];
343
+ }
344
+
345
+ const startCell = cells[startIndex];
346
+ return this.runAll({ continueFrom: startCell.id });
347
+ }
348
+
349
+ /**
350
+ * Run cells that depend on a changed cell
351
+ */
352
+ async runDependents(cellId: string): Promise<NotebookResult[]> {
353
+ const toReexecute = this.registry.getCellsToReexecute(cellId);
354
+ const results: NotebookResult[] = [];
355
+
356
+ for (const depId of toReexecute) {
357
+ const result = await this.runCell(depId);
358
+ results.push(result);
359
+
360
+ if (!result.result.success) {
361
+ break;
362
+ }
363
+ }
364
+
365
+ return results;
366
+ }
367
+
368
+ /**
369
+ * Cancel execution
370
+ */
371
+ cancel(): void {
372
+ if (this.abortController) {
373
+ this.abortController.abort();
374
+ }
375
+ }
376
+
377
+ /**
378
+ * Clear all cell outputs
379
+ */
380
+ clearOutputs(): void {
381
+ for (const cell of this.registry.getAll()) {
382
+ cell.result = undefined;
383
+ cell.state = "idle";
384
+ }
385
+ this.executionCount = 0;
386
+ }
387
+
388
+ /**
389
+ * Restart all kernels
390
+ */
391
+ async restart(): Promise<void> {
392
+ for (const kernel of this.kernels.values()) {
393
+ await kernel.restart();
394
+ }
395
+ this.clearOutputs();
396
+ }
397
+
398
+ /**
399
+ * Export notebook
400
+ */
401
+ export(format: "ipynb" | "json" | "markdown"): string {
402
+ switch (format) {
403
+ case "ipynb":
404
+ return this.toIpynb();
405
+ case "json":
406
+ return this.toJson();
407
+ case "markdown":
408
+ return this.toMarkdown();
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Import notebook
414
+ */
415
+ static import(data: string, format: "ipynb" | "json" | "markdown"): BaseNotebook {
416
+ switch (format) {
417
+ case "ipynb":
418
+ return BaseNotebook.fromIpynb(data);
419
+ case "json":
420
+ return BaseNotebook.fromJson(data);
421
+ case "markdown":
422
+ return BaseNotebook.fromMarkdown(data);
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Export to Jupyter format
428
+ */
429
+ private toIpynb(): string {
430
+ const cells = this.registry.getAll().sort(
431
+ (a, b) => ((a.metadata?.index as number) ?? 0) - ((b.metadata?.index as number) ?? 0)
432
+ );
433
+
434
+ const ipynb = {
435
+ nbformat: 4,
436
+ nbformat_minor: 5,
437
+ metadata: {
438
+ kernelspec: {
439
+ display_name: this.metadata.name,
440
+ language: this.metadata.language,
441
+ name: this.metadata.language,
442
+ },
443
+ language_info: {
444
+ name: this.metadata.language,
445
+ },
446
+ },
447
+ cells: cells.map(cell => ({
448
+ id: cell.id,
449
+ cell_type: "code",
450
+ metadata: cell.metadata ?? {},
451
+ source: cell.source.split("\n"),
452
+ execution_count: cell.executionCount ?? null,
453
+ outputs: this.cellToOutputs(cell),
454
+ })),
455
+ };
456
+
457
+ return JSON.stringify(ipynb, null, 2);
458
+ }
459
+
460
+ /**
461
+ * Export to JSON
462
+ */
463
+ private toJson(): string {
464
+ return JSON.stringify({
465
+ id: this.id,
466
+ metadata: this.metadata,
467
+ cells: this.registry.getAll(),
468
+ }, null, 2);
469
+ }
470
+
471
+ /**
472
+ * Export to Markdown
473
+ */
474
+ private toMarkdown(): string {
475
+ const cells = this.registry.getAll().sort(
476
+ (a, b) => ((a.metadata?.index as number) ?? 0) - ((b.metadata?.index as number) ?? 0)
477
+ );
478
+
479
+ const lines: string[] = [
480
+ `# ${this.metadata.name}`,
481
+ "",
482
+ `> Language: ${this.metadata.language}`,
483
+ `> Created: ${this.metadata.created.toISOString()}`,
484
+ "",
485
+ ];
486
+
487
+ for (const cell of cells) {
488
+ const lang = cell.language === "javascript" ? "js" : cell.language;
489
+ lines.push(`\`\`\`${lang}`);
490
+ lines.push(cell.source);
491
+ lines.push("```");
492
+ lines.push("");
493
+
494
+ if (cell.result) {
495
+ if (cell.result.output.stdout.length > 0) {
496
+ lines.push("**Output:**");
497
+ lines.push("```");
498
+ lines.push(...cell.result.output.stdout);
499
+ lines.push("```");
500
+ lines.push("");
501
+ }
502
+ }
503
+ }
504
+
505
+ return lines.join("\n");
506
+ }
507
+
508
+ /**
509
+ * Import from Jupyter format
510
+ */
511
+ static fromIpynb(data: string): BaseNotebook {
512
+ const ipynb = JSON.parse(data);
513
+ const cells: Cell[] = [];
514
+
515
+ for (const cell of ipynb.cells ?? []) {
516
+ if (cell.cell_type === "code") {
517
+ cells.push({
518
+ id: cell.id ?? uuid(),
519
+ language: (ipynb.metadata?.language_info?.name as Language) ?? "python",
520
+ source: Array.isArray(cell.source)
521
+ ? cell.source.join("\n")
522
+ : cell.source,
523
+ metadata: cell.metadata,
524
+ });
525
+ }
526
+ }
527
+
528
+ return new BaseNotebook({
529
+ name: ipynb.metadata?.kernelspec?.display_name ?? "Imported Notebook",
530
+ defaultLanguage: ipynb.metadata?.language_info?.name,
531
+ cells,
532
+ });
533
+ }
534
+
535
+ /**
536
+ * Import from JSON
537
+ */
538
+ static fromJson(data: string): BaseNotebook {
539
+ const obj = JSON.parse(data);
540
+
541
+ return new BaseNotebook({
542
+ id: obj.id,
543
+ name: obj.metadata?.name,
544
+ defaultLanguage: obj.metadata?.language,
545
+ cells: obj.cells,
546
+ });
547
+ }
548
+
549
+ /**
550
+ * Import from Markdown
551
+ */
552
+ static fromMarkdown(data: string): BaseNotebook {
553
+ const cells: ExecutableCell[] = [];
554
+ const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
555
+ let match;
556
+ let index = 0;
557
+
558
+ // Extract title
559
+ const titleMatch = data.match(/^#\s+(.+)$/m);
560
+ const name = titleMatch ? titleMatch[1] : "Imported Notebook";
561
+
562
+ while ((match = codeBlockRegex.exec(data)) !== null) {
563
+ const lang = (match[1] as Language) ?? "javascript";
564
+ const source = match[2].trim();
565
+
566
+ cells.push({
567
+ id: uuid(),
568
+ language: lang,
569
+ source,
570
+ state: "idle",
571
+ metadata: { index: index++ },
572
+ });
573
+ }
574
+
575
+ const notebook = new BaseNotebook({ name, cells });
576
+ return notebook;
577
+ }
578
+
579
+ /**
580
+ * Convert cell outputs to Jupyter format
581
+ */
582
+ private cellToOutputs(cell: ExecutableCell): unknown[] {
583
+ const outputs: unknown[] = [];
584
+
585
+ if (!cell.result) return outputs;
586
+
587
+ // stdout
588
+ if (cell.result.output.stdout.length > 0) {
589
+ outputs.push({
590
+ output_type: "stream",
591
+ name: "stdout",
592
+ text: cell.result.output.stdout,
593
+ });
594
+ }
595
+
596
+ // stderr
597
+ if (cell.result.output.stderr.length > 0) {
598
+ outputs.push({
599
+ output_type: "stream",
600
+ name: "stderr",
601
+ text: cell.result.output.stderr,
602
+ });
603
+ }
604
+
605
+ // displays
606
+ for (const display of cell.result.output.displays) {
607
+ outputs.push({
608
+ output_type: "execute_result" as const,
609
+ data: {
610
+ [`text/${display.type}`]: display.data,
611
+ },
612
+ execution_count: cell.executionCount,
613
+ });
614
+ }
615
+
616
+ // error
617
+ if (cell.result.error) {
618
+ outputs.push({
619
+ output_type: "error",
620
+ ename: cell.result.error.type,
621
+ evalue: cell.result.error.message,
622
+ traceback: [cell.result.error.stack ?? ""],
623
+ });
624
+ }
625
+
626
+ return outputs;
627
+ }
628
+ }
629
+
630
+ /**
631
+ * Create a notebook
632
+ */
633
+ export function createNotebook(options: NotebookOptions): BaseNotebook {
634
+ return new BaseNotebook(options);
635
+ }