@marimo-team/islands 0.25.3-dev16 → 0.25.3-dev162
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-BbDrlHvG.js} +17 -15
- package/dist/{ErrorBoundary-BEmYzeHb.js → ErrorBoundary-D6GPQ8dk.js} +16 -16
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Dr-fo8_z.js} +2 -2
- package/dist/any-language-editor-3E24SnCV.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-ByKIl9GG.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/assets/__vite-browser-external-DVeFf2e7.js +1 -0
- package/dist/assets/worker-C1pfNBsx.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-BsV2WH-4.js} +1143 -1142
- package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-IKDP18MQ.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-LkIgegwh.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-DReBYtnB.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-DQ0A0-1D.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-CwvXdCNE.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-D0XAxDsc.js} +2 -2
- package/dist/{code-visibility-D75HwL4W.js → code-visibility-DEIiTBMH.js} +6 -6
- package/dist/{common-hR234FGW.js → common-BmlT-bPP.js} +6828 -6648
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-BFN68nHr.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-CZt4rtLq.js} +1 -1
- package/dist/{data-grid-overlay-editor-D-NMDtk0.js → data-grid-overlay-editor-20Ge8ID1.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-D5cOz47_.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-Qgdppb4a.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-BsDCvily.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-igTkGjKI.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-BWnnAstC.js} +1277 -1229
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-BHuZGjIr.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-DKObXTVE.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-D40pmfQQ.js} +83 -83
- package/dist/{error-entries-Bv6bZPF3.js → error-entries-BpUJSLUZ.js} +1019 -978
- package/dist/{feedback-button-B3sliPJj.js → feedback-button-zWcCfXEI.js} +23 -23
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-DZI_kit0.js} +2 -2
- package/dist/{formats-27CW_UP4.js → formats-CwJHWasD.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-Dufy2ePW.js → glide-data-editor-Dn1Ekucb.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
- package/dist/{globals-B02fTTAH.js → globals-D_fhTQMd.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-CQr2-IDA.js} +632 -595
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-DdPl-7-n.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-DbyW6l59.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-BMX9SyBS.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 +7568 -7246
- package/dist/{mermaid-CHo49Yv-.js → mermaid-C8W8mTbA.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-Zd_tAxWL.js} +1 -1
- package/dist/{number-overlay-editor-EF8mCVoy.js → number-overlay-editor-ELtg9k3M.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-DjYydPdo.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-R5LKjO2n.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-BZg56CCb.js → process-output-Uw-VJE5V.js} +5 -5
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-C7uNKtfm.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-CxAIzQfl.js} +1 -1
- package/dist/{reveal-component-Boolki8h.js → reveal-component-CduO3VgT.js} +14 -14
- package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-B5tmlPd5.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-45FnujvG.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-C1hc5H7Y.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-DRWeqQTn.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-NTLas--s.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-ChPggljD.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-B4CZ9srJ.js} +1 -1
- package/dist/{toDate-UtiwmnH2.js → toDate-rySyYxqk.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-B7MiltyV.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-eCL_SdeG.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-DZmHBD_1.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-DRbRhzxg.js} +3 -3
- package/dist/{useTheme-CRnjkku0.js → useTheme-TLkqJsvo.js} +57 -54
- package/dist/{vega-component-BeF9dfyO.js → vega-component-DC6P127L.js} +148 -148
- 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-DJIvMt44.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-45H0zg0u.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-ZT-XzcPN.js} +2 -2
- package/package.json +16 -16
- package/src/__tests__/module-entry.test.ts +44 -0
- package/src/__tests__/mount.test.ts +1 -21
- package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
- 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/app-config/user-config-form.tsx +35 -0
- 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/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
- package/src/components/editor/__tests__/data-attributes.test.tsx +6 -2
- 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/actions/useRestartKernel.tsx +1 -1
- 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/__tests__/connection-notice.test.tsx +1 -1
- package/src/components/editor/alerts/connection-notice.tsx +1 -1
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/app-container.tsx +1 -1
- package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
- package/src/components/editor/cell/CreateCellButton.tsx +10 -12
- package/src/components/editor/cell/DeleteButton.tsx +3 -2
- package/src/components/editor/cell/RunButton.tsx +2 -2
- package/src/components/editor/cell/StopButton.tsx +2 -2
- 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 +2 -2
- 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/components/__tests__/feedback-button.test.tsx +1 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
- package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -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 +9 -18
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -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/Controls.tsx +2 -2
- 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/__tests__/notebook-menu-dropdown.test.tsx +1 -1
- 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 +9 -23
- package/src/components/editor/errors/send-error-report-button.tsx +3 -6
- 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/__tests__/status.test.tsx +5 -3
- package/src/components/editor/header/app-header.tsx +1 -1
- package/src/components/editor/header/status.tsx +40 -20
- 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 +12 -3
- package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
- package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
- package/src/components/editor/output/Outputs.css +8 -0
- 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/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/ai/__tests__/resources.test.ts +117 -0
- package/src/core/codemirror/ai/resources.ts +1 -1
- 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/readonly/__tests__/extension.test.ts +1 -1
- package/src/core/codemirror/readonly/extension.ts +2 -2
- 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/__tests__/config-schema.test.ts +5 -3
- package/src/core/config/config-schema.ts +3 -0
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/edit-app.tsx +2 -2
- package/src/core/errors/error-entries.ts +3 -0
- package/src/core/export/hooks.ts +1 -1
- 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/__tests__/connection.test.ts +1 -1
- package/src/core/network/connection-notice.ts +1 -1
- package/src/core/network/connection.ts +5 -3
- package/src/core/network/requests-lazy.ts +1 -1
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/notebook/attachments.ts +38 -0
- package/src/core/notebook/document/__tests__/codemirror.test.ts +485 -0
- package/src/core/notebook/document/__tests__/draft.test.ts +322 -0
- package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
- package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
- package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
- package/src/core/notebook/document/__tests__/model.test.ts +191 -0
- package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
- package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
- package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
- package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
- package/src/core/notebook/document/__tests__/state.test.ts +438 -0
- package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
- package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
- package/src/core/notebook/document/__tests__/test-host.ts +247 -0
- package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
- package/src/core/notebook/document/__tests__/user.ts +61 -0
- package/src/core/notebook/document/codemirror.ts +311 -0
- package/src/core/notebook/document/draft.ts +472 -0
- package/src/core/notebook/document/hooks.tsx +118 -0
- package/src/core/notebook/document/index.ts +15 -0
- package/src/core/notebook/document/model.ts +55 -0
- package/src/core/notebook/document/select.ts +41 -0
- package/src/core/notebook/document/state.ts +374 -0
- package/src/core/notebook/document/sync.ts +369 -0
- package/src/core/notebook/index.ts +18 -0
- package/src/core/notebook/replica/AGENTS.md +11 -0
- package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
- package/src/core/notebook/replica/__tests__/document.test.ts +126 -0
- package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
- package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
- package/src/core/notebook/replica/backend.ts +19 -0
- package/src/core/notebook/replica/connection.ts +42 -0
- package/src/core/notebook/replica/index.ts +13 -0
- package/src/core/notebook/replica/replica.ts +286 -0
- package/src/core/notebook/replica/resources/attachments.ts +22 -0
- package/src/core/notebook/replica/resources/document.ts +101 -0
- package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
- package/src/core/packages/useSandboxController.ts +1 -1
- package/src/core/run-app.tsx +3 -3
- package/src/core/runtime/__tests__/adapter.test.ts +1 -1
- package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +32 -58
- package/src/core/runtime/adapter.ts +1 -1
- package/src/core/runtime/config.ts +2 -2
- package/src/core/runtime/runtime.ts +38 -42
- package/src/core/runtime/types.ts +0 -2
- package/src/core/saving/filename.ts +1 -1
- package/src/core/saving/save-component.tsx +13 -4
- package/src/core/saving/useAutoSave.ts +1 -1
- package/src/core/session/__tests__/backend.test.ts +235 -0
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +183 -0
- package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +609 -0
- package/src/core/session/active-notebook.ts +7 -0
- package/src/core/session/backend.ts +125 -0
- package/src/core/{websocket → session}/types.ts +2 -2
- package/src/core/session/useNotebookReplica.ts +72 -0
- package/src/core/{websocket → session}/useNotebookSession.tsx +18 -25
- 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/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
- package/src/core/transports/__tests__/server.test.ts +408 -0
- package/src/core/transports/__tests__/static.test.ts +175 -0
- package/src/core/transports/__tests__/wasm.test.ts +166 -0
- package/src/core/{websocket → transports}/connection-state.ts +9 -16
- package/src/core/transports/server.ts +152 -0
- package/src/core/transports/static.ts +84 -0
- package/src/core/transports/wasm.ts +97 -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/css/globals.css +10 -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 +1 -5
- 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 +153 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/model.ts +3 -1
- package/src/plugins/impl/anywidget/registry.ts +18 -14
- 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/cell.stories.tsx +1 -1
- package/src/stories/editor.stories.tsx +24 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
- package/src/stories/runtime-story.tsx +1 -1
- 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__/createReducer.test.ts +1 -0
- package/src/utils/__tests__/numbers.test.ts +105 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +11 -2
- package/src/utils/blob.ts +1 -1
- package/src/utils/createReducer.ts +11 -5
- package/src/utils/maps.ts +0 -3
- package/src/utils/numbers.ts +79 -18
- package/src/utils/objects.ts +4 -9
- 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/attachments/state.ts +0 -21
- package/src/core/host/AGENTS.md +0 -6
- 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/connection.ts +0 -81
- 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/__tests__/useNotebookSession.hook.test.tsx +0 -883
- 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
- /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
- /package/src/core/{websocket → session}/connection-utils.ts +0 -0
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
} from "@/__tests__/branded";
|
|
11
11
|
import { notebookAtom } from "@/core/cells/cells";
|
|
12
12
|
import { islandsPendingInitialRunsAtom } from "@/core/islands/state";
|
|
13
|
-
import type { IslandsKernelMessage } from "../worker/worker";
|
|
14
13
|
|
|
15
14
|
type Base64String = components["schemas"]["Base64String"];
|
|
16
15
|
interface TestIslandApp {
|
|
@@ -89,9 +88,6 @@ vi.mock("@/core/wasm/rpc", () => ({
|
|
|
89
88
|
startSession: mockStartSessionRequest,
|
|
90
89
|
stopSession: mockStopSessionRequest,
|
|
91
90
|
},
|
|
92
|
-
send: {
|
|
93
|
-
consumerReady: vi.fn(),
|
|
94
|
-
},
|
|
95
91
|
},
|
|
96
92
|
addMessageListener: vi.fn(
|
|
97
93
|
(name: string, listener: (payload: never) => void) => {
|
|
@@ -177,17 +173,22 @@ describe("IslandsPyodideBridge", () => {
|
|
|
177
173
|
});
|
|
178
174
|
}
|
|
179
175
|
|
|
180
|
-
function
|
|
181
|
-
const listener = mockMessageListeners.get("
|
|
176
|
+
function sendNotebookEvent(sessionGeneration: number, frame: unknown) {
|
|
177
|
+
const listener = mockMessageListeners.get("notebookEvent");
|
|
182
178
|
if (!listener) {
|
|
183
|
-
throw new Error("Missing
|
|
179
|
+
throw new Error("Missing notebook event listener");
|
|
184
180
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
181
|
+
listener({ event: JSON.stringify(frame), sessionGeneration } as never);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Send a notification and return the call the consumer should receive. */
|
|
185
|
+
function sendKernelMessage(sessionGeneration: number) {
|
|
186
|
+
const notification = { op: "interrupted" };
|
|
187
|
+
sendNotebookEvent(sessionGeneration, {
|
|
188
|
+
event: "marimo",
|
|
189
|
+
data: { marimo: notification },
|
|
190
|
+
});
|
|
191
|
+
return [notification, sessionGeneration];
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
async function initializeSingleApp() {
|
|
@@ -300,7 +301,7 @@ describe("IslandsPyodideBridge", () => {
|
|
|
300
301
|
describe("app lifecycle", () => {
|
|
301
302
|
it("ignores messages after a session yields ownership", async () => {
|
|
302
303
|
const consumeMessage = vi.fn();
|
|
303
|
-
bridge.
|
|
304
|
+
bridge.consumeNotifications(consumeMessage);
|
|
304
305
|
mockSingleApp();
|
|
305
306
|
await bridge.initializeApps();
|
|
306
307
|
|
|
@@ -319,10 +320,7 @@ describe("IslandsPyodideBridge", () => {
|
|
|
319
320
|
sendKernelMessage(1);
|
|
320
321
|
const currentMessage = sendKernelMessage(2);
|
|
321
322
|
|
|
322
|
-
expect(consumeMessage.mock.calls).toEqual([
|
|
323
|
-
[firstMessage],
|
|
324
|
-
[currentMessage],
|
|
325
|
-
]);
|
|
323
|
+
expect(consumeMessage.mock.calls).toEqual([firstMessage, currentMessage]);
|
|
326
324
|
|
|
327
325
|
finishReplacement();
|
|
328
326
|
await replacement;
|
|
@@ -330,7 +328,7 @@ describe("IslandsPyodideBridge", () => {
|
|
|
330
328
|
|
|
331
329
|
it("restores message ownership when replacement fails", async () => {
|
|
332
330
|
const consumeMessage = vi.fn();
|
|
333
|
-
bridge.
|
|
331
|
+
bridge.consumeNotifications(consumeMessage);
|
|
334
332
|
mockSingleApp();
|
|
335
333
|
await bridge.initializeApps();
|
|
336
334
|
mockReplaceSessionRequest.mockRejectedValueOnce(
|
|
@@ -344,12 +342,12 @@ describe("IslandsPyodideBridge", () => {
|
|
|
344
342
|
const previousMessage = sendKernelMessage(1);
|
|
345
343
|
sendKernelMessage(2);
|
|
346
344
|
|
|
347
|
-
expect(consumeMessage.mock.calls).toEqual([
|
|
345
|
+
expect(consumeMessage.mock.calls).toEqual([previousMessage]);
|
|
348
346
|
});
|
|
349
347
|
|
|
350
348
|
it("ignores messages while their session is stopping", async () => {
|
|
351
349
|
const consumeMessage = vi.fn();
|
|
352
|
-
bridge.
|
|
350
|
+
bridge.consumeNotifications(consumeMessage);
|
|
353
351
|
mockSingleApp();
|
|
354
352
|
await bridge.initializeApps();
|
|
355
353
|
let finishStop!: () => void;
|
|
@@ -373,7 +371,7 @@ describe("IslandsPyodideBridge", () => {
|
|
|
373
371
|
|
|
374
372
|
it("forwards messages from every app in a multi-app document", async () => {
|
|
375
373
|
const consumeMessage = vi.fn();
|
|
376
|
-
bridge.
|
|
374
|
+
bridge.consumeNotifications(consumeMessage);
|
|
377
375
|
mockParseMarimoIslandApps.mockReturnValue([app(), app("app-2")]);
|
|
378
376
|
mockCreateMarimoFile
|
|
379
377
|
.mockReturnValueOnce("generated app 1")
|
|
@@ -385,10 +383,17 @@ describe("IslandsPyodideBridge", () => {
|
|
|
385
383
|
const secondMessage = sendKernelMessage(2);
|
|
386
384
|
sendKernelMessage(3);
|
|
387
385
|
|
|
388
|
-
expect(consumeMessage.mock.calls).toEqual([
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
386
|
+
expect(consumeMessage.mock.calls).toEqual([firstMessage, secondMessage]);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("delivers only the notebook stream's marimo notifications", async () => {
|
|
390
|
+
const consumeMessage = vi.fn();
|
|
391
|
+
bridge.consumeNotifications(consumeMessage);
|
|
392
|
+
await initializeSingleApp();
|
|
393
|
+
sendNotebookEvent(1, { event: "ready", id: "3", data: {} });
|
|
394
|
+
const notification = sendKernelMessage(1);
|
|
395
|
+
|
|
396
|
+
expect(consumeMessage.mock.calls).toEqual([notification]);
|
|
392
397
|
});
|
|
393
398
|
|
|
394
399
|
it("holds controls until the first app session is ready", async () => {
|
|
@@ -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
|
|