@marimo-team/islands 0.23.16-dev9 → 0.23.17-dev0

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 (164) hide show
  1. package/dist/{chat-ui-JeekqoMH.js → chat-ui-DsZJj75A.js} +3104 -3107
  2. package/dist/{code-visibility-DveLKNtj.js → common-CotPLtrU.js} +1068 -1036
  3. package/dist/{formats-CO8cn5_K.js → formats-Dwq1THhr.js} +1 -1
  4. package/dist/{html-to-image-Bif4utQZ.js → html-to-image-CZ1kLKkq.js} +7336 -6342
  5. package/dist/main.js +211 -147
  6. package/dist/{node-sql-parser-DLl_zNw0.js → node-sql-parser-v1Vi-Fft.js} +16867 -16665
  7. package/dist/{process-output-TAzy-GUk.js → process-output-bVfbcx5_.js} +30 -26
  8. package/dist/{reveal-component-DxV4Ppa2.js → reveal-component-IoHipy82.js} +634 -626
  9. package/dist/style.css +1 -1
  10. package/dist/toDate-CqhBWjvO.js +713 -0
  11. package/dist/{vega-component-DphdxaJ_.js → vega-component-C7nO5zcf.js} +2 -2
  12. package/package.json +3 -4
  13. package/src/__mocks__/requests.ts +56 -4
  14. package/src/components/data-table/__tests__/__snapshots__/chart-spec-model.test.ts.snap +174 -21
  15. package/src/components/data-table/__tests__/chart-spec-model.test.ts +102 -1
  16. package/src/components/data-table/__tests__/columns.test.tsx +9 -1
  17. package/src/components/data-table/column-summary/chart-spec-model.tsx +163 -103
  18. package/src/components/data-table/column-summary/legacy-chart-spec.ts +15 -7
  19. package/src/components/data-table/column-summary/utils.ts +26 -7
  20. package/src/components/data-table/columns.tsx +11 -1
  21. package/src/components/data-table/types.ts +1 -1
  22. package/src/components/editor/__tests__/viewer-banner.test.tsx +14 -0
  23. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +99 -18
  24. package/src/components/editor/actions/__tests__/pdf-export.test.ts +32 -13
  25. package/src/components/editor/actions/pair-with-agent-commands.ts +21 -10
  26. package/src/components/editor/actions/pair-with-agent-modal.tsx +2 -2
  27. package/src/components/editor/actions/pdf-export.ts +11 -14
  28. package/src/components/editor/actions/useNotebookActions.tsx +28 -19
  29. package/src/components/editor/cell/code/__tests__/cell-editor-activity-lifecycle.test.ts +250 -0
  30. package/src/components/editor/cell/code/cell-editor.tsx +13 -7
  31. package/src/components/editor/chrome/__tests__/state.test.ts +7 -1
  32. package/src/components/editor/chrome/panels/__tests__/logs-panel.test.tsx +25 -0
  33. package/src/components/editor/chrome/panels/__tests__/panel-accordion-state.test.ts +42 -0
  34. package/src/components/editor/chrome/panels/file-explorer-panel.tsx +6 -17
  35. package/src/components/editor/chrome/panels/logs-panel.tsx +12 -2
  36. package/src/components/editor/chrome/panels/panel-accordion-state.ts +51 -0
  37. package/src/components/editor/chrome/panels/session-panel.tsx +5 -16
  38. package/src/components/editor/chrome/panels/write-secret-modal.tsx +40 -12
  39. package/src/components/editor/chrome/state.ts +10 -0
  40. package/src/components/editor/connections/__tests__/json-credentials.test.ts +114 -0
  41. package/src/components/editor/connections/__tests__/paths.test.ts +39 -0
  42. package/src/components/editor/connections/__tests__/quick-add-data-sources.test.tsx +113 -0
  43. package/src/components/editor/connections/add-connection-dialog.tsx +2 -0
  44. package/src/components/editor/connections/components.tsx +6 -2
  45. package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +27 -5
  46. package/src/components/editor/connections/database/__tests__/as-code.test.ts +33 -0
  47. package/src/components/editor/connections/database/as-code.ts +37 -13
  48. package/src/components/editor/connections/database/schemas.ts +6 -5
  49. package/src/components/editor/connections/form-renderers.tsx +99 -1
  50. package/src/components/editor/connections/json-credentials.ts +57 -0
  51. package/src/components/editor/connections/paths.ts +21 -0
  52. package/src/components/editor/connections/quick-add-data-sources.tsx +106 -0
  53. package/src/components/editor/connections/secret-combobox.tsx +41 -20
  54. package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +88 -2
  55. package/src/components/editor/connections/storage/__tests__/as-code.test.ts +128 -8
  56. package/src/components/editor/connections/storage/as-code.ts +79 -36
  57. package/src/components/editor/connections/storage/schemas.ts +85 -44
  58. package/src/components/editor/file-tree/__tests__/renderers.test.ts +31 -0
  59. package/src/components/editor/file-tree/file-viewer.tsx +11 -7
  60. package/src/components/editor/file-tree/renderers.tsx +21 -0
  61. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +2 -2
  62. package/src/components/editor/viewer-banner.tsx +6 -1
  63. package/src/components/forms/form.tsx +59 -24
  64. package/src/components/forms/options.ts +2 -1
  65. package/src/components/slides/__tests__/cell-output-block.test.tsx +40 -0
  66. package/src/components/slides/__tests__/slide-cell-view.test.tsx +33 -0
  67. package/src/components/slides/reveal-component.tsx +22 -17
  68. package/src/components/slides/slide-cell-view.tsx +1 -1
  69. package/src/components/slides/slides.css +4 -2
  70. package/src/components/static-html/share-modal.tsx +1 -1
  71. package/src/core/ai/context/providers/file.ts +8 -29
  72. package/src/core/cells/__tests__/cells.test.ts +12 -2
  73. package/src/core/cells/__tests__/logs.test.ts +5 -5
  74. package/src/core/cells/cells.ts +17 -4
  75. package/src/core/cells/document-changes.ts +1 -0
  76. package/src/core/cells/logs.ts +14 -4
  77. package/src/core/codemirror/cm.ts +3 -0
  78. package/src/core/codemirror/code-lens/__tests__/actions.test.ts +68 -0
  79. package/src/core/codemirror/code-lens/__tests__/analyzer.test.ts +224 -0
  80. package/src/core/codemirror/code-lens/__tests__/entities.test.ts +175 -0
  81. package/src/core/codemirror/code-lens/__tests__/extension.test.ts +325 -0
  82. package/src/core/codemirror/code-lens/__tests__/perf.test.ts +121 -0
  83. package/src/core/codemirror/code-lens/__tests__/popover.test.ts +93 -0
  84. package/src/core/codemirror/code-lens/actions.ts +33 -0
  85. package/src/core/codemirror/code-lens/analyzer.ts +284 -0
  86. package/src/core/codemirror/code-lens/entities.ts +123 -0
  87. package/src/core/codemirror/code-lens/extension.ts +298 -0
  88. package/src/core/codemirror/code-lens/icons.ts +36 -0
  89. package/src/core/codemirror/code-lens/popover.tsx +240 -0
  90. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +396 -100
  91. package/src/core/codemirror/copilot/__tests__/transport.test.ts +128 -540
  92. package/src/core/codemirror/copilot/language-server.ts +182 -70
  93. package/src/core/codemirror/copilot/transport.ts +15 -207
  94. package/src/core/codemirror/copilot/types.ts +9 -2
  95. package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +42 -30
  96. package/src/core/codemirror/find-replace/navigate.ts +2 -0
  97. package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +24 -3
  98. package/src/core/codemirror/go-to-definition/commands.ts +93 -90
  99. package/src/core/codemirror/language/__tests__/sql.test.ts +627 -61
  100. package/src/core/codemirror/language/languages/python.ts +23 -11
  101. package/src/core/codemirror/language/languages/sql/completion-store.ts +5 -1
  102. package/src/core/codemirror/language/languages/sql/renderers.tsx +3 -3
  103. package/src/core/codemirror/language/languages/sql/sql.ts +251 -16
  104. package/src/core/codemirror/lsp/__tests__/federated-lsp.test.ts +161 -0
  105. package/src/core/codemirror/lsp/__tests__/log-messages.test.ts +53 -0
  106. package/src/core/codemirror/lsp/__tests__/normalize-markdown-math.test.ts +25 -0
  107. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +598 -156
  108. package/src/core/codemirror/lsp/__tests__/transports.test.ts +112 -0
  109. package/src/core/codemirror/lsp/federated-lsp.ts +76 -23
  110. package/src/core/codemirror/lsp/log-messages.ts +37 -0
  111. package/src/core/codemirror/lsp/normalize-markdown-math.ts +8 -4
  112. package/src/core/codemirror/lsp/notebook-lsp.ts +220 -56
  113. package/src/core/codemirror/lsp/transports.ts +8 -1
  114. package/src/core/codemirror/lsp/types.ts +68 -8
  115. package/src/core/codemirror/lsp/utils.ts +14 -0
  116. package/src/core/codemirror/python-node-names.ts +90 -0
  117. package/src/core/codemirror/reactive-references/analyzer.ts +52 -57
  118. package/src/core/codemirror/utils.ts +28 -0
  119. package/src/core/config/feature-flag.tsx +3 -1
  120. package/src/core/datasets/data-source-discovery.ts +5 -0
  121. package/src/core/datasets/request-registry.ts +11 -0
  122. package/src/core/edit-app.tsx +1 -2
  123. package/src/core/export/__tests__/hooks.test.ts +2 -4
  124. package/src/core/export/hooks.ts +4 -3
  125. package/src/core/islands/__tests__/bridge.test.ts +107 -0
  126. package/src/core/islands/bootstrap.ts +1 -0
  127. package/src/core/islands/bridge.ts +18 -0
  128. package/src/core/kernel/messages.ts +2 -0
  129. package/src/core/lsp/__tests__/transport.test.ts +509 -337
  130. package/src/core/lsp/transport.ts +304 -132
  131. package/src/core/mode.ts +10 -0
  132. package/src/core/network/__tests__/api.test.ts +42 -0
  133. package/src/core/network/__tests__/connection.test.ts +45 -0
  134. package/src/core/network/__tests__/requests-lazy.test.ts +47 -1
  135. package/src/core/network/__tests__/requests-network.test.ts +48 -0
  136. package/src/core/network/api.ts +27 -0
  137. package/src/core/network/connection.ts +15 -0
  138. package/src/core/network/requests-lazy.ts +3 -0
  139. package/src/core/network/requests-network.ts +31 -8
  140. package/src/core/network/requests-static.ts +3 -0
  141. package/src/core/network/requests-toasting.tsx +3 -0
  142. package/src/core/network/types.ts +27 -6
  143. package/src/core/rtc/state.ts +9 -0
  144. package/src/core/static/download-html.ts +5 -14
  145. package/src/core/wasm/__tests__/bridge.test.ts +99 -5
  146. package/src/core/wasm/bridge.ts +42 -9
  147. package/src/core/wasm/worker/types.ts +10 -3
  148. package/src/core/wasm/worker/worker.ts +7 -8
  149. package/src/core/websocket/useMarimoKernelConnection.tsx +4 -0
  150. package/src/css/app/codemirror.css +16 -2
  151. package/src/hooks/__tests__/useDataSourceDiscovery.test.ts +80 -0
  152. package/src/hooks/useDataSourceDiscovery.ts +18 -0
  153. package/src/plugins/impl/DataTablePlugin.tsx +4 -1
  154. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +158 -0
  155. package/src/plugins/impl/anywidget/__tests__/model.test.ts +55 -0
  156. package/src/plugins/impl/anywidget/model.ts +20 -5
  157. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +33 -21
  158. package/src/plugins/impl/data-frames/forms/renderers.tsx +11 -8
  159. package/src/stories/log-viewer.stories.tsx +12 -6
  160. package/src/utils/__tests__/blob.test.ts +27 -1
  161. package/src/utils/__tests__/download.test.tsx +44 -4
  162. package/src/utils/blob.ts +24 -1
  163. package/src/utils/download.ts +14 -15
  164. package/dist/toDate-CmR_xR3P.js +0 -692
@@ -23,37 +23,43 @@ export const Primary: Story = {
23
23
  {
24
24
  timestamp: Date.now(),
25
25
  level: "stdout",
26
- cellId: cellId("cell1"),
26
+ source: { type: "cell", cellId: cellId("cell1") },
27
27
  message: "Hello world!",
28
28
  },
29
29
  {
30
30
  timestamp: Date.now(),
31
31
  level: "stdout",
32
- cellId: cellId("cell1"),
32
+ source: { type: "cell", cellId: cellId("cell1") },
33
33
  message: "Running cell...",
34
34
  },
35
35
  {
36
36
  timestamp: Date.now(),
37
37
  level: "stdout",
38
- cellId: cellId("cell1"),
38
+ source: { type: "cell", cellId: cellId("cell1") },
39
39
  message: "Done!",
40
40
  },
41
41
  {
42
42
  timestamp: Date.now(),
43
43
  level: "stderr",
44
- cellId: cellId("cell2"),
44
+ source: { type: "cell", cellId: cellId("cell2") },
45
45
  message: "Output is too large!",
46
46
  },
47
47
  {
48
48
  timestamp: Date.now(),
49
49
  level: "stderr",
50
- cellId: cellId("cell2"),
50
+ source: { type: "cell", cellId: cellId("cell2") },
51
51
  message: "String length is too short.".repeat(100),
52
52
  },
53
+ {
54
+ timestamp: Date.now(),
55
+ level: "stderr",
56
+ source: { type: "lsp", name: "pylsp" },
57
+ message: "Failed to load plugin 'ruff': not installed",
58
+ },
53
59
  ...Array.from({ length: 100 }).map(() => ({
54
60
  timestamp: Date.now(),
55
61
  level: "stdout" as const,
56
- cellId: cellId("cell1"),
62
+ source: { type: "cell", cellId: cellId("cell1") } as const,
57
63
  message: "Running cell...",
58
64
  })),
59
65
  ]}
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import { beforeEach, describe, expect, test } from "vitest";
3
- import { deserializeBlob, serializeBlob } from "../blob";
3
+ import { deserializeBlob, fileDetailsToBlob, serializeBlob } from "../blob";
4
4
  import { blobToString } from "../fileToBase64";
5
5
 
6
6
  describe("Blob serialization and deserialization", () => {
@@ -52,6 +52,32 @@ describe("Blob serialization and deserialization", () => {
52
52
  });
53
53
  });
54
54
 
55
+ describe("fileDetailsToBlob", () => {
56
+ test("decodes base64 contents into a binary blob", async () => {
57
+ const bytes = new Uint8Array([0, 1, 2, 3, 255]);
58
+ const base64 = btoa(String.fromCharCode(...bytes));
59
+ const blob = fileDetailsToBlob({
60
+ contents: base64,
61
+ mimeType: "image/png",
62
+ isBase64: true,
63
+ });
64
+ expect(blob.type).toBe("image/png");
65
+ const roundTripped = new Uint8Array(await blob.arrayBuffer());
66
+ expect(roundTripped).toEqual(bytes);
67
+ });
68
+
69
+ test("treats non-base64 contents as UTF-8 text", async () => {
70
+ const svg = '<svg xmlns="http://www.w3.org/2000/svg"></svg>';
71
+ const blob = fileDetailsToBlob({
72
+ contents: svg,
73
+ mimeType: "image/svg+xml",
74
+ isBase64: false,
75
+ });
76
+ expect(blob.type).toBe("image/svg+xml");
77
+ expect(await blob.text()).toBe(svg);
78
+ });
79
+ });
80
+
55
81
  describe("blobToString", () => {
56
82
  const testString = "Hello, world!";
57
83
  const mimeType = "text/plain";
@@ -8,6 +8,7 @@ import {
8
8
  downloadAsPDF,
9
9
  downloadByURL,
10
10
  downloadCellOutputAsImage,
11
+ downloadExportedFile,
11
12
  downloadHTMLAsImage,
12
13
  getImageDataUrlForCell,
13
14
  withLoadingToast,
@@ -195,7 +196,6 @@ describe("downloadAsPDF", () => {
195
196
 
196
197
  await expect(
197
198
  downloadAsPDF({
198
- filename: "path/to/notebook.py",
199
199
  webpdf: false,
200
200
  preset: "slides",
201
201
  }),
@@ -205,9 +205,26 @@ describe("downloadAsPDF", () => {
205
205
  webpdf: false,
206
206
  preset: "slides",
207
207
  includeInputs: true,
208
- rasterizeOutputs: true,
209
- rasterScale: 4,
210
- rasterServer: "static",
208
+ includeOutputs: true,
209
+ });
210
+ });
211
+
212
+ it("should send input and output selections", async () => {
213
+ mockExportAsPDF.mockRejectedValue(new Error("network"));
214
+
215
+ await expect(
216
+ downloadAsPDF({
217
+ webpdf: true,
218
+ includeInputs: false,
219
+ includeOutputs: false,
220
+ }),
221
+ ).rejects.toThrow("network");
222
+
223
+ expect(mockExportAsPDF).toHaveBeenCalledWith({
224
+ webpdf: true,
225
+ preset: "document",
226
+ includeInputs: false,
227
+ includeOutputs: false,
211
228
  });
212
229
  });
213
230
  });
@@ -572,6 +589,7 @@ describe("downloadByURL", () => {
572
589
 
573
590
  afterEach(() => {
574
591
  vi.restoreAllMocks();
592
+ vi.unstubAllGlobals();
575
593
  });
576
594
 
577
595
  it("should create anchor, set attributes, click, and remove", () => {
@@ -583,4 +601,26 @@ describe("downloadByURL", () => {
583
601
  expect(mockAnchor.click).toHaveBeenCalled();
584
602
  expect(mockAnchor.remove).toHaveBeenCalled();
585
603
  });
604
+
605
+ it("downloads an exported file with its returned metadata", async () => {
606
+ let downloadedBlob: Blob | undefined;
607
+ vi.stubGlobal("URL", {
608
+ createObjectURL: vi.fn((blob: Blob) => {
609
+ downloadedBlob = blob;
610
+ return "blob:export";
611
+ }),
612
+ revokeObjectURL: vi.fn(),
613
+ });
614
+
615
+ downloadExportedFile({
616
+ contents: "notebook",
617
+ filename: "résumé.qmd",
618
+ mediaType: "text/plain; charset=utf-8",
619
+ });
620
+
621
+ expect(downloadedBlob?.type).toBe("text/plain; charset=utf-8");
622
+ expect(await downloadedBlob?.text()).toBe("notebook");
623
+ expect(mockAnchor.download).toBe("résumé.qmd");
624
+ expect(URL.revokeObjectURL).toHaveBeenCalledWith("blob:export");
625
+ });
586
626
  });
package/src/utils/blob.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- import type { DataURLString } from "./json/base64";
2
+ import {
3
+ type Base64String,
4
+ base64ToDataURL,
5
+ type DataURLString,
6
+ } from "./json/base64";
3
7
 
4
8
  export function serializeBlob<T>(blob: Blob): Promise<DataURLString> {
5
9
  return new Promise<DataURLString>((resolve, reject) => {
@@ -30,3 +34,22 @@ export function deserializeBlob(serializedBlob: DataURLString): Blob {
30
34
  const blob = new Blob([bytes], { type: mimeType });
31
35
  return blob;
32
36
  }
37
+
38
+ /**
39
+ * Convert file details into a `Blob`, using the authoritative `isBase64` flag
40
+ * to decide between decoding base64 bytes and treating contents as UTF-8 text.
41
+ */
42
+ export function fileDetailsToBlob({
43
+ contents,
44
+ mimeType,
45
+ isBase64,
46
+ }: {
47
+ contents: string;
48
+ mimeType: string;
49
+ isBase64: boolean;
50
+ }): Blob {
51
+ if (isBase64) {
52
+ return deserializeBlob(base64ToDataURL(contents as Base64String, mimeType));
53
+ }
54
+ return new Blob([contents], { type: mimeType });
55
+ }
@@ -4,8 +4,8 @@ import React from "react";
4
4
  import { toast } from "@/components/ui/use-toast";
5
5
  import { type CellId, CellOutputId } from "@/core/cells/ids";
6
6
  import { getRequestClient } from "@/core/network/requests";
7
+ import type { ExportedFile } from "@/core/network/types";
7
8
  import { Filenames } from "@/utils/filenames";
8
- import { Paths } from "@/utils/paths";
9
9
  import { prettyError } from "./errors";
10
10
  import { toPng } from "./html-to-image";
11
11
  import { captureExternalIframes } from "./iframe";
@@ -191,6 +191,14 @@ export function downloadBlob(blob: Blob, filename: string) {
191
191
  URL.revokeObjectURL(url);
192
192
  }
193
193
 
194
+ export function downloadExportedFile({
195
+ contents,
196
+ filename,
197
+ mediaType,
198
+ }: ExportedFile) {
199
+ downloadBlob(new Blob([contents], { type: mediaType }), filename);
200
+ }
201
+
194
202
  export type PDFExportPreset = "document" | "slides";
195
203
 
196
204
  /**
@@ -200,37 +208,28 @@ export type PDFExportPreset = "document" | "slides";
200
208
  * Standard PDF requires Pandoc & TeX (~few GBs) but is of higher quality.
201
209
  */
202
210
  export async function downloadAsPDF(opts: {
203
- filename: string;
204
211
  webpdf: boolean;
205
212
  preset?: PDFExportPreset;
206
213
  includeInputs?: boolean;
207
- rasterizeOutputs?: boolean;
208
- rasterScale?: number;
209
- rasterServer?: "static" | "live";
214
+ includeOutputs?: boolean;
210
215
  }) {
211
216
  const client = getRequestClient();
212
217
  const {
213
- filename,
214
218
  webpdf,
215
219
  preset = "document",
216
220
  includeInputs = true,
217
- rasterizeOutputs = true,
218
- rasterScale = 4,
219
- rasterServer = "static",
221
+ includeOutputs = true,
220
222
  } = opts;
221
223
 
222
224
  try {
223
- const pdfBlob = await client.exportAsPDF({
225
+ const exportedFile = await client.exportAsPDF({
224
226
  webpdf,
225
227
  preset,
226
228
  includeInputs,
227
- rasterizeOutputs,
228
- rasterScale,
229
- rasterServer,
229
+ includeOutputs,
230
230
  });
231
231
 
232
- const filenameWithoutPath = Paths.basename(filename);
233
- downloadBlob(pdfBlob, Filenames.toPDF(filenameWithoutPath));
232
+ downloadExportedFile(exportedFile);
234
233
  } catch (error) {
235
234
  toast({
236
235
  title: "Failed to download",