@marimo-team/islands 0.25.3-dev14 → 0.25.3-dev140
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-CNMliVzw.js → ConnectedDataExplorerComponent-BAiSVaHj.js} +17 -15
- package/dist/{ErrorBoundary-S_edj6VQ.js → ErrorBoundary-CTJ1U1fx.js} +16 -16
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-BBHN92-F.js} +2 -2
- package/dist/any-language-editor-3E24SnCV.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.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-DaHynk8g.js → chat-ui-CvB8Map3.js} +1142 -1141
- package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-hJXey5p2.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-JMzTmmVW.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-BIyoHTXi.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-CCzH2Uwa.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-DB1kOPS6.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-CPaFL0OB.js} +2 -2
- package/dist/{code-visibility-BBdICLTP.js → code-visibility-C1jZfwPW.js} +6 -6
- package/dist/{common-7r9HNiTn.js → common-CNv_7gvI.js} +6766 -6590
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-CF93uliH.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-BBB-_p9D.js} +1 -1
- package/dist/{data-grid-overlay-editor-Bz1FTAfW.js → data-grid-overlay-editor-t0t17DPI.js} +5 -5
- package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-BsSJJldB.js → diagram-S7CK7UJ4-BynCnbyt.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-svOxikMa.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-BVQSnPx0.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.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-BIN1sweE.js → ebnfDiagram-PWID7BFC-C9tq9-Qo.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-BiaeB7Fi.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-D40pmfQQ.js} +83 -83
- package/dist/{error-entries-Bv6bZPF3.js → error-entries-CmFDQ9CA.js} +1018 -977
- package/dist/{feedback-button-BAheGhdl.js → feedback-button-JzaiyZZm.js} +23 -23
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-f-sLm87k.js} +2 -2
- package/dist/{formats-27CW_UP4.js → formats-CCxaLPNs.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-CAvrTnyB.js → glide-data-editor-B3eq-1SC.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
- package/dist/{globals-C03jB5fY.js → globals-BW8TOLYQ.js} +3 -3
- package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
- package/dist/{html-to-image-Bf8QMGi4.js → html-to-image-BrC8OJcj.js} +632 -595
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-BHrWywBe.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-Da4s0Reg.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.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 +7551 -7231
- package/dist/{mermaid-CHo49Yv-.js → mermaid-ClwTt7OD.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-D60oMZtT.js} +1 -1
- package/dist/{number-overlay-editor-DRF7iVLO.js → number-overlay-editor-DoUnDbPE.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-BqvywNJA.js → pegDiagram-XKGWAZYB-B9wFpMga.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-BZwvMuBT.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-BZg56CCb.js → process-output-Bw-vzyoy.js} +5 -5
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-DqhZGsN2.js} +2 -2
- package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
- package/dist/{requirementDiagram-BXWQKSXE-a_MxGvxe.js → requirementDiagram-BXWQKSXE-CL5dYARV.js} +1 -1
- package/dist/{reveal-component-QSvE6jwa.js → reveal-component-ClNn1CDl.js} +14 -14
- package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-BSUCRd2x.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-DiSh_qJC.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-B-1Hvyb0.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH--HtiR4yB.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-Bdfhrd-2.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.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-D3c46WM5.js → timeline-definition-24CTP7MA-Cs4EfFD3.js} +1 -1
- package/dist/{toDate-UtiwmnH2.js → toDate-DGvRHwTk.js} +19 -18
- 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-BeF9dfyO.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-BSZD8JcZ.js → vennDiagram-4TSXK5OY-DRu0vRjO.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-DzbDxwDY.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-CLWj6ZFQ.js} +2 -2
- package/package.json +14 -14
- package/src/__tests__/host-imports.test.ts +1 -0
- package/src/__tests__/module-entry.test.ts +32 -0
- package/src/__tests__/mount.test.ts +0 -20
- 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__/data-table.test.tsx +1 -0
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
- 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 +36 -20
- package/src/components/data-table/data-table.tsx +13 -1
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +76 -48
- 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/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/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/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-modal.test.tsx +24 -0
- package/src/components/editor/actions/pair-with-agent-modal.tsx +18 -15
- 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/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 +12 -18
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- 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 +12 -23
- 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/MarimoTracebackOutput.tsx +19 -17
- package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
- package/src/components/editor/output/ansi-reduce.ts +33 -20
- 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/state.ts +5 -8
- 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 +3 -1
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +117 -36
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +3 -1
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +1 -1
- 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/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/host/AGENTS.md +8 -2
- 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 +71 -0
- package/src/core/host/__tests__/replica.test.ts +550 -0
- package/src/core/host/__tests__/static.test.ts +169 -0
- package/src/core/host/__tests__/wasm.test.ts +163 -0
- package/src/core/host/backend.ts +19 -0
- package/src/core/host/connection.ts +1 -40
- 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 +72 -0
- package/src/core/host/wasm.ts +107 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +16 -42
- package/src/core/islands/__tests__/bridge.test.ts +31 -26
- package/src/core/islands/bootstrap.ts +22 -52
- 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/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +32 -58
- package/src/core/runtime/runtime.ts +38 -42
- package/src/core/runtime/types.ts +0 -2
- 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 +42 -1
- package/src/core/wasm/__tests__/worker.test.ts +182 -0
- package/src/core/wasm/bridge.ts +40 -21
- package/src/core/wasm/rpc.ts +0 -1
- 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/types.ts +23 -14
- package/src/core/wasm/worker/worker.ts +77 -36
- package/src/core/websocket/__tests__/backend.test.ts +228 -0
- package/src/core/websocket/__tests__/connection-state.test.ts +0 -12
- package/src/core/websocket/__tests__/useNotebookReplica.hook.test.tsx +141 -0
- package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +154 -428
- package/src/core/websocket/backend.ts +130 -0
- package/src/core/websocket/connection-state.ts +1 -11
- 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 +2 -2
- package/src/core/websocket/useNotebookReplica.ts +69 -0
- package/src/core/websocket/useNotebookSession.tsx +18 -25
- 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 +0 -4
- 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 +117 -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__/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/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-DZ_YTVus.js +0 -76
- package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
- package/dist/assets/worker-HPY9fbhz.js +0 -114
- package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- package/src/core/host/__tests__/events.test.ts +0 -46
- package/src/core/host/__tests__/notebook-client.test.ts +0 -191
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/events.ts +0 -60
- package/src/core/host/notebook-client.ts +0 -226
- package/src/core/host/protocol.ts +0 -1943
- 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__/createConnectionTransport.test.ts +0 -49
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -140
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
- 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/create.ts +0 -31
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -50
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useNotebookClient.ts +0 -80
|
@@ -9,11 +9,7 @@ import {
|
|
|
9
9
|
} from "@/plugins/impl/anywidget/registry";
|
|
10
10
|
import { initializePlugins } from "@/plugins/plugins";
|
|
11
11
|
import { Functions } from "@/utils/functions";
|
|
12
|
-
import {
|
|
13
|
-
safeExtractSetUIElementMessageBuffers,
|
|
14
|
-
type JsonString,
|
|
15
|
-
} from "@/utils/json/base64";
|
|
16
|
-
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
12
|
+
import { safeExtractSetUIElementMessageBuffers } from "@/utils/json/base64";
|
|
17
13
|
import { Logger } from "@/utils/Logger";
|
|
18
14
|
import { logNever } from "@/utils/assertNever";
|
|
19
15
|
import {
|
|
@@ -30,10 +26,7 @@ import {
|
|
|
30
26
|
handleKernelReady,
|
|
31
27
|
handleRemoveUIElements,
|
|
32
28
|
} from "../kernel/handlers";
|
|
33
|
-
import type {
|
|
34
|
-
NotificationMessage,
|
|
35
|
-
NotificationMessageType,
|
|
36
|
-
} from "../kernel/messages";
|
|
29
|
+
import type { NotificationMessage } from "../kernel/messages";
|
|
37
30
|
import { queryParamHandlers } from "../kernel/queryParamHandlers";
|
|
38
31
|
import { RuntimeState } from "../kernel/RuntimeState";
|
|
39
32
|
import { initialModeAtom } from "../mode";
|
|
@@ -126,19 +119,9 @@ export async function initializeIslands(
|
|
|
126
119
|
}
|
|
127
120
|
});
|
|
128
121
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// as NotificationPayload (just {data}), but the actual wire format
|
|
133
|
-
// includes the outer op too.
|
|
134
|
-
// Worker metadata identifies the session that emitted the message.
|
|
135
|
-
bridge.consumeMessages(({ message, sessionGeneration }) => {
|
|
136
|
-
handleMessage(
|
|
137
|
-
message as unknown as JsonString<IslandsNotificationMessage>,
|
|
138
|
-
actions,
|
|
139
|
-
store,
|
|
140
|
-
sessionGeneration,
|
|
141
|
-
);
|
|
122
|
+
// Each notification names the session that sent it.
|
|
123
|
+
bridge.consumeNotifications((notification, sessionGeneration) => {
|
|
124
|
+
handleNotification(notification, actions, store, sessionGeneration);
|
|
142
125
|
});
|
|
143
126
|
|
|
144
127
|
// Track first user interaction before initialization completes
|
|
@@ -154,27 +137,15 @@ export async function initializeIslands(
|
|
|
154
137
|
RuntimeState.INSTANCE.start(bridge.sendComponentValues);
|
|
155
138
|
}
|
|
156
139
|
|
|
157
|
-
|
|
158
|
-
[K in NotificationMessageType]: {
|
|
159
|
-
data: Extract<NotificationMessage, { op: K }>;
|
|
160
|
-
op: K;
|
|
161
|
-
};
|
|
162
|
-
}[NotificationMessageType];
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Handles a single message from the kernel.
|
|
166
|
-
*
|
|
167
|
-
* Wire format from Python: {"op": "<name>", "data": {"op": "<name>", ...}}
|
|
168
|
-
*/
|
|
140
|
+
/** Handles a single notification from the kernel. */
|
|
169
141
|
// oxlint-disable-next-line marimo/prefer-object-params
|
|
170
|
-
function
|
|
171
|
-
|
|
142
|
+
function handleNotification(
|
|
143
|
+
msg: NotificationMessage,
|
|
172
144
|
actions: NotebookActions,
|
|
173
145
|
store: Store,
|
|
174
146
|
sessionGeneration: number,
|
|
175
147
|
): void {
|
|
176
148
|
try {
|
|
177
|
-
const msg = jsonParseWithSpecialChar(message);
|
|
178
149
|
Logger.debug("Islands received message:", msg.op);
|
|
179
150
|
|
|
180
151
|
switch (msg.op) {
|
|
@@ -209,7 +180,6 @@ function handleMessage(
|
|
|
209
180
|
case "cache-info":
|
|
210
181
|
case "kernel-startup-error":
|
|
211
182
|
case "notebook-document-transaction":
|
|
212
|
-
case "attachments":
|
|
213
183
|
return;
|
|
214
184
|
|
|
215
185
|
case "completed-run":
|
|
@@ -224,7 +194,7 @@ function handleMessage(
|
|
|
224
194
|
return;
|
|
225
195
|
|
|
226
196
|
case "kernel-ready":
|
|
227
|
-
handleKernelReady(msg
|
|
197
|
+
handleKernelReady(msg, {
|
|
228
198
|
autoInstantiate: true,
|
|
229
199
|
setCells: actions.setCells,
|
|
230
200
|
setLayoutData: Functions.NOOP,
|
|
@@ -240,47 +210,47 @@ function handleMessage(
|
|
|
240
210
|
|
|
241
211
|
case "send-ui-element-message":
|
|
242
212
|
UI_ELEMENT_REGISTRY.broadcastMessage(
|
|
243
|
-
msg.
|
|
244
|
-
msg.
|
|
245
|
-
safeExtractSetUIElementMessageBuffers(msg
|
|
213
|
+
msg.ui_element,
|
|
214
|
+
msg.message,
|
|
215
|
+
safeExtractSetUIElementMessageBuffers(msg),
|
|
246
216
|
);
|
|
247
217
|
return;
|
|
248
218
|
|
|
249
219
|
case "remove-ui-elements":
|
|
250
|
-
handleRemoveUIElements(msg
|
|
220
|
+
handleRemoveUIElements(msg);
|
|
251
221
|
return;
|
|
252
222
|
|
|
253
223
|
case "function-call-result":
|
|
254
|
-
FUNCTIONS_REGISTRY.resolve(msg.
|
|
224
|
+
FUNCTIONS_REGISTRY.resolve(msg.function_call_id, msg);
|
|
255
225
|
return;
|
|
256
226
|
|
|
257
227
|
case "cell-op":
|
|
258
|
-
handleCellNotificationeration(msg
|
|
228
|
+
handleCellNotificationeration(msg, actions.handleCellMessage);
|
|
259
229
|
return;
|
|
260
230
|
|
|
261
231
|
case "alert":
|
|
262
232
|
toast({
|
|
263
|
-
title: msg.
|
|
264
|
-
description: renderHTML({ html: msg.
|
|
265
|
-
variant: msg.
|
|
233
|
+
title: msg.title,
|
|
234
|
+
description: renderHTML({ html: msg.description }),
|
|
235
|
+
variant: msg.variant,
|
|
266
236
|
});
|
|
267
237
|
return;
|
|
268
238
|
|
|
269
239
|
case "query-params-append":
|
|
270
|
-
queryParamHandlers.append(msg
|
|
240
|
+
queryParamHandlers.append(msg);
|
|
271
241
|
return;
|
|
272
242
|
case "query-params-set":
|
|
273
|
-
queryParamHandlers.set(msg
|
|
243
|
+
queryParamHandlers.set(msg);
|
|
274
244
|
return;
|
|
275
245
|
case "query-params-delete":
|
|
276
|
-
queryParamHandlers.delete(msg
|
|
246
|
+
queryParamHandlers.delete(msg);
|
|
277
247
|
return;
|
|
278
248
|
case "query-params-clear":
|
|
279
249
|
queryParamHandlers.clear();
|
|
280
250
|
return;
|
|
281
251
|
|
|
282
252
|
case "model-lifecycle":
|
|
283
|
-
handleWidgetMessage(WIDGET_REGISTRY, msg
|
|
253
|
+
handleWidgetMessage(WIDGET_REGISTRY, msg);
|
|
284
254
|
return;
|
|
285
255
|
|
|
286
256
|
case "consumer-capabilities":
|
|
@@ -5,15 +5,16 @@ import { getWorkerRPC } from "@/core/wasm/rpc";
|
|
|
5
5
|
import { Deferred } from "@/utils/Deferred";
|
|
6
6
|
import { throwNotImplemented } from "@/utils/functions";
|
|
7
7
|
import { Logger } from "@/utils/Logger";
|
|
8
|
+
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
8
9
|
import { generateUUID } from "@/utils/uuid";
|
|
9
10
|
import { initialNotebookState, notebookAtom } from "../cells/cells";
|
|
10
|
-
import type { ClientCommand } from "../kernel/messages";
|
|
11
|
+
import type { ClientCommand, NotificationMessage } from "../kernel/messages";
|
|
11
12
|
import type { EditRequests, RunRequests } from "../network/types";
|
|
12
13
|
import { store as defaultStore } from "../state/jotai";
|
|
13
14
|
import { getMarimoExportContext } from "../static/export-context";
|
|
14
15
|
import { createMarimoFile, parseMarimoIslandApps } from "./parse";
|
|
15
16
|
import { islandsInitializedAtom, islandsPendingInitialRunsAtom } from "./state";
|
|
16
|
-
import type {
|
|
17
|
+
import type { WorkerSchema } from "./worker/worker";
|
|
17
18
|
import type { WorkerFactory } from "./worker-factory";
|
|
18
19
|
import { DefaultWorkerFactory } from "./worker-factory";
|
|
19
20
|
|
|
@@ -52,14 +53,14 @@ interface AppSession {
|
|
|
52
53
|
* @example
|
|
53
54
|
* ```ts
|
|
54
55
|
* const bridge = new IslandsPyodideBridge();
|
|
55
|
-
* bridge.
|
|
56
|
+
* bridge.consumeNotifications((notification) => console.log(notification.op));
|
|
56
57
|
* await bridge.initializeApps();
|
|
57
58
|
* ```
|
|
58
59
|
*/
|
|
59
60
|
export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
60
61
|
private rpc: ReturnType<typeof getWorkerRPC<WorkerSchema>>;
|
|
61
|
-
private
|
|
62
|
-
| ((
|
|
62
|
+
private notificationConsumer:
|
|
63
|
+
| ((notification: NotificationMessage, sessionGeneration: number) => void)
|
|
63
64
|
| undefined;
|
|
64
65
|
private readonly store: typeof defaultStore;
|
|
65
66
|
private readonly root: Document | Element;
|
|
@@ -110,14 +111,24 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
110
111
|
},
|
|
111
112
|
);
|
|
112
113
|
|
|
113
|
-
this.rpc.addMessageListener(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
this.rpc.addMessageListener(
|
|
115
|
+
"notebookEvent",
|
|
116
|
+
({ event, sessionGeneration }) => {
|
|
117
|
+
// A stopped session can still have events in transit after the next
|
|
118
|
+
// app takes ownership of the shared frontend state.
|
|
119
|
+
if (!this.activeSessionGenerations.has(sessionGeneration)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Islands follow only the notebook's marimo notifications.
|
|
123
|
+
const frame = jsonParseWithSpecialChar(event) as {
|
|
124
|
+
event: string;
|
|
125
|
+
data: { marimo?: NotificationMessage };
|
|
126
|
+
};
|
|
127
|
+
if (frame.event === "marimo" && frame.data.marimo) {
|
|
128
|
+
this.notificationConsumer?.(frame.data.marimo, sessionGeneration);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
);
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
public async initializeApps(): Promise<void> {
|
|
@@ -246,14 +257,14 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
246
257
|
await this.rpc.proxy.request.startSession(opts);
|
|
247
258
|
}
|
|
248
259
|
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
260
|
+
/** Receive each running session's marimo notifications. */
|
|
261
|
+
public consumeNotifications(
|
|
262
|
+
consumer: (
|
|
263
|
+
notification: NotificationMessage,
|
|
264
|
+
sessionGeneration: number,
|
|
265
|
+
) => void,
|
|
254
266
|
): void {
|
|
255
|
-
this.
|
|
256
|
-
this.rpc.proxy.send.consumerReady({});
|
|
267
|
+
this.notificationConsumer = consumer;
|
|
257
268
|
}
|
|
258
269
|
|
|
259
270
|
// ============================================================================
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { MockRequestClient } from "@/__mocks__/requests";
|
|
5
6
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
6
7
|
import type { CellId } from "@/core/cells/ids";
|
|
7
8
|
import * as requestsModule from "@/core/network/requests";
|
|
@@ -18,7 +19,8 @@ vi.mock("@/utils/copy", () => ({
|
|
|
18
19
|
}));
|
|
19
20
|
|
|
20
21
|
describe("IslandControls", () => {
|
|
21
|
-
const mockSendRun =
|
|
22
|
+
const mockSendRun =
|
|
23
|
+
vi.fn<ReturnType<typeof requestsModule.useRequestClient>["sendRun"]>();
|
|
22
24
|
const mockCopyToClipboard = vi.fn();
|
|
23
25
|
const mockCodeCallback = vi.fn(() => "print('test code')");
|
|
24
26
|
const cellId = "test-cell-id" as CellId;
|
|
@@ -30,11 +32,11 @@ describe("IslandControls", () => {
|
|
|
30
32
|
|
|
31
33
|
beforeEach(() => {
|
|
32
34
|
vi.clearAllMocks();
|
|
33
|
-
mockSendRun.mockResolvedValue(
|
|
35
|
+
mockSendRun.mockResolvedValue(null);
|
|
34
36
|
|
|
35
|
-
vi.spyOn(requestsModule, "useRequestClient").mockReturnValue(
|
|
36
|
-
sendRun: mockSendRun,
|
|
37
|
-
|
|
37
|
+
vi.spyOn(requestsModule, "useRequestClient").mockReturnValue(
|
|
38
|
+
MockRequestClient.create({ sendRun: mockSendRun }),
|
|
39
|
+
);
|
|
38
40
|
|
|
39
41
|
vi.spyOn(copyModule, "copyToClipboard").mockImplementation(
|
|
40
42
|
mockCopyToClipboard,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { PyodideInterface } from "pyodide";
|
|
4
4
|
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { Deferred } from "@/utils/Deferred";
|
|
5
6
|
import { ReadonlyWasmController } from "../controller";
|
|
6
7
|
|
|
7
8
|
class TestController extends ReadonlyWasmController {
|
|
@@ -50,15 +51,71 @@ function createPyodideStub(
|
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
function
|
|
54
|
-
return controller.
|
|
54
|
+
function prepareSession(controller: TestController, code: string) {
|
|
55
|
+
return controller.prepareSession({
|
|
55
56
|
code,
|
|
56
57
|
filename: `${code}.py`,
|
|
57
|
-
onMessage: vi.fn(),
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
async function startSession(controller: TestController, code: string) {
|
|
62
|
+
const session = await prepareSession(controller, code);
|
|
63
|
+
void session.start();
|
|
64
|
+
return session;
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
describe("WASM controller session lifecycle", () => {
|
|
68
|
+
it("releases a prepared session and ignores start after stop", async () => {
|
|
69
|
+
const { init, pyodide } = createPyodideStub();
|
|
70
|
+
const controller = new TestController();
|
|
71
|
+
controller.setPyodide(pyodide);
|
|
72
|
+
|
|
73
|
+
const session = await prepareSession(controller, "current");
|
|
74
|
+
await session.stop();
|
|
75
|
+
expect(init.destroy).toHaveBeenCalledOnce();
|
|
76
|
+
await session.start();
|
|
77
|
+
expect(init).not.toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it.each(["resolve", "reject"] as const)(
|
|
81
|
+
"releases a stopped session before its dependencies %s",
|
|
82
|
+
async (outcome) => {
|
|
83
|
+
const dependencies = new Deferred<void>();
|
|
84
|
+
const { init, loadPackagesFromImports, pyodide, bridge, stop } =
|
|
85
|
+
createPyodideStub();
|
|
86
|
+
loadPackagesFromImports.mockReturnValue(dependencies.promise);
|
|
87
|
+
const controller = new TestController();
|
|
88
|
+
controller.setPyodide(pyodide);
|
|
89
|
+
const session = await prepareSession(controller, "current");
|
|
90
|
+
const starting = session.start();
|
|
91
|
+
expect(init).not.toHaveBeenCalled();
|
|
92
|
+
await session.stop();
|
|
93
|
+
expect(init.destroy).toHaveBeenCalledOnce();
|
|
94
|
+
expect(bridge.destroy).toHaveBeenCalledOnce();
|
|
95
|
+
if (outcome === "resolve") {
|
|
96
|
+
dependencies.resolve();
|
|
97
|
+
} else {
|
|
98
|
+
dependencies.reject(new Error("Loading failed after stop"));
|
|
99
|
+
}
|
|
100
|
+
await starting;
|
|
101
|
+
await session.stop();
|
|
102
|
+
expect(stop).toHaveBeenCalledOnce();
|
|
103
|
+
expect(init).not.toHaveBeenCalled();
|
|
104
|
+
},
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
it("reports dependency failures when starting an active session", async () => {
|
|
108
|
+
const { init, loadPackagesFromImports, pyodide } = createPyodideStub();
|
|
109
|
+
loadPackagesFromImports.mockRejectedValue(new Error("Dependency failed"));
|
|
110
|
+
const controller = new TestController();
|
|
111
|
+
controller.setPyodide(pyodide);
|
|
112
|
+
const session = await prepareSession(controller, "current");
|
|
113
|
+
await expect(session.start()).rejects.toThrow("Dependency failed");
|
|
114
|
+
expect(init).not.toHaveBeenCalled();
|
|
115
|
+
expect(init.destroy).toHaveBeenCalledOnce();
|
|
116
|
+
await session.stop();
|
|
117
|
+
});
|
|
118
|
+
|
|
62
119
|
it("stops and releases the active session", async () => {
|
|
63
120
|
const { init, packages, pyodide, sessionResources, stop } =
|
|
64
121
|
createPyodideStub();
|
|
@@ -116,7 +173,6 @@ describe("WASM controller session lifecycle", () => {
|
|
|
116
173
|
|
|
117
174
|
await startSession(controller, "first");
|
|
118
175
|
await startSession(controller, "second");
|
|
119
|
-
second.bridge.destroy();
|
|
120
176
|
|
|
121
177
|
expect(first.stop.destroy).not.toHaveBeenCalled();
|
|
122
178
|
|
|
@@ -126,6 +182,8 @@ describe("WASM controller session lifecycle", () => {
|
|
|
126
182
|
expect(second.stop).toHaveBeenCalledOnce();
|
|
127
183
|
expect(first.stop.destroy).toHaveBeenCalledOnce();
|
|
128
184
|
expect(second.stop.destroy).toHaveBeenCalledOnce();
|
|
185
|
+
expect(first.bridge.destroy).toHaveBeenCalledOnce();
|
|
186
|
+
expect(second.bridge.destroy).toHaveBeenCalledOnce();
|
|
129
187
|
});
|
|
130
188
|
|
|
131
189
|
it("continues stopping sessions after one stop fails", async () => {
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import type { PyodideInterface } from "pyodide";
|
|
3
3
|
import { defaultUserConfig } from "@/core/config/config-schema";
|
|
4
|
-
import type { NotificationPayload } from "@/core/kernel/messages";
|
|
5
4
|
import { DefaultWasmController } from "@/core/wasm/worker/bootstrap";
|
|
6
5
|
import { WasmFileSystem } from "@/core/wasm/worker/fs";
|
|
7
|
-
import type {
|
|
8
|
-
import type { JsonString } from "@/utils/json/base64";
|
|
6
|
+
import type { WasmSession } from "@/core/wasm/worker/types";
|
|
9
7
|
import { Logger } from "../../../utils/Logger";
|
|
10
8
|
|
|
11
9
|
export class ReadonlyWasmController extends DefaultWasmController {
|
|
@@ -37,19 +35,15 @@ export class ReadonlyWasmController extends DefaultWasmController {
|
|
|
37
35
|
return { code, filename };
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
public override async
|
|
38
|
+
public override async prepareSession(opts: {
|
|
41
39
|
code: string;
|
|
42
40
|
filename: string | null;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const bridge = super.startSession({
|
|
41
|
+
}): Promise<WasmSession> {
|
|
42
|
+
return super.prepareSession({
|
|
46
43
|
queryParameters: {},
|
|
47
44
|
code: opts.code,
|
|
48
45
|
filename: opts.filename,
|
|
49
|
-
onMessage: opts.onMessage,
|
|
50
46
|
userConfig: defaultUserConfig(),
|
|
51
47
|
});
|
|
52
|
-
|
|
53
|
-
return bridge;
|
|
54
48
|
}
|
|
55
49
|
}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import type { PyodideInterface } from "pyodide";
|
|
4
|
-
import type { PyProxy } from "pyodide/ffi";
|
|
5
4
|
import {
|
|
6
5
|
createRPC,
|
|
7
6
|
createRPCRequestHandler,
|
|
8
7
|
createWorkerParentTransport,
|
|
9
8
|
type RPCSchema,
|
|
10
9
|
} from "rpc-anywhere";
|
|
11
|
-
import type { NotificationPayload } from "@/core/kernel/messages";
|
|
12
10
|
import type { ParentSchema } from "@/core/wasm/rpc";
|
|
13
11
|
import { shouldLoadDuckDBPackages } from "@/core/wasm/utils";
|
|
14
12
|
import { TRANSPORT_ID } from "@/core/wasm/worker/constants";
|
|
15
13
|
import { getPyodideVersion } from "@/core/wasm/worker/getPyodideVersion";
|
|
16
|
-
import { MessageBuffer } from "@/core/wasm/worker/message-buffer";
|
|
17
14
|
import type { RawBridge, SerializedBridge } from "@/core/wasm/worker/types";
|
|
18
|
-
import type { JsonString } from "@/utils/json/base64";
|
|
19
15
|
import { Logger } from "@/utils/Logger";
|
|
20
16
|
import { prettyError } from "../../../utils/errors";
|
|
21
17
|
import { invariant } from "../../../utils/invariant";
|
|
@@ -45,14 +41,11 @@ async function loadPyodideAndPackages() {
|
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
const pyodideReadyPromise = loadPyodideAndPackages();
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
/** An event of one session's notebook stream. */
|
|
45
|
+
export interface IslandsNotebookEvent {
|
|
46
|
+
event: string;
|
|
50
47
|
sessionGeneration: number;
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
const messageBuffer = new MessageBuffer<IslandsKernelMessage>((payload) => {
|
|
54
|
-
rpc.send.kernelMessage(payload);
|
|
55
|
-
});
|
|
56
49
|
interface SessionRequest {
|
|
57
50
|
code: string;
|
|
58
51
|
appId: string;
|
|
@@ -79,21 +72,22 @@ async function startSession(
|
|
|
79
72
|
code: opts.code,
|
|
80
73
|
filename: `app-${opts.appId}.py`,
|
|
81
74
|
});
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
75
|
+
const session = await self.controller.prepareSession(notebook);
|
|
76
|
+
// Follow before the session instantiates. Each subscription begins with
|
|
77
|
+
// its own kernel-ready and the session's retained notifications.
|
|
78
|
+
try {
|
|
79
|
+
await follow(session.bridge, opts.sessionGeneration);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
await session.stop();
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
void session.start().catch((error: unknown) => {
|
|
85
|
+
rpc.send.initializedError({ error: prettyError(error) });
|
|
90
86
|
});
|
|
91
|
-
if (activeSession) {
|
|
92
|
-
(nextBridge as unknown as PyProxy).destroy();
|
|
93
|
-
} else {
|
|
87
|
+
if (!activeSession) {
|
|
94
88
|
activeSession = {
|
|
95
89
|
appId: opts.appId,
|
|
96
|
-
bridge:
|
|
90
|
+
bridge: session.bridge,
|
|
97
91
|
sessionGeneration: opts.sessionGeneration,
|
|
98
92
|
};
|
|
99
93
|
}
|
|
@@ -107,10 +101,23 @@ async function startSession(
|
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
async function stopActiveSession(): Promise<void> {
|
|
110
|
-
|
|
104
|
+
// Stopping closes every session and its notebook subscriptions.
|
|
111
105
|
await self.controller.stopSession();
|
|
112
106
|
activeSession = undefined;
|
|
113
|
-
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function follow(
|
|
110
|
+
bridge: SerializedBridge,
|
|
111
|
+
sessionGeneration: number,
|
|
112
|
+
): Promise<void> {
|
|
113
|
+
const notebook = bridge.notebook;
|
|
114
|
+
try {
|
|
115
|
+
await notebook.subscribe(`island-${sessionGeneration}`, null, (event) => {
|
|
116
|
+
rpc.send.notebookEvent({ event, sessionGeneration });
|
|
117
|
+
});
|
|
118
|
+
} finally {
|
|
119
|
+
notebook.destroy();
|
|
120
|
+
}
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
function enqueueSession<T>(operation: () => Promise<T>): Promise<T> {
|
|
@@ -243,8 +250,8 @@ export type WorkerSchema = RPCSchema<
|
|
|
243
250
|
messages: {
|
|
244
251
|
// Emitted when the worker is ready
|
|
245
252
|
ready: {};
|
|
246
|
-
// Emitted
|
|
247
|
-
|
|
253
|
+
// Emitted for each event of a session's notebook stream
|
|
254
|
+
notebookEvent: IslandsNotebookEvent;
|
|
248
255
|
// Emitted when the Pyodide is initialized
|
|
249
256
|
initialized: {};
|
|
250
257
|
// Emitted when the Pyodide fails to initialize
|
|
@@ -263,13 +270,6 @@ const rpc = createRPC<WorkerSchema, ParentSchema>({
|
|
|
263
270
|
|
|
264
271
|
rpc.send("ready", {});
|
|
265
272
|
|
|
266
|
-
/// Listeners
|
|
267
|
-
// When the consumer is ready, start the message buffer
|
|
268
|
-
rpc.addMessageListener("consumerReady", async () => {
|
|
269
|
-
await pyodideReadyPromise; // Make sure loading is done
|
|
270
|
-
messageBuffer.start();
|
|
271
|
-
});
|
|
272
|
-
|
|
273
273
|
function getMarimoVersion() {
|
|
274
274
|
return self.name; // We store the version in the worker name
|
|
275
275
|
}
|
|
@@ -25,7 +25,7 @@ describe("RuntimeState", () => {
|
|
|
25
25
|
|
|
26
26
|
beforeEach(() => {
|
|
27
27
|
vi.clearAllMocks();
|
|
28
|
-
mockSendComponentValues = vi.fn((
|
|
28
|
+
mockSendComponentValues = vi.fn(() => Promise.resolve(null));
|
|
29
29
|
uiElementRegistry = UIElementRegistry.INSTANCE;
|
|
30
30
|
uiElementRegistry.entries.clear();
|
|
31
31
|
|
|
@@ -7,8 +7,10 @@ import { waitFor } from "../state/jotai";
|
|
|
7
7
|
import { type ConnectionStatus, ConnectionState } from "../websocket/types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Shared application state, not the actual event-stream status.
|
|
11
|
+
*
|
|
12
|
+
* TODO(MO-8051) Expose read-only connection state and derive UI availability
|
|
13
|
+
* separately.
|
|
12
14
|
*/
|
|
13
15
|
export const connectionAtom = atom<ConnectionStatus>({
|
|
14
16
|
state: ConnectionState.NOT_STARTED,
|
|
@@ -17,11 +17,17 @@ export function useConnectionNotice(
|
|
|
17
17
|
const notice = useAtomValue(connectionNoticeAtom);
|
|
18
18
|
const connected = useAtomValue(isConnectedAtom);
|
|
19
19
|
const elapsed = useDelayElapsed(notice?.pending ? delayMs : 0);
|
|
20
|
-
const [previous, setPrevious] = useState<ConnectionNotice | null>(
|
|
20
|
+
const [previous, setPrevious] = useState<ConnectionNotice | null>(
|
|
21
|
+
elapsed ? notice : null,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const visibleNotice = elapsed ? notice : null;
|
|
25
|
+
if ((notice || !connected) && previous !== visibleNotice) {
|
|
26
|
+
setPrevious(visibleNotice);
|
|
27
|
+
}
|
|
21
28
|
|
|
22
29
|
useEffect(() => {
|
|
23
30
|
if (notice || !connected) {
|
|
24
|
-
setPrevious(elapsed ? notice : null);
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
27
33
|
const timeout = setTimeout(() => setPrevious(null), 1500);
|