@marimo-team/islands 0.25.3-dev141 → 0.25.3-dev143
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/dist/{ConnectedDataExplorerComponent-CNSxdKyJ.js → ConnectedDataExplorerComponent-BAiSVaHj.js} +17 -15
- package/dist/{ErrorBoundary-Cg59O3xL.js → ErrorBoundary-BRBKqg2U.js} +16 -16
- package/dist/{abnfDiagram-VCTEODGH-DQDjNXt3.js → abnfDiagram-VCTEODGH-BBHN92-F.js} +2 -2
- package/dist/any-language-editor-3E24SnCV.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-Nmls7Wxn.js → architectureDiagram-5GKGNRK7-C0Rd64qh.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/assets/__vite-browser-external-BgQNn4dS.js +1 -0
- package/dist/assets/worker-FKe3RHT4.js +113 -0
- package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-CI4xUPsp.js} +2 -2
- package/dist/{chat-ui-BDpymeoe.js → chat-ui-CvB8Map3.js} +1195 -1195
- package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
- package/dist/{chunk-IMKFNOWR-CoIFEo-1.js → chunk-IMKFNOWR-hJXey5p2.js} +1 -1
- package/dist/{chunk-SHT3W25Y-lHiGx3ZC.js → chunk-SHT3W25Y-JMzTmmVW.js} +1 -1
- package/dist/{chunk-SVP7TREG-BvsHIrY_.js → chunk-SVP7TREG-BIyoHTXi.js} +1 -1
- package/dist/{chunk-TICWLB2K-BC8YIm_n.js → chunk-TICWLB2K-CCzH2Uwa.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-Bt98lkkv.js → classDiagram-ZZMXUADV-DB1kOPS6.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-D9bfbcC3.js → classDiagram-v2-VYDZK3BY-CPaFL0OB.js} +2 -2
- package/dist/{code-visibility-Da3iitn_.js → code-visibility-CAgcNzoX.js} +17 -17
- package/dist/{common-C6FHcu5p.js → common-BovIV1xq.js} +6341 -5870
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CgWra7wt.js → cynefinDiagram-5FMLGOSQ-CF93uliH.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-CFZ8-35c.js → dagre-GXQ25YYZ-BBB-_p9D.js} +1 -1
- package/dist/{data-grid-overlay-editor-mJt3Pg4S.js → data-grid-overlay-editor-CBsr8Yo0.js} +5 -5
- package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-lCNQrW7d.js → diagram-S7CK7UJ4-BynCnbyt.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-CQPQ6pP_.js → diagram-UQ7AKVKN-svOxikMa.js} +1 -1
- package/dist/{diagram-VX7I27RA-Cf3b0llz.js → diagram-VX7I27RA-BVQSnPx0.js} +1 -1
- package/dist/{diagram-Z3DM3KII-Bt4QLrpn.js → diagram-Z3DM3KII-nR1J0BH5.js} +1 -1
- package/dist/{dialog-CEBFZNyc.js → dialog-DgeqyrEZ.js} +3 -3
- package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
- package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-GWcGCcxE.js} +1277 -1229
- package/dist/{ebnfDiagram-PWID7BFC-D3NAyPFY.js → ebnfDiagram-PWID7BFC-C9tq9-Qo.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Tlu09_Nm.js → erDiagram-RLTQ6QDP-BiaeB7Fi.js} +1 -1
- package/dist/{error-banner-Da600cwz.js → error-banner-D40pmfQQ.js} +86 -81
- package/dist/{cells-C8iCYvLU.js → error-entries-CmFDQ9CA.js} +1718 -1621
- package/dist/{feedback-button-DaPwHIdM.js → feedback-button-B_9o6DdV.js} +122 -123
- package/dist/{flowDiagram-HODETNUW-CAYbpJmV.js → flowDiagram-HODETNUW-f-sLm87k.js} +2 -2
- package/dist/{formats-BGh2thRc.js → formats-CCxaLPNs.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-Ctz2mH6k.js → glide-data-editor-i7BEAfhs.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
- package/dist/{globals-EpFoRj_E.js → globals-BDzA_Re9.js} +3 -3
- package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
- package/dist/{html-to-image-CZY1pIZH.js → html-to-image-BrC8OJcj.js} +634 -597
- package/dist/{infoDiagram-27XIBGKW-XrDxhr0x.js → infoDiagram-27XIBGKW-BHrWywBe.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-CD1muzov.js → ishikawaDiagram-5VMMS53U-Da4s0Reg.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-Dg9W142_.js → kanban-definition-UXKFOSKX-DDf1GVLj.js} +1 -1
- package/dist/{label-BDKF3Afc.js → label-D9_-zSg-.js} +3 -3
- package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
- package/dist/{loader-BQOfjTIJ.js → loader-DOVB0Syl.js} +12 -12
- package/dist/main.js +7548 -7226
- package/dist/{mermaid-CiAXjLpA.js → mermaid-ClwTt7OD.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-DgCidgYJ.js → mindmap-definition-YA3MSWOX-D60oMZtT.js} +1 -1
- package/dist/{number-overlay-editor-CtxrummL.js → number-overlay-editor-D9WjQlOL.js} +3 -3
- package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
- package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-coOYYKB6.js → pegDiagram-XKGWAZYB-B9wFpMga.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BnXTc3bj.js → pieDiagram-E7YTZNPT-BZwvMuBT.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-e4jj9Ijt.js → process-output-Bw-vzyoy.js} +4 -4
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-B28-u83n.js → railroadDiagram-O6MQD6OU-DqhZGsN2.js} +2 -2
- package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
- package/dist/{requirementDiagram-BXWQKSXE-CdYCTMu0.js → requirementDiagram-BXWQKSXE-CL5dYARV.js} +1 -1
- package/dist/{reveal-component-DrIXvR_7.js → reveal-component-BxP2jlPx.js} +14 -14
- package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
- package/dist/{sequenceDiagram-WJ2MYXX4-CM3aRAe_.js → sequenceDiagram-WJ2MYXX4-BSUCRd2x.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-DiSh_qJC.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DOZUMVj8.js → stateDiagram-D77RDMKH-B-1Hvyb0.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-CISYxma6.js → stateDiagram-v2-MP3YSRHH--HtiR4yB.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-BkSppxp8.js → swimlanes-42K2YHIH-Bdfhrd-2.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-c8G5pGxC.js → swimlanesDiagram-VR7AAH4N-BJIfxSz0.js} +2 -2
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-BkCm-kLg.js} +2 -2
- package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
- package/dist/{timeline-definition-24CTP7MA-CaMQayqK.js → timeline-definition-24CTP7MA-Cs4EfFD3.js} +1 -1
- package/dist/{toDate-BNJf01u1.js → toDate-DGvRHwTk.js} +57 -54
- package/dist/{toast-B9UMEi8u.js → toast-Btbve3Lm.js} +231 -213
- package/dist/{tooltip-BO1REbqs.js → tooltip-CJ4Rqasp.js} +327 -303
- package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-CmGwRNId.js} +1482 -1433
- package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-BmVgnMP5.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-eCL_SdeG.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-Ch_AeGu6.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-B5BX921H.js} +3 -3
- package/dist/{useTheme-CRnjkku0.js → useTheme-Bq9pi_vz.js} +6 -6
- package/dist/{vega-component-DG29TAB7.js → vega-component-BgyZ-COt.js} +147 -147
- package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
- package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
- package/dist/{vennDiagram-4TSXK5OY-CF8pfaK3.js → vennDiagram-4TSXK5OY-DRu0vRjO.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-dGPu39d-.js → wardleyDiagram-VM6X3IG4-DzbDxwDY.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CP6-9q56.js → xychartDiagram-S5SC5T6Z-CLWj6ZFQ.js} +2 -2
- package/package.json +15 -12
- package/src/__tests__/fixtures/{pair-preview.ts → pair-config.ts} +3 -2
- package/src/__tests__/host-imports.test.ts +101 -0
- package/src/__tests__/module-entry.test.ts +32 -0
- package/src/__tests__/mount.test.ts +8 -8
- package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
- package/src/components/ai/ai-model-dropdown.tsx +11 -6
- package/src/components/app-config/ai-config.tsx +7 -2
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
- package/src/components/chat/acp/__tests__/state.test.ts +2 -2
- package/src/components/chat/acp/blocks.tsx +3 -2
- package/src/components/chat/acp/session-tabs.tsx +8 -3
- package/src/components/chat/chat-components.tsx +2 -0
- package/src/components/chat/chat-panel.tsx +9 -8
- package/src/components/chat/chat-utils.ts +4 -8
- package/src/components/data-table/TableTopBar.tsx +2 -0
- package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
- package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
- package/src/components/data-table/__tests__/columns.test.tsx +105 -0
- package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
- package/src/components/data-table/__tests__/context-menu.test.ts +176 -0
- package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
- package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +24 -1
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +434 -6
- package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
- package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
- package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
- package/src/components/data-table/cell-selection/feature.ts +2 -2
- package/src/components/data-table/cell-selection/types.ts +2 -2
- package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
- package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
- package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
- package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
- package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
- package/src/components/data-table/charts/charts.tsx +40 -30
- package/src/components/data-table/charts/storage.ts +16 -5
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
- package/src/components/data-table/column-summary/column-summary.tsx +2 -4
- package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
- package/src/components/data-table/columns.tsx +45 -46
- package/src/components/data-table/context-menu.tsx +161 -46
- package/src/components/data-table/data-table.tsx +13 -1
- package/src/components/data-table/date-filter-inputs.tsx +15 -42
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +267 -163
- package/src/components/data-table/range-focus/atoms.ts +4 -6
- package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
- package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
- package/src/components/data-table/renderers.tsx +16 -7
- package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
- package/src/components/data-table/schemas.ts +14 -36
- package/src/components/data-table/search-highlight.tsx +79 -0
- package/src/components/data-table/types.ts +1 -0
- package/src/components/data-table/url-detector.tsx +49 -9
- package/src/components/data-table/utils.ts +18 -0
- package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
- package/src/components/datasources/__tests__/column-preview.test.tsx +98 -5
- package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
- package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
- package/src/components/datasources/__tests__/utils.test.ts +57 -6
- package/src/components/datasources/column-preview.tsx +13 -4
- package/src/components/datasources/datasources.tsx +51 -39
- package/src/components/datasources/utils.ts +32 -23
- package/src/components/debugger/debugger-code.tsx +5 -0
- package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
- package/src/components/dependency-graph/elements.ts +24 -21
- package/src/components/dependency-graph/panels.tsx +2 -1
- package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
- package/src/components/editor/Output.tsx +9 -2
- package/src/components/editor/SortableCell.tsx +1 -3
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +80 -252
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +210 -34
- package/src/components/editor/actions/pair-with-agent-commands.ts +42 -51
- package/src/components/editor/actions/pair-with-agent-modal.tsx +100 -37
- package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/cell/CreateCellButton.tsx +8 -10
- package/src/components/editor/cell/DeleteButton.tsx +1 -0
- package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +1 -1
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- package/src/components/editor/cell/collapse.tsx +5 -3
- package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +30 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/error-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
- package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
- package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
- package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
- package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -1
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +366 -0
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-item.tsx +32 -24
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +237 -0
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- package/src/components/editor/chrome/wrapper/footer.tsx +2 -0
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/connections/components.tsx +1 -1
- package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
- package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
- package/src/components/editor/controls/command-palette.tsx +22 -10
- package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
- package/src/components/editor/dynamic-favicon.tsx +21 -40
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +537 -0
- package/src/components/editor/errors/send-error-report-button.tsx +69 -0
- package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
- package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
- package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
- package/src/components/editor/file-tree/file-explorer.tsx +45 -8
- package/src/components/editor/file-tree/file-name-input.tsx +1 -0
- package/src/components/editor/file-tree/file-viewer.tsx +4 -2
- package/src/components/editor/file-tree/use-file-search.ts +35 -21
- package/src/components/editor/header/status.tsx +28 -5
- package/src/components/editor/links/__tests__/cell-link.test.tsx +146 -0
- package/src/components/editor/links/cell-link.tsx +14 -5
- package/src/components/editor/navigation/focus-utils.ts +4 -4
- package/src/components/editor/notebook-banner.tsx +1 -0
- package/src/components/editor/notebook-cell.tsx +11 -2
- package/src/components/editor/output/MarimoErrorOutput.tsx +21 -5
- package/src/components/editor/output/MarimoTracebackOutput.tsx +54 -37
- package/src/components/editor/output/__tests__/ansi-reduce.test.ts +18 -0
- package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
- package/src/components/editor/output/ansi-reduce.ts +36 -17
- package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
- package/src/components/editor/package-alert.tsx +14 -7
- package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
- package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
- package/src/components/home/components.tsx +17 -31
- package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
- package/src/components/icons/large-spinner.tsx +3 -14
- package/src/components/icons/spinner.tsx +1 -1
- package/src/components/mcp/mcp-status-indicator.tsx +1 -1
- package/src/components/pages/__tests__/home-page.test.tsx +116 -0
- package/src/components/pages/home-page.tsx +164 -91
- package/src/components/scratchpad/scratchpad.test.tsx +95 -0
- package/src/components/scratchpad/scratchpad.tsx +16 -3
- package/src/components/slides/reveal-component.tsx +4 -2
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/slides/slide-form.tsx +1 -0
- package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
- package/src/components/tracing/tracing.tsx +45 -41
- package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
- package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
- package/src/components/ui/alert-dialog.tsx +1 -1
- package/src/components/ui/draggable-popover.tsx +24 -2
- package/src/components/ui/range-slider.tsx +22 -9
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/ai/tools/base.ts +16 -7
- package/src/core/ai/tools/edit-notebook-tool.ts +47 -45
- package/src/core/ai/tools/registry.ts +13 -8
- package/src/core/ai/tools/sample-tool.ts +6 -7
- package/src/core/attachments/__tests__/toast.test.tsx +58 -0
- package/src/core/attachments/state.ts +18 -0
- package/src/core/attachments/toast.ts +15 -0
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
- package/src/core/cells/__tests__/cell.test.ts +39 -0
- package/src/core/cells/__tests__/cells.test.ts +55 -1
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/error-report.test.ts +139 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +167 -37
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +3 -1
- package/src/core/cells/error-report.ts +63 -0
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +29 -2
- package/src/core/cells/types.ts +10 -1
- package/src/core/codemirror/__tests__/setup.test.ts +29 -29
- package/src/core/codemirror/cells/__tests__/extensions.test.ts +15 -0
- package/src/core/codemirror/cells/extensions.ts +7 -3
- package/src/core/codemirror/keymaps/vim.ts +2 -6
- package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
- package/src/core/codemirror/language/extension.ts +8 -8
- package/src/core/codemirror/language/languages/markdown.ts +8 -6
- package/src/core/codemirror/language/languages/python.ts +16 -10
- package/src/core/codemirror/language/languages/sql/sql.ts +9 -7
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/codemirror/language/types.ts +7 -7
- package/src/core/codemirror/rtc/extension.ts +24 -12
- package/src/core/codemirror/rtc/loro/awareness.ts +34 -19
- package/src/core/codemirror/rtc/loro/sync.ts +1 -0
- package/src/core/codemirror/utils.ts +1 -0
- package/src/core/config/pair.ts +5 -3
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +4 -4
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/document/__tests__/codemirror.test.ts +485 -0
- package/src/core/document/__tests__/draft.test.ts +322 -0
- package/src/core/document/__tests__/fixtures.ts +92 -0
- package/src/core/document/__tests__/hooks.test.tsx +386 -0
- package/src/core/document/__tests__/lifecycle-scenarios.test.ts +61 -0
- package/src/core/document/__tests__/model.test.ts +191 -0
- package/src/core/document/__tests__/protocol-fixtures.ts +38 -0
- package/src/core/document/__tests__/recovery-scenarios.test.ts +230 -0
- package/src/core/document/__tests__/scenario-fixture.ts +43 -0
- package/src/core/document/__tests__/scenarios.test.ts +205 -0
- package/src/core/document/__tests__/state.test.ts +438 -0
- package/src/core/document/__tests__/submission.test.ts +203 -0
- package/src/core/document/__tests__/test-host.test.ts +92 -0
- package/src/core/document/__tests__/test-host.ts +247 -0
- package/src/core/document/__tests__/test-notebook.ts +149 -0
- package/src/core/document/__tests__/user.ts +61 -0
- package/src/core/document/codemirror.ts +311 -0
- package/src/core/document/draft.ts +472 -0
- package/src/core/document/hooks.tsx +118 -0
- package/src/core/document/index.ts +15 -0
- package/src/core/document/model.ts +55 -0
- package/src/core/document/select.ts +41 -0
- package/src/core/document/state.ts +374 -0
- package/src/core/document/sync.ts +369 -0
- package/src/core/edit-app.tsx +2 -2
- package/src/core/host/AGENTS.md +12 -0
- package/src/core/host/__tests__/attachments.test.ts +56 -0
- package/src/core/host/__tests__/document.test.ts +126 -0
- package/src/core/host/__tests__/fixtures.ts +79 -0
- package/src/core/host/__tests__/replica.test.ts +550 -0
- package/src/core/host/__tests__/static.test.ts +175 -0
- package/src/core/host/__tests__/wasm.test.ts +166 -0
- package/src/core/host/backend.ts +19 -0
- package/src/core/host/connection.ts +42 -0
- package/src/core/host/index.ts +14 -0
- package/src/core/host/replica.ts +286 -0
- package/src/core/host/resources/attachments.ts +22 -0
- package/src/core/host/resources/document.ts +101 -0
- package/src/core/host/static.ts +77 -0
- package/src/core/host/wasm.ts +97 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +17 -17
- package/src/core/islands/__tests__/bridge.test.ts +31 -26
- package/src/core/islands/bootstrap.ts +22 -51
- package/src/core/islands/bridge.ts +31 -20
- package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
- package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
- package/src/core/islands/worker/controller.ts +4 -10
- package/src/core/islands/worker/worker.tsx +33 -33
- package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
- package/src/core/network/connection.ts +4 -2
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/run-app.tsx +2 -2
- package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +33 -15
- package/src/core/runtime/runtime.ts +39 -30
- package/src/core/saving/save-component.tsx +12 -3
- package/src/core/state/__tests__/jotai.test.tsx +108 -0
- package/src/core/state/jotai.ts +1 -1
- package/src/core/static/__tests__/files.test.ts +38 -10
- package/src/core/static/files.ts +2 -0
- package/src/core/wasm/__tests__/bridge.test.ts +213 -50
- package/src/core/wasm/__tests__/worker.test.ts +187 -0
- package/src/core/wasm/bridge.ts +81 -52
- package/src/core/wasm/rpc.ts +15 -3
- package/src/core/wasm/store.ts +3 -3
- package/src/core/wasm/worker/bootstrap.ts +55 -51
- package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
- package/src/core/wasm/worker/save-worker.ts +9 -10
- package/src/core/wasm/worker/types.ts +29 -18
- package/src/core/wasm/worker/worker.ts +97 -44
- package/src/core/websocket/__tests__/backend.test.ts +235 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts} +15 -29
- package/src/core/websocket/__tests__/useNotebookReplica.hook.test.tsx +141 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.hook.test.tsx → useNotebookSession.hook.test.tsx} +197 -184
- package/src/core/websocket/backend.ts +129 -0
- package/src/core/websocket/connection-state.ts +60 -0
- package/src/core/websocket/state.ts +7 -0
- package/src/core/websocket/transports/__tests__/notebook.test.ts +405 -0
- package/src/core/websocket/transports/notebook.ts +159 -0
- package/src/core/websocket/types.ts +9 -39
- package/src/core/websocket/useNotebookReplica.ts +69 -0
- package/src/core/websocket/{useMarimoKernelConnection.tsx → useNotebookSession.tsx} +63 -228
- package/src/css/globals.css +5 -0
- package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
- package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
- package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
- package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
- package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
- package/src/hooks/__tests__/useScript.test.tsx +77 -0
- package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
- package/src/hooks/useAsyncData.ts +3 -3
- package/src/hooks/useDataSourceDiscovery.ts +6 -4
- package/src/hooks/useDebounce.ts +6 -10
- package/src/hooks/useDeepCompareMemoize.ts +1 -1
- package/src/hooks/useDelayElapsed.ts +14 -10
- package/src/hooks/useElapsedTime.ts +3 -3
- package/src/hooks/useEventListener.ts +1 -2
- package/src/hooks/useInputHistory.ts +4 -7
- package/src/hooks/useInternalStateWithSync.ts +6 -6
- package/src/hooks/useResizeObserver.ts +4 -7
- package/src/hooks/useScript.ts +67 -70
- package/src/hooks/useStateForKey.ts +93 -0
- package/src/mount.tsx +3 -3
- package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
- package/src/plugins/core/registerReactComponent.tsx +1 -1
- package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataTablePlugin.tsx +29 -33
- package/src/plugins/impl/DropdownPlugin.tsx +2 -6
- package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
- package/src/plugins/impl/FormPlugin.tsx +1 -1
- package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
- package/src/plugins/impl/RefreshPlugin.tsx +1 -0
- package/src/plugins/impl/SliderPlugin.tsx +6 -8
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +201 -1
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
- package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
- package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
- package/src/plugins/impl/anywidget/__tests__/registry.test.ts +2 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/runtime.ts +21 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
- package/src/plugins/impl/chat/chat-ui.tsx +14 -11
- package/src/plugins/impl/code/any-language-editor.tsx +2 -2
- package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
- package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
- package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
- package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
- package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
- package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
- package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
- package/src/plugins/impl/data-frames/panel.tsx +43 -16
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
- package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
- package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
- package/src/plugins/impl/panel/utils.ts +17 -0
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
- package/src/plugins/impl/plotly/selection.ts +25 -19
- package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
- package/src/plugins/impl/vega/make-selectable.ts +4 -7
- package/src/plugins/layout/RoutesPlugin.tsx +1 -1
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/button.stories.tsx +1 -0
- package/src/stories/editor.stories.tsx +24 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- package/src/stories/select.stories.tsx +2 -2
- package/src/stories/switchable-multi-select.stories.tsx +1 -1
- package/src/utils/__tests__/arrays.test.ts +35 -0
- package/src/utils/__tests__/batch-requests.test.ts +3 -3
- package/src/utils/__tests__/dates.test.ts +116 -0
- package/src/utils/__tests__/numbers.test.ts +105 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +10 -0
- package/src/utils/blob.ts +1 -1
- package/src/utils/dates.ts +94 -0
- package/src/utils/numbers.ts +79 -18
- package/src/utils/objects.ts +3 -7
- package/src/utils/once.ts +19 -19
- package/src/utils/tracer.ts +9 -5
- package/src/utils/zod-utils.ts +1 -3
- package/dist/any-language-editor-B9REGlD9.js +0 -76
- package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
- package/dist/assets/worker-HPY9fbhz.js +0 -114
- package/dist/error-entries-CzoYkIQZ.js +0 -56
- package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- package/src/core/state/__tests__/jotai.test.ts +0 -25
- package/src/core/wasm/worker/message-buffer.ts +0 -33
- package/src/core/websocket/__tests__/useWebSocket.test.ts +0 -49
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -338
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -61
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useWebSocket.tsx +0 -88
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { loadPyodide, type PyodideInterface } from "pyodide";
|
|
3
3
|
import type { PyCallable, PyProxy } from "pyodide/ffi";
|
|
4
|
-
import type { UserConfig } from "@/core/config/config-schema";
|
|
5
|
-
import type { NotificationPayload } from "@/core/kernel/messages";
|
|
6
|
-
import type { JsonString } from "@/utils/json/base64";
|
|
7
4
|
import { invariant } from "../../../utils/invariant";
|
|
5
|
+
import { once } from "../../../utils/once";
|
|
8
6
|
import { Logger } from "../../../utils/Logger";
|
|
9
7
|
import { WasmFileSystem } from "./fs";
|
|
10
8
|
import { getMarimoWheel } from "./getMarimoWheel";
|
|
11
9
|
import { t } from "./tracer";
|
|
12
|
-
import type { SerializedBridge, WasmController } from "./types";
|
|
10
|
+
import type { SerializedBridge, WasmController, WasmSession } from "./types";
|
|
13
11
|
import { shouldLoadDuckDBPackages } from "../utils";
|
|
14
12
|
|
|
15
13
|
const MAKE_SNAPSHOT = false;
|
|
@@ -45,7 +43,7 @@ export class DefaultWasmController implements WasmController {
|
|
|
45
43
|
protected pyodide: PyodideInterface | null = null;
|
|
46
44
|
private packageLoadQueue = Promise.resolve();
|
|
47
45
|
private sessionGeneration = 0;
|
|
48
|
-
private
|
|
46
|
+
private sessions = new Set<WasmSession>();
|
|
49
47
|
|
|
50
48
|
public get requirePyodide() {
|
|
51
49
|
invariant(this.pyodide, "Pyodide not loaded");
|
|
@@ -85,7 +83,7 @@ export class DefaultWasmController implements WasmController {
|
|
|
85
83
|
packages: [
|
|
86
84
|
"micropip",
|
|
87
85
|
"msgspec",
|
|
88
|
-
getMarimoWheel(
|
|
86
|
+
getMarimoWheel(),
|
|
89
87
|
"Markdown",
|
|
90
88
|
"pymdown-extensions",
|
|
91
89
|
"narwhals",
|
|
@@ -138,28 +136,15 @@ export class DefaultWasmController implements WasmController {
|
|
|
138
136
|
});
|
|
139
137
|
}
|
|
140
138
|
|
|
141
|
-
public async
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
filename: string | null;
|
|
145
|
-
onMessage: (message: JsonString<NotificationPayload>) => void;
|
|
146
|
-
userConfig: UserConfig;
|
|
147
|
-
}): Promise<SerializedBridge> {
|
|
139
|
+
public async prepareSession(
|
|
140
|
+
opts: Parameters<WasmController["prepareSession"]>[0],
|
|
141
|
+
): Promise<WasmSession> {
|
|
148
142
|
const sessionGeneration = this.sessionGeneration;
|
|
149
|
-
const { code, filename,
|
|
150
|
-
// We pass down a messenger object to the code
|
|
151
|
-
// This is used to have synchronous communication between the JS and Python code
|
|
152
|
-
// Previously, we used a queue, but this would not properly flush the queue
|
|
153
|
-
// during processing of a cell's code.
|
|
154
|
-
//
|
|
155
|
-
// This adds a messenger object to the global scope (import js; js.messenger.callback)
|
|
156
|
-
self.messenger = {
|
|
157
|
-
callback: onMessage,
|
|
158
|
-
};
|
|
143
|
+
const { code, filename, queryParameters, userConfig } = opts;
|
|
159
144
|
self.query_params = queryParameters;
|
|
160
145
|
self.user_config = userConfig;
|
|
161
146
|
|
|
162
|
-
const span = t.startSpan("
|
|
147
|
+
const span = t.startSpan("prepareSession.runPython");
|
|
163
148
|
const nbFilename = filename || WasmFileSystem.NOTEBOOK_FILENAME;
|
|
164
149
|
const sessionResources = this.requirePyodide.runPython(
|
|
165
150
|
`
|
|
@@ -169,14 +154,12 @@ export class DefaultWasmController implements WasmController {
|
|
|
169
154
|
import js
|
|
170
155
|
from marimo._pyodide.bootstrap import create_session, instantiate
|
|
171
156
|
|
|
172
|
-
assert js.messenger, "messenger is not defined"
|
|
173
157
|
assert js.query_params, "query_params is not defined"
|
|
174
158
|
|
|
175
159
|
def create_session_resources():
|
|
176
160
|
session, bridge = create_session(
|
|
177
161
|
filename="${nbFilename}",
|
|
178
162
|
query_params=js.query_params.to_py(),
|
|
179
|
-
message_callback=js.messenger.callback,
|
|
180
163
|
user_config=js.user_config.to_py(),
|
|
181
164
|
)
|
|
182
165
|
session_task = None
|
|
@@ -198,6 +181,7 @@ export class DefaultWasmController implements WasmController {
|
|
|
198
181
|
if task is not None:
|
|
199
182
|
await asyncio.gather(task, return_exceptions=True)
|
|
200
183
|
if bridge is not None:
|
|
184
|
+
bridge.close()
|
|
201
185
|
bridge.session = None
|
|
202
186
|
task = None
|
|
203
187
|
kernel_task = None
|
|
@@ -235,45 +219,65 @@ export class DefaultWasmController implements WasmController {
|
|
|
235
219
|
} finally {
|
|
236
220
|
packagesProxy.destroy();
|
|
237
221
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
//
|
|
244
|
-
// a sense of responsiveness.
|
|
222
|
+
let stopped = false;
|
|
223
|
+
let stopping: Promise<void> | undefined;
|
|
224
|
+
const releaseInit = once(() => initSession.destroy());
|
|
225
|
+
const isStopped = () =>
|
|
226
|
+
stopped || sessionGeneration !== this.sessionGeneration;
|
|
227
|
+
// Load in parallel with subscription setup; only start() executes cells.
|
|
245
228
|
const dependenciesReady = this.packageLoadQueue.then(() => {
|
|
246
|
-
if (
|
|
229
|
+
if (isStopped()) {
|
|
247
230
|
return;
|
|
248
231
|
}
|
|
249
232
|
return this.loadNotebookDeps(code, foundPackages);
|
|
250
233
|
});
|
|
251
234
|
this.packageLoadQueue = dependenciesReady.catch(() => undefined);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
235
|
+
const session: WasmSession = {
|
|
236
|
+
bridge: bridgeProxy as unknown as SerializedBridge,
|
|
237
|
+
start: once(async () => {
|
|
238
|
+
try {
|
|
239
|
+
if (isStopped()) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
await dependenciesReady;
|
|
243
|
+
if (!isStopped()) {
|
|
244
|
+
initSession(userConfig.runtime.auto_instantiate);
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (!isStopped()) {
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
} finally {
|
|
251
|
+
releaseInit();
|
|
256
252
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
253
|
+
}),
|
|
254
|
+
stop: () => {
|
|
255
|
+
stopped = true;
|
|
256
|
+
releaseInit();
|
|
257
|
+
stopping ??= (async () => {
|
|
258
|
+
await stopSession();
|
|
259
|
+
stopSession.destroy();
|
|
260
|
+
bridgeProxy.destroy();
|
|
261
|
+
this.sessions.delete(session);
|
|
262
|
+
})().catch((error: unknown) => {
|
|
263
|
+
stopping = undefined;
|
|
264
|
+
throw error;
|
|
265
|
+
});
|
|
266
|
+
return stopping;
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
this.sessions.add(session);
|
|
270
|
+
return session;
|
|
265
271
|
}
|
|
266
272
|
|
|
267
273
|
public async stopSession(): Promise<void> {
|
|
268
274
|
this.sessionGeneration += 1;
|
|
269
|
-
const
|
|
275
|
+
const sessions = [...this.sessions];
|
|
270
276
|
let hasFailure = false;
|
|
271
277
|
let firstFailure: unknown;
|
|
272
|
-
for (const
|
|
278
|
+
for (const session of sessions) {
|
|
273
279
|
try {
|
|
274
|
-
await stop();
|
|
275
|
-
this.activeSessionStops.delete(stop);
|
|
276
|
-
stop.destroy();
|
|
280
|
+
await session.stop();
|
|
277
281
|
} catch (error) {
|
|
278
282
|
if (!hasFailure) {
|
|
279
283
|
hasFailure = true;
|
|
@@ -7,12 +7,11 @@ import {
|
|
|
7
7
|
createWorkerParentTransport,
|
|
8
8
|
type RPCSchema,
|
|
9
9
|
} from "rpc-anywhere";
|
|
10
|
-
import type { SaveNotebookRequest } from "@/core/network/types";
|
|
11
10
|
import { decodeUtf8 } from "@/utils/strings";
|
|
12
11
|
import { Deferred } from "../../../utils/Deferred";
|
|
13
12
|
import { prettyError } from "../../../utils/errors";
|
|
14
13
|
import { Logger } from "../../../utils/Logger";
|
|
15
|
-
import type { ParentSchema } from "../rpc";
|
|
14
|
+
import type { ParentSchema, PersistNotebookRequest } from "../rpc";
|
|
16
15
|
import type { WasmRuntimeConfig } from "../runtime-config";
|
|
17
16
|
import { TRANSPORT_ID } from "./constants";
|
|
18
17
|
import { WasmFileSystem } from "./fs";
|
|
@@ -70,14 +69,14 @@ const requestHandler = createRPCRequestHandler({
|
|
|
70
69
|
await pyodideReadyPromise; // Make sure loading is done
|
|
71
70
|
return WasmFileSystem.readNotebook(self.pyodide);
|
|
72
71
|
},
|
|
73
|
-
|
|
74
|
-
await pyodideReadyPromise;
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
writeNotebook: async ({ filename, contents }: PersistNotebookRequest) => {
|
|
73
|
+
await pyodideReadyPromise;
|
|
74
|
+
const directory = filename.substring(0, filename.lastIndexOf("/"));
|
|
75
|
+
if (directory) {
|
|
76
|
+
self.pyodide.FS.mkdirTree(directory);
|
|
77
|
+
}
|
|
78
|
+
self.pyodide.FS.writeFile(filename, contents);
|
|
79
|
+
self.pyodide.FS.writeFile(WasmFileSystem.NOTEBOOK_FILENAME, contents);
|
|
81
80
|
await WasmFileSystem.persistFilesToRemote(self.pyodide);
|
|
82
81
|
},
|
|
83
82
|
});
|
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
import type { PyodideInterface } from "pyodide";
|
|
3
3
|
import type { WasmRuntimeConfig } from "../runtime-config";
|
|
4
4
|
import type { UserConfig } from "@/core/config/config-schema";
|
|
5
|
-
import type {
|
|
6
|
-
ClientCommand,
|
|
7
|
-
NotificationPayload,
|
|
8
|
-
} from "@/core/kernel/messages";
|
|
9
|
-
import type { JsonString } from "@/utils/json/base64";
|
|
5
|
+
import type { ClientCommand } from "@/core/kernel/messages";
|
|
10
6
|
import type {
|
|
11
7
|
CodeCompletionRequest,
|
|
12
8
|
CopyNotebookRequest,
|
|
@@ -34,7 +30,6 @@ import type {
|
|
|
34
30
|
FormatCellsRequest,
|
|
35
31
|
FormatResponse,
|
|
36
32
|
SaveAppConfigurationRequest,
|
|
37
|
-
SaveNotebookRequest,
|
|
38
33
|
SaveUserConfigurationRequest,
|
|
39
34
|
Snippets,
|
|
40
35
|
} from "../../network/types";
|
|
@@ -58,19 +53,21 @@ export interface WasmController {
|
|
|
58
53
|
code: string;
|
|
59
54
|
filename: string | null;
|
|
60
55
|
}): Promise<{ code: string; filename: string }>;
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
* @param opts.code - The code to start with
|
|
64
|
-
* @param opts.fallbackCode - The code to fallback to
|
|
65
|
-
* @param opts.filename - The filename to start with
|
|
66
|
-
*/
|
|
67
|
-
startSession(opts: {
|
|
56
|
+
/** Prepare a session and load its dependencies without executing cells. */
|
|
57
|
+
prepareSession(opts: {
|
|
68
58
|
queryParameters: Record<string, string | string[]>;
|
|
69
59
|
code: string;
|
|
70
60
|
filename: string | null;
|
|
71
61
|
userConfig: UserConfig;
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
}): Promise<WasmSession>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface WasmSession {
|
|
66
|
+
readonly bridge: SerializedBridge;
|
|
67
|
+
/** Start once dependencies are ready. Repeated calls share the same start. */
|
|
68
|
+
start(): Promise<void>;
|
|
69
|
+
/** Prevent a pending start and release the session and its bridge. */
|
|
70
|
+
stop(): Promise<void>;
|
|
74
71
|
}
|
|
75
72
|
|
|
76
73
|
export interface RawBridge {
|
|
@@ -81,7 +78,6 @@ export interface RawBridge {
|
|
|
81
78
|
read_snippets(): Promise<Snippets>;
|
|
82
79
|
get_environment_info(): Promise<EnvironmentInfo>;
|
|
83
80
|
format(request: FormatCellsRequest): Promise<FormatResponse>;
|
|
84
|
-
save(request: SaveNotebookRequest): Promise<string>;
|
|
85
81
|
copy(request: CopyNotebookRequest): Promise<string>;
|
|
86
82
|
save_app_config(request: SaveAppConfigurationRequest): Promise<string>;
|
|
87
83
|
save_user_config(request: SaveUserConfigurationRequest): Promise<null>;
|
|
@@ -114,11 +110,26 @@ export type BridgePayload<T extends keyof RawBridge> = T extends keyof RawBridge
|
|
|
114
110
|
: undefined;
|
|
115
111
|
|
|
116
112
|
export type SerializedBridge = {
|
|
117
|
-
[P in
|
|
113
|
+
[P in keyof RawBridge]: RawBridge[P] extends (
|
|
118
114
|
payload: string,
|
|
119
115
|
) => Promise<unknown>
|
|
120
116
|
? (payload: string) => Promise<string>
|
|
121
117
|
: RawBridge[P];
|
|
122
118
|
} & {
|
|
123
|
-
|
|
119
|
+
notebook: {
|
|
120
|
+
readonly id: string;
|
|
121
|
+
subscribe(
|
|
122
|
+
id: string,
|
|
123
|
+
cursor: string | null,
|
|
124
|
+
emit: (event: string) => void,
|
|
125
|
+
): Promise<void>;
|
|
126
|
+
unsubscribe(id: string): void;
|
|
127
|
+
call(call: string): Promise<string>;
|
|
128
|
+
transaction(request: string): Promise<void>;
|
|
129
|
+
set_layout(layout: string): Promise<void>;
|
|
130
|
+
set_persistence(
|
|
131
|
+
persist: (contents: string, filename: string) => Promise<void>,
|
|
132
|
+
): void;
|
|
133
|
+
destroy(): void;
|
|
134
|
+
};
|
|
124
135
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import type { unstable_NotebookCall } from "@marimo-team/client";
|
|
3
4
|
import type { PyodideInterface } from "pyodide";
|
|
4
5
|
import {
|
|
5
6
|
createRPC,
|
|
@@ -8,14 +9,12 @@ import {
|
|
|
8
9
|
type RPCSchema,
|
|
9
10
|
} from "rpc-anywhere";
|
|
10
11
|
import type { UserConfig } from "@/core/config/config-schema";
|
|
11
|
-
import type { NotificationPayload } from "@/core/kernel/messages";
|
|
12
12
|
import type {
|
|
13
13
|
ListPackagesResponse,
|
|
14
14
|
PackageOperationResponse,
|
|
15
|
+
NotebookDocumentTransactionRequest,
|
|
15
16
|
SaveNotebookRequest,
|
|
16
17
|
} from "@/core/network/types";
|
|
17
|
-
import type { JsonString } from "@/utils/json/base64";
|
|
18
|
-
import { once } from "@/utils/once";
|
|
19
18
|
import { decodeUtf8 } from "@/utils/strings";
|
|
20
19
|
import { Deferred } from "../../../utils/Deferred";
|
|
21
20
|
import { prettyError } from "../../../utils/errors";
|
|
@@ -27,12 +26,11 @@ import { TRANSPORT_ID } from "./constants";
|
|
|
27
26
|
import { WasmFileSystem } from "./fs";
|
|
28
27
|
import { getController } from "./getController";
|
|
29
28
|
import { getPyodideVersion } from "./getPyodideVersion";
|
|
30
|
-
import { MessageBuffer } from "./message-buffer";
|
|
31
29
|
import { t } from "./tracer";
|
|
32
30
|
import type {
|
|
33
31
|
BridgePayload,
|
|
34
32
|
RawBridge,
|
|
35
|
-
|
|
33
|
+
WasmSession,
|
|
36
34
|
WasmController,
|
|
37
35
|
} from "./types";
|
|
38
36
|
import { shouldLoadDuckDBPackages } from "../utils";
|
|
@@ -72,16 +70,66 @@ async function loadPyodideAndPackages() {
|
|
|
72
70
|
}
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
const
|
|
76
|
-
(message: JsonString<NotificationPayload>) => {
|
|
77
|
-
rpc.send.kernelMessage({ message });
|
|
78
|
-
},
|
|
79
|
-
);
|
|
80
|
-
const bridgeReady = new Deferred<SerializedBridge>();
|
|
73
|
+
const sessionReady = new Deferred<WasmSession>();
|
|
81
74
|
let started = false;
|
|
82
75
|
|
|
83
76
|
// Handle RPC requests
|
|
77
|
+
const notebookSubscriptions = new Map<
|
|
78
|
+
string,
|
|
79
|
+
{ promise: Promise<void>; cancel(): void }
|
|
80
|
+
>();
|
|
81
|
+
async function getNotebook() {
|
|
82
|
+
const session = await sessionReady.promise;
|
|
83
|
+
return session.bridge.notebook;
|
|
84
|
+
}
|
|
85
|
+
|
|
84
86
|
const requestHandler = createRPCRequestHandler({
|
|
87
|
+
notebookSubscribe: (request: { id: string; cursor: string | null }) => {
|
|
88
|
+
let canceled = false;
|
|
89
|
+
const subscribing = (async () => {
|
|
90
|
+
const session = await sessionReady.promise;
|
|
91
|
+
const notebook = session.bridge.notebook;
|
|
92
|
+
try {
|
|
93
|
+
await notebook.subscribe(request.id, request.cursor, (event) => {
|
|
94
|
+
rpc.send.notebookEvent({ id: request.id, event });
|
|
95
|
+
});
|
|
96
|
+
if (!canceled) {
|
|
97
|
+
void session.start().catch((error: unknown) => {
|
|
98
|
+
rpc.send.initializedError({ error: prettyError(error) });
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
} finally {
|
|
102
|
+
notebook.destroy();
|
|
103
|
+
}
|
|
104
|
+
})();
|
|
105
|
+
notebookSubscriptions.set(request.id, {
|
|
106
|
+
promise: subscribing,
|
|
107
|
+
cancel: () => {
|
|
108
|
+
canceled = true;
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
return subscribing.finally(() => notebookSubscriptions.delete(request.id));
|
|
112
|
+
},
|
|
113
|
+
notebookUnsubscribe: async (id: string) => {
|
|
114
|
+
// An RPC timeout can close a reader while its subscription is still opening.
|
|
115
|
+
const pending = notebookSubscriptions.get(id);
|
|
116
|
+
pending?.cancel();
|
|
117
|
+
await pending?.promise.catch(() => undefined);
|
|
118
|
+
const notebook = await getNotebook();
|
|
119
|
+
try {
|
|
120
|
+
notebook.unsubscribe(id);
|
|
121
|
+
} finally {
|
|
122
|
+
notebook.destroy();
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
notebookCall: async (call: unstable_NotebookCall): Promise<unknown> => {
|
|
126
|
+
const notebook = await getNotebook();
|
|
127
|
+
try {
|
|
128
|
+
return JSON.parse(await notebook.call(JSON.stringify(call)));
|
|
129
|
+
} finally {
|
|
130
|
+
notebook.destroy();
|
|
131
|
+
}
|
|
132
|
+
},
|
|
85
133
|
/**
|
|
86
134
|
* Start the session
|
|
87
135
|
*/
|
|
@@ -105,29 +153,34 @@ const requestHandler = createRPCRequestHandler({
|
|
|
105
153
|
code: opts.code,
|
|
106
154
|
filename: opts.filename,
|
|
107
155
|
});
|
|
108
|
-
const
|
|
109
|
-
self.controller.
|
|
156
|
+
const prepareSession = t.wrapAsync(
|
|
157
|
+
self.controller.prepareSession.bind(self.controller),
|
|
110
158
|
);
|
|
111
|
-
const initializeOnce = once(() => {
|
|
112
|
-
rpc.send.initializingMessage({
|
|
113
|
-
message: "Initializing notebook...",
|
|
114
|
-
});
|
|
115
|
-
rpc.send.initialized({});
|
|
116
|
-
});
|
|
117
159
|
rpc.send.initializingMessage({
|
|
118
160
|
message: "Loading notebook and dependencies...",
|
|
119
161
|
});
|
|
120
|
-
const
|
|
162
|
+
const session = await prepareSession({
|
|
121
163
|
code: opts.code,
|
|
122
164
|
filename: opts.filename,
|
|
123
165
|
queryParameters: opts.queryParameters,
|
|
124
166
|
userConfig: opts.userConfig,
|
|
125
|
-
onMessage: (msg) => {
|
|
126
|
-
initializeOnce();
|
|
127
|
-
messageBuffer.push(msg);
|
|
128
|
-
},
|
|
129
167
|
});
|
|
130
|
-
|
|
168
|
+
const notebook = session.bridge.notebook;
|
|
169
|
+
try {
|
|
170
|
+
notebook.set_persistence(async (contents, filename) => {
|
|
171
|
+
// Keep file operations in the execution worker from syncing stale source.
|
|
172
|
+
self.pyodide.FS.writeFile(filename, contents);
|
|
173
|
+
self.pyodide.FS.writeFile(WasmFileSystem.NOTEBOOK_FILENAME, contents);
|
|
174
|
+
await rpc.proxy.request.persistNotebook({ filename, contents });
|
|
175
|
+
});
|
|
176
|
+
} finally {
|
|
177
|
+
notebook.destroy();
|
|
178
|
+
}
|
|
179
|
+
sessionReady.resolve(session);
|
|
180
|
+
rpc.send.initializingMessage({
|
|
181
|
+
message: "Initializing notebook...",
|
|
182
|
+
});
|
|
183
|
+
rpc.send.initialized({});
|
|
131
184
|
workerInitSpan.end("ok");
|
|
132
185
|
} catch (error) {
|
|
133
186
|
rpc.send.initializedError({
|
|
@@ -249,13 +302,21 @@ const requestHandler = createRPCRequestHandler({
|
|
|
249
302
|
};
|
|
250
303
|
},
|
|
251
304
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
305
|
+
documentTransaction: async (request: NotebookDocumentTransactionRequest) => {
|
|
306
|
+
const notebook = await getNotebook();
|
|
307
|
+
try {
|
|
308
|
+
await notebook.transaction(JSON.stringify(request));
|
|
309
|
+
} finally {
|
|
310
|
+
notebook.destroy();
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
setNotebookLayout: async (layout: SaveNotebookRequest["layout"]) => {
|
|
314
|
+
const notebook = await getNotebook();
|
|
315
|
+
try {
|
|
316
|
+
await notebook.set_layout(JSON.stringify(layout));
|
|
317
|
+
} finally {
|
|
318
|
+
notebook.destroy();
|
|
319
|
+
}
|
|
259
320
|
},
|
|
260
321
|
|
|
261
322
|
/**
|
|
@@ -302,7 +363,7 @@ const requestHandler = createRPCRequestHandler({
|
|
|
302
363
|
}
|
|
303
364
|
|
|
304
365
|
// Perform the function call to the Python bridge
|
|
305
|
-
const bridge = await
|
|
366
|
+
const { bridge } = await sessionReady.promise;
|
|
306
367
|
|
|
307
368
|
// Serialize the payload
|
|
308
369
|
const payloadString =
|
|
@@ -335,10 +396,9 @@ const requestHandler = createRPCRequestHandler({
|
|
|
335
396
|
export type WorkerSchema = RPCSchema<
|
|
336
397
|
{
|
|
337
398
|
messages: {
|
|
399
|
+
notebookEvent: { id: string; event: string };
|
|
338
400
|
// Emitted when the worker is ready
|
|
339
401
|
ready: {};
|
|
340
|
-
// Emitted when the kernel sends a message
|
|
341
|
-
kernelMessage: { message: JsonString<NotificationPayload> };
|
|
342
402
|
// Emitted when the Pyodide is initialized
|
|
343
403
|
initialized: {};
|
|
344
404
|
// Emitted when the Pyodide is initializing, with new messages
|
|
@@ -355,22 +415,15 @@ const rpc = createRPC<WorkerSchema, ParentSchema>({
|
|
|
355
415
|
transportId: TRANSPORT_ID,
|
|
356
416
|
}),
|
|
357
417
|
requestHandler,
|
|
418
|
+
// Persistence can include bootstrapping the storage worker.
|
|
419
|
+
maxRequestTime: Infinity,
|
|
358
420
|
});
|
|
359
421
|
|
|
360
422
|
rpc.addMessageListener("bootstrap", (config) => runtimeConfig.resolve(config));
|
|
361
423
|
|
|
362
424
|
rpc.send("ready", {});
|
|
363
425
|
|
|
364
|
-
/// Listeners
|
|
365
|
-
// When the consumer is ready, start the message buffer
|
|
366
|
-
rpc.addMessageListener("consumerReady", async () => {
|
|
367
|
-
await pyodideReadyPromise; // Make sure loading is done
|
|
368
|
-
messageBuffer.start();
|
|
369
|
-
});
|
|
370
|
-
|
|
371
426
|
const namesThatRequireSync = new Set<keyof RawBridge>([
|
|
372
|
-
"save",
|
|
373
|
-
"save_app_config",
|
|
374
427
|
"rename_file",
|
|
375
428
|
"create_file_or_directory",
|
|
376
429
|
"delete_file_or_directory",
|