@marimo-team/islands 0.25.3-dev10 → 0.25.3-dev101
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-Dhf5EGs5.js} +14 -14
- package/dist/{ErrorBoundary-BsqSMK9Y.js → ErrorBoundary-kKLKZNGz.js} +8 -8
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Di400kYu.js} +2 -2
- package/dist/any-language-editor-k2B8YI3Y.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-BdTJcsNJ.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/assets/__vite-browser-external-35VXYmnw.js +1 -0
- package/dist/assets/{worker-HPY9fbhz.js → worker-Dq8y-WM5.js} +2 -2
- package/dist/{button-CvjkwdSk.js → button-BxB3RDjN.js} +1 -1
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-BgR0osfN.js} +2 -2
- package/dist/{chat-ui-0lKdOoQ3.js → chat-ui-BIgPxfPP.js} +1141 -1141
- package/dist/{check-EDwSwP89.js → check-P35dc2dH.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-mtD7aJBw.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-DybB1ShH.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-DNhhdCex.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-NhAQhlDf.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-GTL0l5xS.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-BWrM2ruI.js} +2 -2
- package/dist/{code-visibility-CXQvUXHT.js → code-visibility-CK84K0J7.js} +6 -6
- package/dist/{common-CuD-CAC-.js → common-DbG2Uufx.js} +5550 -5451
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-CPoxUG7G.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-CX22wa7c.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-Df6Pp-cl.js} +1 -1
- package/dist/{data-grid-overlay-editor-DgeyYmC1.js → data-grid-overlay-editor-BggIiNWF.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-CctU9kVx.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-FVHjCF9j.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-BSDbwFFv.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-BX8kW7Nc.js} +1 -1
- package/dist/{dialog-CEBFZNyc.js → dialog-C1PcpCqX.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-B_7xD2X4.js} +177 -169
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-DtapdLet.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-BAru9jHt.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-Sl2FlSJ4.js} +2 -2
- package/dist/{error-entries-DSvFWT_M.js → error-entries-TAO6kEhF.js} +797 -784
- package/dist/{feedback-button-DZMj9PF3.js → feedback-button-CRF9v3d1.js} +29 -29
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-CjaeFeea.js} +2 -2
- package/dist/{formats-CeOmU1MU.js → formats-V8ifA0Bk.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-g_L8FLAC.js → glide-data-editor-DgZRBzBJ.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Bt8_pBa2.js} +16 -16
- package/dist/{globals-CYGlmBXb.js → globals-Bxo0esfB.js} +3 -3
- package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
- package/dist/{html-to-image-B8s5SgGm.js → html-to-image-CWdayGZU.js} +29 -29
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-B1hmUggC.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-DUeT3t-d.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-DEUnNNgc.js} +1 -1
- package/dist/{label-BDKF3Afc.js → label-BRnUC0NX.js} +2 -2
- package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
- package/dist/{loader-BQOfjTIJ.js → loader-Bm8cy3e8.js} +12 -12
- package/dist/main.js +3236 -3019
- package/dist/{mermaid-CHo49Yv-.js → mermaid-B0fXpsNP.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-CPexlhDQ.js} +1 -1
- package/dist/{number-overlay-editor-9VRv-pdj.js → number-overlay-editor-CI5EhMRq.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-CMpp1OOQ.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-DlMWg5t1.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-CKRXyszb.js → process-output-DD-oSvZk.js} +4 -4
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-DBJfseeO.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-BC7V639r.js} +1 -1
- package/dist/{reveal-component-C87mv9Mn.js → reveal-component-Y4-XPwJF.js} +23 -23
- package/dist/{select-BButFi-d.js → select-B0LRDH0g.js} +4 -4
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-CgesU6F-.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-CcT0slVc.js} +4 -4
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-lH_BUhs3.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-8LL6FrBe.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-Cuf9B9kE.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-BoMMtOPh.js} +2 -2
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-DfhRvAFi.js} +2 -2
- package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
- package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-yzzw4TF4.js} +1 -1
- package/dist/{toDate-vIXljnsr.js → toDate-DKH0_kMo.js} +29 -31
- package/dist/{toast-B9UMEi8u.js → toast-CFWpihJU.js} +4 -4
- package/dist/{tooltip-BO1REbqs.js → tooltip-CKO1pHJo.js} +2 -2
- package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-DBCITLeF.js} +1 -1
- package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-D0mLJstx.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-c_yJtkAe.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-BpPWi3G3.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-BkdeVdXC.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-Dum8WSXq.js} +3 -3
- package/dist/{useTheme-CRnjkku0.js → useTheme-CfeaVw5D.js} +6 -6
- package/dist/{vega-component-DTG6zxaY.js → vega-component-DgytCKrL.js} +147 -147
- package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
- package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
- package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-eJOrTqqC.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-TILPvee6.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-DUPvRwwJ.js} +2 -2
- package/package.json +7 -7
- package/src/__tests__/host-imports.test.ts +1 -0
- package/src/components/app-config/ai-config.tsx +7 -2
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/acp/__tests__/state.test.ts +2 -2
- package/src/components/chat/acp/blocks.tsx +2 -2
- 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/__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__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +105 -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__/storage.test.ts +4 -1
- package/src/components/data-table/charts/charts.tsx +35 -25
- 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/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 +7 -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/row-viewer-panel/row-viewer.tsx +2 -2
- 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 +63 -2
- package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
- package/src/components/datasources/column-preview.tsx +8 -2
- package/src/components/datasources/datasources.tsx +47 -35
- package/src/components/debugger/debugger-code.tsx +5 -0
- package/src/components/dependency-graph/panels.tsx +2 -1
- package/src/components/editor/SortableCell.tsx +1 -3
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +24 -0
- package/src/components/editor/actions/pair-with-agent-modal.tsx +18 -15
- package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/cell/CreateCellButton.tsx +8 -10
- package/src/components/editor/cell/DeleteButton.tsx +1 -0
- package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +1 -1
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +30 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +12 -18
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/connections/components.tsx +1 -1
- package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
- package/src/components/editor/controls/command-palette.tsx +22 -10
- package/src/components/editor/dynamic-favicon.tsx +21 -40
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +12 -23
- package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
- package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
- package/src/components/editor/file-tree/file-explorer.tsx +10 -5
- 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/notebook-banner.tsx +1 -0
- package/src/components/editor/output/MarimoTracebackOutput.tsx +2 -2
- package/src/components/editor/output/ansi-reduce.ts +6 -0
- package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
- package/src/components/editor/package-alert.tsx +6 -4
- 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.tsx +2 -2
- 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.tsx +2 -2
- package/src/components/ui/alert-dialog.tsx +1 -1
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/attachments/state.ts +5 -8
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
- package/src/core/cells/__tests__/cell.test.ts +39 -0
- package/src/core/cells/__tests__/cells.test.ts +3 -1
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/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 +1 -1
- package/src/core/codemirror/keymaps/vim.ts +2 -6
- package/src/core/codemirror/language/languages/markdown.ts +1 -1
- package/src/core/codemirror/language/languages/python.ts +3 -3
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +4 -4
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/document/__tests__/draft.test.ts +322 -0
- package/src/core/document/__tests__/fixtures.ts +92 -0
- package/src/core/document/__tests__/lifecycle-scenarios.test.ts +61 -0
- package/src/core/document/__tests__/model.test.ts +158 -0
- package/src/core/document/__tests__/protocol-fixtures.ts +38 -0
- package/src/core/document/__tests__/recovery-scenarios.test.ts +230 -0
- package/src/core/document/__tests__/scenario-fixture.ts +42 -0
- package/src/core/document/__tests__/scenarios.test.ts +205 -0
- package/src/core/document/__tests__/state.test.ts +446 -0
- package/src/core/document/__tests__/submission.test.ts +201 -0
- package/src/core/document/__tests__/test-host.test.ts +92 -0
- package/src/core/document/__tests__/test-host.ts +247 -0
- package/src/core/document/__tests__/test-notebook.ts +139 -0
- package/src/core/document/__tests__/user.ts +61 -0
- package/src/core/document/draft.ts +472 -0
- package/src/core/document/index.ts +10 -0
- package/src/core/document/model.ts +53 -0
- package/src/core/document/state.ts +401 -0
- package/src/core/document/sync.ts +359 -0
- package/src/core/edit-app.tsx +2 -2
- package/src/core/host/AGENTS.md +12 -2
- package/src/core/host/__tests__/attachments.test.ts +56 -0
- package/src/core/host/__tests__/document.test.ts +126 -0
- package/src/core/host/__tests__/fixtures.ts +41 -0
- package/src/core/host/__tests__/notebook-client.test.ts +570 -0
- package/src/core/host/connection.ts +42 -0
- package/src/core/host/notebook-client.ts +297 -0
- package/src/core/host/resources/attachments.ts +22 -0
- package/src/core/host/resources/document.ts +101 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +0 -26
- package/src/core/islands/bootstrap.ts +0 -1
- package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
- package/src/core/network/connection.ts +4 -2
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/run-app.tsx +2 -2
- package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +18 -17
- package/src/core/runtime/runtime.ts +26 -30
- package/src/core/state/__tests__/jotai.test.tsx +108 -0
- package/src/core/state/jotai.ts +1 -1
- package/src/core/static/files.ts +2 -0
- package/src/core/wasm/bridge.ts +2 -10
- package/src/core/wasm/store.ts +3 -3
- package/src/core/wasm/worker/bootstrap.ts +1 -1
- package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts} +15 -29
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +223 -0
- package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +606 -0
- package/src/core/websocket/connection-state.ts +60 -0
- package/src/core/websocket/state.ts +7 -0
- package/src/core/websocket/transports/__tests__/notebook.test.ts +502 -0
- package/src/core/websocket/transports/notebook.ts +213 -0
- package/src/core/websocket/types.ts +9 -39
- package/src/core/websocket/useNotebookClient.ts +89 -0
- package/src/core/websocket/{useMarimoKernelConnection.tsx → useNotebookSession.tsx} +53 -233
- package/src/css/globals.css +5 -0
- package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
- package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
- package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
- package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
- package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
- package/src/hooks/__tests__/useScript.test.tsx +77 -0
- package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
- package/src/hooks/useAsyncData.ts +3 -3
- package/src/hooks/useDataSourceDiscovery.ts +6 -4
- package/src/hooks/useDebounce.ts +5 -8
- package/src/hooks/useDeepCompareMemoize.ts +1 -1
- package/src/hooks/useDelayElapsed.ts +14 -10
- package/src/hooks/useElapsedTime.ts +3 -3
- 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/plugins/core/registerReactComponent.tsx +1 -1
- package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataTablePlugin.tsx +14 -15
- 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 +0 -1
- 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__/SliderPlugin.test.tsx +24 -3
- package/src/plugins/impl/anywidget/__tests__/registry.test.ts +2 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/runtime.ts +21 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
- package/src/plugins/impl/chat/chat-ui.tsx +12 -10
- 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/state/reducer.ts +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +0 -1
- 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/vega/make-selectable.ts +4 -7
- package/src/plugins/layout/RoutesPlugin.tsx +1 -1
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/button.stories.tsx +1 -0
- package/src/stories/editor.stories.tsx +24 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- package/src/stories/select.stories.tsx +2 -2
- package/src/stories/switchable-multi-select.stories.tsx +1 -1
- package/src/utils/__tests__/arrays.test.ts +35 -0
- package/src/utils/__tests__/batch-requests.test.ts +3 -3
- package/src/utils/__tests__/numbers.test.ts +48 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +10 -0
- package/src/utils/blob.ts +1 -1
- package/src/utils/numbers.ts +28 -17
- package/src/utils/objects.ts +3 -7
- package/src/utils/once.ts +19 -19
- 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/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/protocol.ts +0 -1943
- package/src/core/state/__tests__/jotai.test.ts +0 -25
- package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +0 -789
- package/src/core/websocket/__tests__/useWebSocket.test.ts +0 -49
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -338
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -61
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useWebSocket.tsx +0 -88
|
@@ -8,8 +8,9 @@ import { RuntimeManager } from "../runtime";
|
|
|
8
8
|
import type { RuntimeConfig } from "../types";
|
|
9
9
|
|
|
10
10
|
// Mock the session module
|
|
11
|
-
vi.mock("@/core/kernel/session", () => ({
|
|
12
|
-
|
|
11
|
+
vi.mock("@/core/kernel/session", async (importOriginal) => ({
|
|
12
|
+
...(await importOriginal<typeof import("@/core/kernel/session")>()),
|
|
13
|
+
getSessionId: () => "test-session-id",
|
|
13
14
|
}));
|
|
14
15
|
|
|
15
16
|
vi.mock("@/utils/Logger", () => ({ Logger: Mocks.quietLogger() }));
|
|
@@ -59,6 +60,7 @@ describe("RuntimeManager", () => {
|
|
|
59
60
|
expect(url.protocol).toBe("wss:");
|
|
60
61
|
expect(url.hostname).toBe("example.com");
|
|
61
62
|
expect(url.pathname).toBe("/ws");
|
|
63
|
+
expect(url.searchParams.has("types")).toBe(false);
|
|
62
64
|
expect(url.searchParams.get("session_id")).toBe(sessionId);
|
|
63
65
|
});
|
|
64
66
|
|
|
@@ -219,15 +221,6 @@ describe("RuntimeManager", () => {
|
|
|
219
221
|
});
|
|
220
222
|
|
|
221
223
|
describe("getSseURL", () => {
|
|
222
|
-
it("should return an http(s) URL with the session ID", () => {
|
|
223
|
-
const runtime = new RuntimeManager(mockConfig);
|
|
224
|
-
const url = runtime.getSseURL("1234" as SessionId);
|
|
225
|
-
|
|
226
|
-
expect(url.protocol).toBe("https:");
|
|
227
|
-
expect(url.pathname).toBe("/sse");
|
|
228
|
-
expect(url.searchParams.get("session_id")).toBe("1234");
|
|
229
|
-
});
|
|
230
|
-
|
|
231
224
|
it("should never put the auth token in the URL, even cross-origin", () => {
|
|
232
225
|
// SSE requests can send headers, so auth travels in the
|
|
233
226
|
// Authorization header; a token in the URL would leak into
|
|
@@ -256,7 +249,8 @@ describe("RuntimeManager", () => {
|
|
|
256
249
|
const url = runtime.getSseURL("s_123" as SessionId);
|
|
257
250
|
|
|
258
251
|
expect(url.searchParams.get("access_token")).toBeNull();
|
|
259
|
-
expect(url.searchParams.get("
|
|
252
|
+
expect(url.searchParams.get("query_params")).toBe("foo=bar");
|
|
253
|
+
expect(url.toString()).not.toContain("page-token");
|
|
260
254
|
} finally {
|
|
261
255
|
window.history.pushState({}, "", original);
|
|
262
256
|
}
|
|
@@ -676,9 +670,16 @@ describe("RuntimeManager", () => {
|
|
|
676
670
|
expect(httpUrl.searchParams.get("base_param")).toBe("existing");
|
|
677
671
|
|
|
678
672
|
// Should preserve all window-level query params (including custom ones)
|
|
679
|
-
expect(
|
|
680
|
-
|
|
681
|
-
|
|
673
|
+
expect(
|
|
674
|
+
Object.fromEntries(
|
|
675
|
+
new URLSearchParams(wsUrl.searchParams.get("query_params") ?? ""),
|
|
676
|
+
),
|
|
677
|
+
).toEqual({
|
|
678
|
+
base_param: "existing",
|
|
679
|
+
custom_param: "value123",
|
|
680
|
+
user_token: "abc",
|
|
681
|
+
theme: "dark",
|
|
682
|
+
});
|
|
682
683
|
expect(httpUrl.searchParams.get("custom_param")).toBe("value123");
|
|
683
684
|
expect(httpUrl.searchParams.get("user_token")).toBe("abc");
|
|
684
685
|
expect(httpUrl.searchParams.get("theme")).toBe("dark");
|
|
@@ -737,7 +738,7 @@ describe("RuntimeManager", () => {
|
|
|
737
738
|
);
|
|
738
739
|
});
|
|
739
740
|
|
|
740
|
-
it("
|
|
741
|
+
it("warns when creating WebSocket URLs from blob URLs", () => {
|
|
741
742
|
const runtime = new RuntimeManager({
|
|
742
743
|
url: "blob:https://example.com/12345678-1234-1234-1234-123456789abc",
|
|
743
744
|
lazy: true,
|
|
@@ -745,7 +746,7 @@ describe("RuntimeManager", () => {
|
|
|
745
746
|
const sessionId = "test" as SessionId;
|
|
746
747
|
|
|
747
748
|
expect(runtime.getWsURL(sessionId).toString()).toMatchInlineSnapshot(
|
|
748
|
-
`"blob:https://example.com/12345678-1234-1234-1234-123456789abc?session_id=test"`,
|
|
749
|
+
`"blob:https://example.com/12345678-1234-1234-1234-123456789abc?query_params=&session_id=test"`,
|
|
749
750
|
);
|
|
750
751
|
expect(Logger.warn).toHaveBeenCalledOnce();
|
|
751
752
|
});
|
|
@@ -9,6 +9,8 @@ import { isStaticNotebook } from "../static/static-state";
|
|
|
9
9
|
import { isWasm } from "../wasm/utils";
|
|
10
10
|
import type { RuntimeConfig } from "./types";
|
|
11
11
|
|
|
12
|
+
const knownQueryParams = new Set(Object.values(KnownQueryParams));
|
|
13
|
+
|
|
12
14
|
export class RuntimeManager {
|
|
13
15
|
private initialHealthyCheck = new Deferred<void>();
|
|
14
16
|
private config: RuntimeConfig;
|
|
@@ -71,10 +73,7 @@ export class RuntimeManager {
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
for (const [key, value] of currentParams.entries()) {
|
|
74
|
-
if (
|
|
75
|
-
restrictToKnownQueryParams &&
|
|
76
|
-
!Object.values(KnownQueryParams).includes(key)
|
|
77
|
-
) {
|
|
76
|
+
if (restrictToKnownQueryParams && !knownQueryParams.has(key)) {
|
|
78
77
|
continue;
|
|
79
78
|
}
|
|
80
79
|
baseUrl.searchParams.set(key, value);
|
|
@@ -129,32 +128,32 @@ export class RuntimeManager {
|
|
|
129
128
|
return asWsUrl(this.appendCrossOriginAuth(url).toString());
|
|
130
129
|
}
|
|
131
130
|
|
|
132
|
-
/**
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return searchParams;
|
|
131
|
+
/** Keep notebook page parameters separate from connection options. */
|
|
132
|
+
private getSessionURL(path: string, sessionId: SessionId): URL {
|
|
133
|
+
const url = this.formatHttpURL({ path });
|
|
134
|
+
const notebookParams = new URLSearchParams(this.httpURL.search);
|
|
135
|
+
const pageParams = new URLSearchParams(window.location.search);
|
|
136
|
+
for (const key of pageParams.keys()) {
|
|
137
|
+
notebookParams.delete(key);
|
|
138
|
+
}
|
|
139
|
+
for (const [key, value] of pageParams) {
|
|
140
|
+
notebookParams.append(key, value);
|
|
141
|
+
}
|
|
142
|
+
// These parameters are internal and are not exposed by mo.query_params().
|
|
143
|
+
notebookParams.delete(KnownQueryParams.accessToken);
|
|
144
|
+
notebookParams.delete("refresh_token");
|
|
145
|
+
notebookParams.delete(KnownQueryParams.sessionId);
|
|
146
|
+
url.searchParams.set("query_params", notebookParams.toString());
|
|
147
|
+
url.searchParams.set(KnownQueryParams.sessionId, sessionId);
|
|
148
|
+
return url;
|
|
151
149
|
}
|
|
152
150
|
|
|
153
151
|
/**
|
|
154
152
|
* The WebSocket URL of the runtime.
|
|
155
153
|
*/
|
|
156
154
|
public getWsURL(sessionId: SessionId): URL {
|
|
157
|
-
|
|
155
|
+
const url = this.getSessionURL("/ws", sessionId);
|
|
156
|
+
return asWsUrl(this.appendCrossOriginAuth(url).toString());
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
/**
|
|
@@ -164,11 +163,7 @@ export class RuntimeManager {
|
|
|
164
163
|
* (see `headers()`) instead of the URL.
|
|
165
164
|
*/
|
|
166
165
|
public getSseURL(sessionId: SessionId): URL {
|
|
167
|
-
const url = this.
|
|
168
|
-
path: "/sse",
|
|
169
|
-
searchParams: this.getSessionSearchParams(sessionId),
|
|
170
|
-
restrictToKnownQueryParams: false,
|
|
171
|
-
});
|
|
166
|
+
const url = this.getSessionURL("/sse", sessionId);
|
|
172
167
|
// The page URL can still carry access_token (merged in from the
|
|
173
168
|
// current page's params, before auth cleanup strips it); never
|
|
174
169
|
// forward it — a token in the URL leaks into proxy/server logs.
|
|
@@ -180,7 +175,8 @@ export class RuntimeManager {
|
|
|
180
175
|
* The WebSocket Sync URL of the runtime, for real-time updates.
|
|
181
176
|
*/
|
|
182
177
|
public getWsSyncURL(sessionId: SessionId): URL {
|
|
183
|
-
|
|
178
|
+
const url = this.getSessionURL("/ws_sync", sessionId);
|
|
179
|
+
return asWsUrl(this.appendCrossOriginAuth(url).toString());
|
|
184
180
|
}
|
|
185
181
|
|
|
186
182
|
/**
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { act, renderHook } from "@testing-library/react";
|
|
4
|
+
import { atom, Provider } from "jotai";
|
|
5
|
+
import type React from "react";
|
|
6
|
+
import { describe, expect, it, vi } from "vitest";
|
|
7
|
+
import { store, useJotaiEffect, waitFor } from "../jotai";
|
|
8
|
+
|
|
9
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
10
|
+
<Provider store={store}>{children}</Provider>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
describe("waitFor function", () => {
|
|
14
|
+
it("should resolve when the atom satisfies the predicate", async () => {
|
|
15
|
+
const testAtom = atom(0);
|
|
16
|
+
store.set(testAtom, 10);
|
|
17
|
+
|
|
18
|
+
const result = await waitFor(testAtom, (value) => value === 10);
|
|
19
|
+
expect(result).toBe(10);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should resolve when the atom changes to satisfy the predicate", async () => {
|
|
23
|
+
const testAtom = atom(0);
|
|
24
|
+
|
|
25
|
+
setTimeout(() => store.set(testAtom, 15), 5);
|
|
26
|
+
setTimeout(() => store.set(testAtom, 20), 10);
|
|
27
|
+
|
|
28
|
+
const result = await waitFor(testAtom, (value) => value === 20);
|
|
29
|
+
expect(result).toBe(20);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("useJotaiEffect", () => {
|
|
34
|
+
it("calls the effect with the new and previous values", () => {
|
|
35
|
+
const testAtom = atom(0);
|
|
36
|
+
const effect = vi.fn();
|
|
37
|
+
renderHook(() => useJotaiEffect(testAtom, effect), { wrapper });
|
|
38
|
+
|
|
39
|
+
act(() => store.set(testAtom, 1));
|
|
40
|
+
act(() => store.set(testAtom, 2));
|
|
41
|
+
|
|
42
|
+
expect(effect.mock.calls).toEqual([
|
|
43
|
+
[1, 0],
|
|
44
|
+
[2, 1],
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("calls only the latest callback after a rerender", () => {
|
|
49
|
+
const testAtom = atom(0);
|
|
50
|
+
const first = vi.fn();
|
|
51
|
+
const second = vi.fn();
|
|
52
|
+
const { rerender } = renderHook(
|
|
53
|
+
({ effect }) => useJotaiEffect(testAtom, effect),
|
|
54
|
+
{ initialProps: { effect: first }, wrapper },
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
rerender({ effect: second });
|
|
58
|
+
act(() => store.set(testAtom, 1));
|
|
59
|
+
|
|
60
|
+
expect(first).not.toHaveBeenCalled();
|
|
61
|
+
expect(second).toHaveBeenCalledTimes(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("subscribes once per rerender with an inline callback", () => {
|
|
65
|
+
const testAtom = atom(0);
|
|
66
|
+
const calls: number[] = [];
|
|
67
|
+
const { rerender } = renderHook(
|
|
68
|
+
() => useJotaiEffect(testAtom, (value) => calls.push(value)),
|
|
69
|
+
{ wrapper },
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
rerender();
|
|
73
|
+
rerender();
|
|
74
|
+
act(() => store.set(testAtom, 1));
|
|
75
|
+
|
|
76
|
+
expect(calls).toEqual([1]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("stops listening to the previous atom when the atom changes", () => {
|
|
80
|
+
const firstAtom = atom(0);
|
|
81
|
+
const secondAtom = atom(0);
|
|
82
|
+
const effect = vi.fn();
|
|
83
|
+
const { rerender } = renderHook(
|
|
84
|
+
({ target }) => useJotaiEffect(target, effect),
|
|
85
|
+
{ initialProps: { target: firstAtom }, wrapper },
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
rerender({ target: secondAtom });
|
|
89
|
+
act(() => store.set(firstAtom, 1));
|
|
90
|
+
expect(effect).not.toHaveBeenCalled();
|
|
91
|
+
|
|
92
|
+
act(() => store.set(secondAtom, 1));
|
|
93
|
+
expect(effect).toHaveBeenCalledTimes(1);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("unsubscribes on unmount", () => {
|
|
97
|
+
const testAtom = atom(0);
|
|
98
|
+
const effect = vi.fn();
|
|
99
|
+
const { unmount } = renderHook(() => useJotaiEffect(testAtom, effect), {
|
|
100
|
+
wrapper,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
unmount();
|
|
104
|
+
act(() => store.set(testAtom, 1));
|
|
105
|
+
|
|
106
|
+
expect(effect).not.toHaveBeenCalled();
|
|
107
|
+
});
|
|
108
|
+
});
|
package/src/core/state/jotai.ts
CHANGED
|
@@ -42,7 +42,7 @@ export function useJotaiEffect<T>(
|
|
|
42
42
|
const store = useStore();
|
|
43
43
|
useEffect(() => {
|
|
44
44
|
let prevValue = store.get(atom);
|
|
45
|
-
store.sub(atom, () => {
|
|
45
|
+
return store.sub(atom, () => {
|
|
46
46
|
const value = store.get(atom);
|
|
47
47
|
effect(value, prevValue);
|
|
48
48
|
prevValue = value;
|
package/src/core/static/files.ts
CHANGED
|
@@ -125,6 +125,8 @@ function withoutLeadingDot(path: string): string {
|
|
|
125
125
|
/**
|
|
126
126
|
* Resolve a URL to a blob URL if it's a virtual file, for use with dynamic import().
|
|
127
127
|
* Unlike fetch, import() can't be patched, so we need to convert data URLs to blob URLs.
|
|
128
|
+
* The caller owns a returned URL that differs from the input and must revoke it
|
|
129
|
+
* once no module consumers or their cleanup callbacks need it.
|
|
128
130
|
*
|
|
129
131
|
* @returns The original URL if not a virtual file, or a blob URL if it is
|
|
130
132
|
*/
|
package/src/core/wasm/bridge.ts
CHANGED
|
@@ -38,8 +38,6 @@ import type {
|
|
|
38
38
|
} from "../network/types";
|
|
39
39
|
import { filenameAtom } from "../saving/file-state";
|
|
40
40
|
import { store } from "../state/jotai";
|
|
41
|
-
import { BasicTransport } from "../websocket/transports/basic";
|
|
42
|
-
import type { IConnectionTransport } from "../websocket/transports/transport";
|
|
43
41
|
import { PyodideRouter } from "./router";
|
|
44
42
|
import { getWorkerRPC } from "./rpc";
|
|
45
43
|
import { getWasmRuntimeConfig } from "./runtime-config";
|
|
@@ -409,7 +407,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
409
407
|
return response as Snippets;
|
|
410
408
|
};
|
|
411
409
|
|
|
412
|
-
public openFile: EditRequests["openFile"] = async (
|
|
410
|
+
public openFile: EditRequests["openFile"] = async () => {
|
|
413
411
|
const url = createShareableLink({
|
|
414
412
|
code: null,
|
|
415
413
|
baseUrl: window.location.origin,
|
|
@@ -453,7 +451,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
453
451
|
return null;
|
|
454
452
|
};
|
|
455
453
|
|
|
456
|
-
public sendInstantiate: RunRequests["sendInstantiate"] = async (
|
|
454
|
+
public sendInstantiate: RunRequests["sendInstantiate"] = async () => {
|
|
457
455
|
return null;
|
|
458
456
|
};
|
|
459
457
|
|
|
@@ -719,12 +717,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
|
|
|
719
717
|
}
|
|
720
718
|
}
|
|
721
719
|
|
|
722
|
-
export function createPyodideConnection(): IConnectionTransport {
|
|
723
|
-
return BasicTransport.withProducerCallback((callback) => {
|
|
724
|
-
PyodideBridge.INSTANCE.attachMessageConsumer(callback);
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
|
|
728
720
|
// Compose the worker name. The optional "::controller" suffix tells
|
|
729
721
|
// getController.ts that the host page provides a custom /wasm/controller.js
|
|
730
722
|
// and that the dynamic import should be attempted. Hosts opt in by setting
|
package/src/core/wasm/store.ts
CHANGED
|
@@ -41,7 +41,7 @@ const urlFileStore: FileStore = {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const domElementFileStore: FileStore = {
|
|
44
|
-
saveFile(
|
|
44
|
+
saveFile(_contents: string) {
|
|
45
45
|
// Do nothing
|
|
46
46
|
},
|
|
47
47
|
readFile() {
|
|
@@ -54,7 +54,7 @@ export const domElementFileStore: FileStore = {
|
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
const remoteDefaultFileStore: FileStore = {
|
|
57
|
-
saveFile(
|
|
57
|
+
saveFile(_contents: string) {
|
|
58
58
|
// Do nothing
|
|
59
59
|
},
|
|
60
60
|
readFile() {
|
|
@@ -79,7 +79,7 @@ export const mountConfigFileStore: FileStore = {
|
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
const emptyFileStore: FileStore = {
|
|
82
|
-
saveFile(
|
|
82
|
+
saveFile(_contents: string) {
|
|
83
83
|
// Do nothing
|
|
84
84
|
},
|
|
85
85
|
readFile() {
|
package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts}
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import { Logger } from "@/utils/Logger";
|
|
5
5
|
import { WebSocketClosedReason, ConnectionState } from "../types";
|
|
6
|
-
import { classifyCloseEvent } from "../
|
|
6
|
+
import { classifyCloseEvent } from "../connection-state";
|
|
7
7
|
|
|
8
8
|
function classify(reason: string | undefined) {
|
|
9
9
|
return classifyCloseEvent({ reason });
|
|
@@ -13,8 +13,10 @@ describe("classifyCloseEvent", () => {
|
|
|
13
13
|
describe("transient closes (default branch)", () => {
|
|
14
14
|
it("retries on empty/undefined reason", () => {
|
|
15
15
|
const decision = classify(undefined);
|
|
16
|
-
expect(decision
|
|
17
|
-
|
|
16
|
+
expect(decision).toEqual({
|
|
17
|
+
kind: "retry",
|
|
18
|
+
status: { state: ConnectionState.CONNECTING },
|
|
19
|
+
});
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
it("treats unknown reason strings as transient and logs a warning", () => {
|
|
@@ -40,41 +42,25 @@ describe("classifyCloseEvent", () => {
|
|
|
40
42
|
// terminal or a rejected client would reconnect forever.
|
|
41
43
|
"MARIMO_UNAUTHORIZED",
|
|
42
44
|
"MARIMO_KIOSK_NOT_ALLOWED",
|
|
43
|
-
])("%s → terminal with KERNEL_DISCONNECTED
|
|
45
|
+
])("%s → terminal with KERNEL_DISCONNECTED", (reason) => {
|
|
44
46
|
const decision = classify(reason);
|
|
45
|
-
expect(decision.kind).toBe("terminal");
|
|
46
|
-
expect(decision.status).toMatchObject({
|
|
47
|
-
state: ConnectionState.CLOSED,
|
|
48
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
49
|
-
});
|
|
50
47
|
expect(decision).toMatchObject({
|
|
51
48
|
kind: "terminal",
|
|
52
|
-
|
|
49
|
+
status: {
|
|
50
|
+
state: ConnectionState.CLOSED,
|
|
51
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
52
|
+
},
|
|
53
53
|
});
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
it("MARIMO_KERNEL_STARTUP_ERROR → terminal
|
|
56
|
+
it("MARIMO_KERNEL_STARTUP_ERROR → terminal", () => {
|
|
57
57
|
const decision = classify("MARIMO_KERNEL_STARTUP_ERROR");
|
|
58
|
-
expect(decision.kind).toBe("terminal");
|
|
59
|
-
expect(decision.status).toMatchObject({
|
|
60
|
-
state: ConnectionState.CLOSED,
|
|
61
|
-
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
62
|
-
});
|
|
63
58
|
expect(decision).toMatchObject({
|
|
64
59
|
kind: "terminal",
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
describe("transport exhaustion", () => {
|
|
71
|
-
it("MARIMO_TRANSPORT_EXHAUSTED → gave-up with KERNEL_DISCONNECTED", () => {
|
|
72
|
-
const decision = classify("MARIMO_TRANSPORT_EXHAUSTED");
|
|
73
|
-
expect(decision.kind).toBe("gave-up");
|
|
74
|
-
expect(decision.status).toEqual({
|
|
75
|
-
state: ConnectionState.CLOSED,
|
|
76
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
77
|
-
reason: "kernel not found",
|
|
60
|
+
status: {
|
|
61
|
+
state: ConnectionState.CLOSED,
|
|
62
|
+
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
63
|
+
},
|
|
78
64
|
});
|
|
79
65
|
});
|
|
80
66
|
});
|