@marimo-team/islands 0.25.3-dev17 → 0.25.3-dev173
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-Le_OBfmt.js} +21 -19
- package/dist/{ErrorBoundary-jaGao4LA.js → ErrorBoundary-wT3f3iJ1.js} +19 -19
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Tf1ghyQQ.js} +2 -2
- package/dist/any-language-editor-B92WMzoC.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-xlnbTG0T.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-CuORr6fL.js} +1142 -1141
- package/dist/{check-EDwSwP89.js → check-C9Mp9eCK.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-Cmd4a5jy.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-mSNp-WpO.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-CWC49D8X.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-De9FINtG.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-DweTkYdp.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-A6MR2TiE.js} +2 -2
- package/dist/{code-visibility-Bub8tnaA.js → code-visibility-ZReaeMaF.js} +25 -25
- package/dist/{common-CdT0nyN1.js → common-DCevHg1m.js} +6917 -6738
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-De584pZ4.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-BSvo5le-.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-tXRQslO6.js} +1 -1
- package/dist/{data-grid-overlay-editor-Dbcss6_2.js → data-grid-overlay-editor-CTC-bJus.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-r3t5VtwI.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-qgbC8YnT.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-CiHxEwtp.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-D95u15Ev.js} +1 -1
- package/dist/{dialog-CEBFZNyc.js → dialog-DVRfQuhD.js} +25 -25
- package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
- package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-DCMbbQ35.js} +1481 -1433
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-P7e4bryK.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-CUHZcmRj.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-DxJ3s8YO.js} +86 -86
- package/dist/{error-entries-Bv6bZPF3.js → error-entries-CmWMEsY_.js} +5756 -5643
- package/dist/{feedback-button-B3Wrnsf_.js → feedback-button-DwXkmewo.js} +35 -35
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-BGZ95AzI.js} +2 -2
- package/dist/{formats-27CW_UP4.js → formats-DI7HEVv7.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-BDYKJdqK.js → glide-data-editor-BlmcP-lw.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-D98laidb.js} +16 -16
- package/dist/{globals-DGTE1S0_.js → globals-BdRitZ4p.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-bpiQh7ND.js} +639 -602
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-BF0YX70D.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-_itsAAn-.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-VNW2Beqh.js} +1 -1
- package/dist/{label-BDKF3Afc.js → label-Qvw1E97W.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 +9672 -7674
- package/dist/{mermaid-CHo49Yv-.js → mermaid-CZ6FrClS.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-DR4ripvd.js} +1 -1
- package/dist/{number-overlay-editor-S8UJY0i5.js → number-overlay-editor-DQG-hFHT.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-CFr3XlGl.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-j91XYSLY.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-BZg56CCb.js → process-output-BzloOI7F.js} +4 -4
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-Cd47ZV9E.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-eJH6gLtX.js} +1 -1
- package/dist/{reveal-component-De4Pvf4V.js → reveal-component-D3r3vSTK.js} +14 -14
- package/dist/{select-BButFi-d.js → select-2KOiReNY.js} +536 -457
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-DdfFEIrm.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-h69nC3SI.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-DkjDvip8.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-DBHACnOo.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-ogImlOmp.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-D6x-zsci.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-DQpLtsHD.js} +1 -1
- package/dist/{toDate-UtiwmnH2.js → toDate-CDzoofJo.js} +37 -36
- package/dist/{toast-B9UMEi8u.js → toast-B5t9o6s_.js} +219 -201
- package/dist/{tooltip-BO1REbqs.js → tooltip-s4zZxwKe.js} +325 -301
- package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-BgDTd2tc.js} +1482 -1433
- package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-Bn8SxUqM.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-D3Tkfzej.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-CC2tnPCk.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-BJlxHqWa.js} +28 -25
- package/dist/{useTheme-CRnjkku0.js → useTheme-DMfQYmlG.js} +301 -297
- package/dist/{vega-component-BeF9dfyO.js → vega-component-CovWHi60.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-BD-SL_vq.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-BDgJV4ah.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-1hIHN6Rl.js} +2 -2
- package/package.json +16 -16
- package/src/__mocks__/requests.ts +0 -1
- 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/TableBottomBar.tsx +4 -1
- 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__/pagination.test.tsx +28 -1
- 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 +17 -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/pagination.tsx +44 -33
- 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/StagedAICell.tsx +10 -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 +9 -16
- 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__/document-sync-status.test.tsx +92 -0
- 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/document-sync-status.tsx +54 -0
- 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/footer.tsx +2 -0
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/connections/components.tsx +1 -1
- package/src/components/editor/controls/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/__tests__/staged-cells.test.ts +8 -5
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/ai/staged-cells.ts +7 -2
- package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +3 -15
- package/src/core/ai/tools/base.ts +16 -7
- package/src/core/ai/tools/edit-notebook-tool.ts +61 -48
- 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 +83 -346
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/document.test.ts +444 -0
- package/src/core/cells/__tests__/flush-document.test.ts +40 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +108 -0
- package/src/core/cells/__tests__/session.test.ts +117 -36
- package/src/core/cells/__tests__/with-document-save.test.ts +67 -0
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +65 -190
- package/src/core/cells/columns.ts +38 -0
- package/src/core/cells/document.ts +389 -0
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +1 -1
- package/src/core/cells/types.ts +22 -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 +42 -1
- package/src/core/codemirror/cells/extensions.ts +21 -3
- package/src/core/codemirror/format.ts +6 -5
- 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/__tests__/utils.test.ts +187 -15
- package/src/core/codemirror/language/cell-code.ts +114 -0
- package/src/core/codemirror/language/extension.ts +52 -35
- 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 +16 -24
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/codemirror/language/types.ts +7 -7
- package/src/core/codemirror/language/utils.ts +9 -39
- package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
- 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 -13
- 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 +13 -9
- package/src/core/errors/error-entries.ts +3 -0
- package/src/core/export/hooks.ts +1 -1
- package/src/core/export/layout.ts +2 -2
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +73 -43
- package/src/core/islands/__tests__/bridge.test.ts +72 -25
- package/src/core/islands/bootstrap.ts +46 -53
- package/src/core/islands/bridge.ts +74 -21
- 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/kernel/__tests__/handlers.test.ts +7 -153
- package/src/core/kernel/handlers.ts +18 -59
- 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 -2
- package/src/core/network/requests-network.ts +0 -9
- package/src/core/network/requests-static.ts +0 -1
- package/src/core/network/requests-toasting.tsx +0 -1
- package/src/core/network/types.ts +0 -5
- 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 +547 -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__/hold.test.ts +88 -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 +247 -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 +216 -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 +23 -0
- package/src/core/notebook/document/model.ts +105 -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 +418 -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 +48 -51
- 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 +10 -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 +663 -0
- package/src/core/session/active-notebook.ts +11 -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 +70 -68
- 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 +75 -53
- 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 +88 -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 +69 -37
- 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 +387 -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/data-table.stories.tsx +31 -0
- 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 → createReducer.test.tsx} +29 -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 +53 -26
- 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/cells/__tests__/apply-transaction.test.ts +0 -991
- package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
- package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
- package/src/core/cells/document-changes.ts +0 -944
- 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
|
@@ -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 {
|
|
@@ -21,19 +17,20 @@ import {
|
|
|
21
17
|
notebookAtom,
|
|
22
18
|
notebookReducer,
|
|
23
19
|
} from "../cells/cells";
|
|
20
|
+
import { followDocument } from "../cells/document";
|
|
21
|
+
import { notebookCells } from "../cells/utils";
|
|
22
|
+
import { createDocumentModel } from "../notebook/document";
|
|
24
23
|
import { defineCustomElement } from "../dom/defineCustomElement";
|
|
25
24
|
import { MarimoValueInputEvent } from "../dom/events";
|
|
26
25
|
import { UI_ELEMENT_REGISTRY } from "../dom/uiregistry";
|
|
27
26
|
import { FUNCTIONS_REGISTRY } from "../functions/FunctionRegistry";
|
|
27
|
+
import { createNotebookReplica } from "../notebook/replica";
|
|
28
28
|
import {
|
|
29
29
|
handleCellNotificationeration,
|
|
30
30
|
handleKernelReady,
|
|
31
31
|
handleRemoveUIElements,
|
|
32
32
|
} from "../kernel/handlers";
|
|
33
|
-
import type {
|
|
34
|
-
NotificationMessage,
|
|
35
|
-
NotificationMessageType,
|
|
36
|
-
} from "../kernel/messages";
|
|
33
|
+
import type { NotificationMessage } from "../kernel/messages";
|
|
37
34
|
import { queryParamHandlers } from "../kernel/queryParamHandlers";
|
|
38
35
|
import { RuntimeState } from "../kernel/RuntimeState";
|
|
39
36
|
import { initialModeAtom } from "../mode";
|
|
@@ -126,19 +123,26 @@ export async function initializeIslands(
|
|
|
126
123
|
}
|
|
127
124
|
});
|
|
128
125
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
126
|
+
// Each notification names the session that sent it.
|
|
127
|
+
bridge.consumeNotifications((notification, sessionGeneration) => {
|
|
128
|
+
handleNotification(notification, actions, store, sessionGeneration);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// The notebook's cells follow the managed session's host document.
|
|
132
|
+
const replica = createNotebookReplica(store);
|
|
133
|
+
replica.connect(bridge.notebookBackend, { onNotification: Functions.NOOP });
|
|
134
|
+
const documentModel = createDocumentModel({
|
|
135
|
+
store,
|
|
136
|
+
documentAtom: replica.documentAtom,
|
|
137
|
+
backendAtom: replica.backendAtom,
|
|
138
|
+
});
|
|
139
|
+
const lifetime = new AbortController();
|
|
140
|
+
documentModel.start({ signal: lifetime.signal });
|
|
141
|
+
followDocument({
|
|
142
|
+
store,
|
|
143
|
+
model: documentModel,
|
|
144
|
+
reconcile: actions.reconcileDocument,
|
|
145
|
+
signal: lifetime.signal,
|
|
142
146
|
});
|
|
143
147
|
|
|
144
148
|
// Track first user interaction before initialization completes
|
|
@@ -154,27 +158,15 @@ export async function initializeIslands(
|
|
|
154
158
|
RuntimeState.INSTANCE.start(bridge.sendComponentValues);
|
|
155
159
|
}
|
|
156
160
|
|
|
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
|
-
*/
|
|
161
|
+
/** Handles a single notification from the kernel. */
|
|
169
162
|
// oxlint-disable-next-line marimo/prefer-object-params
|
|
170
|
-
function
|
|
171
|
-
|
|
163
|
+
function handleNotification(
|
|
164
|
+
msg: NotificationMessage,
|
|
172
165
|
actions: NotebookActions,
|
|
173
166
|
store: Store,
|
|
174
167
|
sessionGeneration: number,
|
|
175
168
|
): void {
|
|
176
169
|
try {
|
|
177
|
-
const msg = jsonParseWithSpecialChar(message);
|
|
178
170
|
Logger.debug("Islands received message:", msg.op);
|
|
179
171
|
|
|
180
172
|
switch (msg.op) {
|
|
@@ -209,7 +201,6 @@ function handleMessage(
|
|
|
209
201
|
case "cache-info":
|
|
210
202
|
case "kernel-startup-error":
|
|
211
203
|
case "notebook-document-transaction":
|
|
212
|
-
case "attachments":
|
|
213
204
|
return;
|
|
214
205
|
|
|
215
206
|
case "completed-run":
|
|
@@ -224,9 +215,11 @@ function handleMessage(
|
|
|
224
215
|
return;
|
|
225
216
|
|
|
226
217
|
case "kernel-ready":
|
|
227
|
-
handleKernelReady(msg
|
|
218
|
+
handleKernelReady(msg, {
|
|
228
219
|
autoInstantiate: true,
|
|
229
|
-
|
|
220
|
+
cells: notebookCells(store.get(notebookAtom)),
|
|
221
|
+
setLastRun: actions.setLastRun,
|
|
222
|
+
resetCellRuntimes: actions.resetCellRuntimes,
|
|
230
223
|
setLayoutData: Functions.NOOP,
|
|
231
224
|
setAppConfig: Functions.NOOP,
|
|
232
225
|
setCapabilities: Functions.NOOP,
|
|
@@ -240,47 +233,47 @@ function handleMessage(
|
|
|
240
233
|
|
|
241
234
|
case "send-ui-element-message":
|
|
242
235
|
UI_ELEMENT_REGISTRY.broadcastMessage(
|
|
243
|
-
msg.
|
|
244
|
-
msg.
|
|
245
|
-
safeExtractSetUIElementMessageBuffers(msg
|
|
236
|
+
msg.ui_element,
|
|
237
|
+
msg.message,
|
|
238
|
+
safeExtractSetUIElementMessageBuffers(msg),
|
|
246
239
|
);
|
|
247
240
|
return;
|
|
248
241
|
|
|
249
242
|
case "remove-ui-elements":
|
|
250
|
-
handleRemoveUIElements(msg
|
|
243
|
+
handleRemoveUIElements(msg);
|
|
251
244
|
return;
|
|
252
245
|
|
|
253
246
|
case "function-call-result":
|
|
254
|
-
FUNCTIONS_REGISTRY.resolve(msg.
|
|
247
|
+
FUNCTIONS_REGISTRY.resolve(msg.function_call_id, msg);
|
|
255
248
|
return;
|
|
256
249
|
|
|
257
250
|
case "cell-op":
|
|
258
|
-
handleCellNotificationeration(msg
|
|
251
|
+
handleCellNotificationeration(msg, actions.handleCellMessage);
|
|
259
252
|
return;
|
|
260
253
|
|
|
261
254
|
case "alert":
|
|
262
255
|
toast({
|
|
263
|
-
title: msg.
|
|
264
|
-
description: renderHTML({ html: msg.
|
|
265
|
-
variant: msg.
|
|
256
|
+
title: msg.title,
|
|
257
|
+
description: renderHTML({ html: msg.description }),
|
|
258
|
+
variant: msg.variant,
|
|
266
259
|
});
|
|
267
260
|
return;
|
|
268
261
|
|
|
269
262
|
case "query-params-append":
|
|
270
|
-
queryParamHandlers.append(msg
|
|
263
|
+
queryParamHandlers.append(msg);
|
|
271
264
|
return;
|
|
272
265
|
case "query-params-set":
|
|
273
|
-
queryParamHandlers.set(msg
|
|
266
|
+
queryParamHandlers.set(msg);
|
|
274
267
|
return;
|
|
275
268
|
case "query-params-delete":
|
|
276
|
-
queryParamHandlers.delete(msg
|
|
269
|
+
queryParamHandlers.delete(msg);
|
|
277
270
|
return;
|
|
278
271
|
case "query-params-clear":
|
|
279
272
|
queryParamHandlers.clear();
|
|
280
273
|
return;
|
|
281
274
|
|
|
282
275
|
case "model-lifecycle":
|
|
283
|
-
handleWidgetMessage(WIDGET_REGISTRY, msg
|
|
276
|
+
handleWidgetMessage(WIDGET_REGISTRY, msg);
|
|
284
277
|
return;
|
|
285
278
|
|
|
286
279
|
case "consumer-capabilities":
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
/* oxlint-disable typescript/no-explicit-any */
|
|
3
3
|
|
|
4
|
+
import type { NotebookTransport } from "@marimo-team/client";
|
|
4
5
|
import { getWorkerRPC } from "@/core/wasm/rpc";
|
|
5
6
|
import { Deferred } from "@/utils/Deferred";
|
|
6
7
|
import { throwNotImplemented } from "@/utils/functions";
|
|
7
8
|
import { Logger } from "@/utils/Logger";
|
|
9
|
+
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
8
10
|
import { generateUUID } from "@/utils/uuid";
|
|
9
11
|
import { initialNotebookState, notebookAtom } from "../cells/cells";
|
|
10
|
-
import type {
|
|
12
|
+
import type { NotebookBackend } from "../notebook/replica";
|
|
13
|
+
import type { ClientCommand, NotificationMessage } from "../kernel/messages";
|
|
11
14
|
import type { EditRequests, RunRequests } from "../network/types";
|
|
12
15
|
import { store as defaultStore } from "../state/jotai";
|
|
13
16
|
import { getMarimoExportContext } from "../static/export-context";
|
|
14
17
|
import { createMarimoFile, parseMarimoIslandApps } from "./parse";
|
|
15
18
|
import { islandsInitializedAtom, islandsPendingInitialRunsAtom } from "./state";
|
|
16
|
-
import type {
|
|
19
|
+
import type { WorkerSchema } from "./worker/worker";
|
|
17
20
|
import type { WorkerFactory } from "./worker-factory";
|
|
18
21
|
import { DefaultWorkerFactory } from "./worker-factory";
|
|
19
22
|
|
|
@@ -52,14 +55,14 @@ interface AppSession {
|
|
|
52
55
|
* @example
|
|
53
56
|
* ```ts
|
|
54
57
|
* const bridge = new IslandsPyodideBridge();
|
|
55
|
-
* bridge.
|
|
58
|
+
* bridge.consumeNotifications((notification) => console.log(notification.op));
|
|
56
59
|
* await bridge.initializeApps();
|
|
57
60
|
* ```
|
|
58
61
|
*/
|
|
59
62
|
export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
60
63
|
private rpc: ReturnType<typeof getWorkerRPC<WorkerSchema>>;
|
|
61
|
-
private
|
|
62
|
-
| ((
|
|
64
|
+
private notificationConsumer:
|
|
65
|
+
| ((notification: NotificationMessage, sessionGeneration: number) => void)
|
|
63
66
|
| undefined;
|
|
64
67
|
private readonly store: typeof defaultStore;
|
|
65
68
|
private readonly root: Document | Element;
|
|
@@ -69,9 +72,37 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
69
72
|
private readonly activeSessionGenerations = new Set<number>();
|
|
70
73
|
private appTransition = Promise.resolve();
|
|
71
74
|
private workerReady = new Deferred<void>();
|
|
75
|
+
/** Where the managed session's host events go while a replica follows them. */
|
|
76
|
+
private stream: Parameters<NotebookTransport>[1] | undefined;
|
|
72
77
|
|
|
73
78
|
public initialized = new Deferred<void>();
|
|
74
79
|
|
|
80
|
+
/**
|
|
81
|
+
* The managed session's host stream, for a replica to follow. Replacing
|
|
82
|
+
* or stopping the session resets the stream, and the next session's
|
|
83
|
+
* snapshot follows.
|
|
84
|
+
*/
|
|
85
|
+
public readonly notebookBackend: NotebookBackend = {
|
|
86
|
+
transport: ({ signal }, handlers) =>
|
|
87
|
+
new Promise((resolve) => {
|
|
88
|
+
this.stream = handlers;
|
|
89
|
+
handlers.open();
|
|
90
|
+
signal.addEventListener(
|
|
91
|
+
"abort",
|
|
92
|
+
() => {
|
|
93
|
+
if (this.stream === handlers) {
|
|
94
|
+
this.stream = undefined;
|
|
95
|
+
}
|
|
96
|
+
resolve();
|
|
97
|
+
},
|
|
98
|
+
{ once: true },
|
|
99
|
+
);
|
|
100
|
+
}),
|
|
101
|
+
notebook: () => {
|
|
102
|
+
throw new Error("Islands do not edit notebooks");
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
75
106
|
public constructor(config: IslandsBridgeConfig = {}) {
|
|
76
107
|
this.store = config.store || defaultStore;
|
|
77
108
|
this.root = config.root || document;
|
|
@@ -110,14 +141,35 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
110
141
|
},
|
|
111
142
|
);
|
|
112
143
|
|
|
113
|
-
this.rpc.addMessageListener(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
144
|
+
this.rpc.addMessageListener(
|
|
145
|
+
"notebookEvent",
|
|
146
|
+
({ event, sessionGeneration }) => {
|
|
147
|
+
// A stopped session can still have events in transit after the next
|
|
148
|
+
// app takes ownership of the shared frontend state.
|
|
149
|
+
if (!this.activeSessionGenerations.has(sessionGeneration)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const frame = jsonParseWithSpecialChar(event) as {
|
|
153
|
+
event: string;
|
|
154
|
+
data: { marimo?: NotificationMessage };
|
|
155
|
+
};
|
|
156
|
+
if (frame.event === "marimo") {
|
|
157
|
+
if (frame.data.marimo) {
|
|
158
|
+
this.notificationConsumer?.(frame.data.marimo, sessionGeneration);
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// The replica follows the managed session's host document.
|
|
163
|
+
if (sessionGeneration === this.session?.sessionGeneration) {
|
|
164
|
+
this.stream?.message(frame);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** The managed session is gone, so its stream starts over. */
|
|
171
|
+
private resetNotebookStream(): void {
|
|
172
|
+
this.stream?.message({ event: "reset", data: {} });
|
|
121
173
|
}
|
|
122
174
|
|
|
123
175
|
public async initializeApps(): Promise<void> {
|
|
@@ -174,6 +226,7 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
174
226
|
const replacesSession = managesSingleApp && previousSession !== undefined;
|
|
175
227
|
this.activeSessionGenerations.add(request.sessionGeneration);
|
|
176
228
|
if (replacesSession) {
|
|
229
|
+
this.resetNotebookStream();
|
|
177
230
|
this.store.set(notebookAtom, initialNotebookState());
|
|
178
231
|
}
|
|
179
232
|
if (managesSingleApp || !previousSession) {
|
|
@@ -225,6 +278,7 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
225
278
|
this.store.set(islandsPendingInitialRunsAtom, null);
|
|
226
279
|
this.session = undefined;
|
|
227
280
|
this.sessionReady = new Deferred<AppSession>();
|
|
281
|
+
this.resetNotebookStream();
|
|
228
282
|
this.store.set(notebookAtom, initialNotebookState());
|
|
229
283
|
});
|
|
230
284
|
}
|
|
@@ -246,14 +300,14 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
246
300
|
await this.rpc.proxy.request.startSession(opts);
|
|
247
301
|
}
|
|
248
302
|
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
303
|
+
/** Receive each running session's marimo notifications. */
|
|
304
|
+
public consumeNotifications(
|
|
305
|
+
consumer: (
|
|
306
|
+
notification: NotificationMessage,
|
|
307
|
+
sessionGeneration: number,
|
|
308
|
+
) => void,
|
|
254
309
|
): void {
|
|
255
|
-
this.
|
|
256
|
-
this.rpc.proxy.send.consumerReady({});
|
|
310
|
+
this.notificationConsumer = consumer;
|
|
257
311
|
}
|
|
258
312
|
|
|
259
313
|
// ============================================================================
|
|
@@ -336,7 +390,6 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
|
|
|
336
390
|
public saveAppConfig = throwNotImplemented;
|
|
337
391
|
public saveCellConfig = throwNotImplemented;
|
|
338
392
|
public sendRestart = throwNotImplemented;
|
|
339
|
-
public sendDocumentTransaction = throwNotImplemented;
|
|
340
393
|
public readCode = throwNotImplemented;
|
|
341
394
|
public readSnippets = throwNotImplemented;
|
|
342
395
|
public previewDatasetColumn = throwNotImplemented;
|
|
@@ -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
|
|