@marimo-team/islands 0.25.3-dev21 → 0.25.3-dev211

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.
Files changed (717) hide show
  1. package/dist/{ConnectedDataExplorerComponent-DfG3PRaJ.js → ConnectedDataExplorerComponent-D6RHJV8D.js} +120 -116
  2. package/dist/{ErrorBoundary-ttSr7_91.js → ErrorBoundary-BpGAot_X.js} +16 -16
  3. package/dist/{abnfDiagram-VCTEODGH-B3w-XWX8.js → abnfDiagram-VCTEODGH-0q7Lbmii.js} +2 -2
  4. package/dist/any-language-editor-jGaR0EAo.js +75 -0
  5. package/dist/{architectureDiagram-5GKGNRK7-C18U9A6k.js → architectureDiagram-5GKGNRK7-1PydKPmE.js} +1 -1
  6. package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
  7. package/dist/assets/__vite-browser-external-CBRgnYY0.js +1 -0
  8. package/dist/assets/worker-DiPNP__U.js +113 -0
  9. package/dist/{button-CvjkwdSk.js → button-B6RjDKJx.js} +227 -217
  10. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CkVzWJEX.js} +2 -2
  11. package/dist/{chat-ui-w8SVynkn.js → chat-ui-B5pH_aXk.js} +1277 -1275
  12. package/dist/{check-BMKBBrdc.js → check-Z_vtI3OL.js} +1 -1
  13. package/dist/{chunk-IMKFNOWR-CrS5bzqW.js → chunk-IMKFNOWR-DEzZZ1Zc.js} +1 -1
  14. package/dist/{chunk-SHT3W25Y-StpvPvUG.js → chunk-SHT3W25Y-CuHj-hnn.js} +1 -1
  15. package/dist/{chunk-SVP7TREG-CBXjbYZC.js → chunk-SVP7TREG-BPiZK2bA.js} +1 -1
  16. package/dist/{chunk-TICWLB2K-Dp6bIb-q.js → chunk-TICWLB2K-DF6XcIjM.js} +1 -1
  17. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  18. package/dist/{classDiagram-ZZMXUADV-BFYuxV5g.js → classDiagram-ZZMXUADV-CMdR-cP4.js} +2 -2
  19. package/dist/{classDiagram-v2-VYDZK3BY-D_tjXVMl.js → classDiagram-v2-VYDZK3BY-DRvc3_7Y.js} +2 -2
  20. package/dist/code-visibility-B5trOyTh.js +134 -0
  21. package/dist/{common-CeebhhhO.js → common-BiM3Xm_d.js} +9837 -9658
  22. package/dist/config-DbjzjwxX.js +636 -0
  23. package/dist/{copy-icon-BgUO8jsi.js → copy-icon-CG57cxwb.js} +3 -3
  24. package/dist/createReducer-DePYJ0F3.js +63 -0
  25. package/dist/{cynefinDiagram-5FMLGOSQ-DSgYrHB2.js → cynefinDiagram-5FMLGOSQ-BkBjEY9l.js} +1 -1
  26. package/dist/{dagre-GXQ25YYZ-GYlruCBf.js → dagre-GXQ25YYZ-D-HEaW4I.js} +1 -1
  27. package/dist/{data-grid-overlay-editor-vxQ4E6k1.js → data-grid-overlay-editor-GxGkM-Al.js} +5 -5
  28. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  29. package/dist/{diagram-S7CK7UJ4-DRu5LX5_.js → diagram-S7CK7UJ4-Bn-oF-rB.js} +1 -1
  30. package/dist/{diagram-UQ7AKVKN-DD7uiejP.js → diagram-UQ7AKVKN-BpzzXWBj.js} +1 -1
  31. package/dist/{diagram-VX7I27RA-ByH9KAJJ.js → diagram-VX7I27RA-COOtvfBP.js} +1 -1
  32. package/dist/{diagram-Z3DM3KII-BsQHPRke.js → diagram-Z3DM3KII-K5cXvbrl.js} +1 -1
  33. package/dist/{dialog-Cc479ZEH.js → dialog-DsZ49mmU.js} +26 -26
  34. package/dist/{dist-Bvs24R_E.js → dist-11T5wq3_.js} +31 -30
  35. package/dist/{dist-F8Ep36rk.js → dist-17ugwGZc.js} +59 -58
  36. package/dist/{dist-BMQf5zIS.js → dist-7cRjf--y.js} +123 -122
  37. package/dist/{dist-diIx5qJW.js → dist-B8pkfkzc.js} +31 -30
  38. package/dist/{dist-CN_BeG2I.js → dist-B9UoM_wq.js} +58 -57
  39. package/dist/{dist-CLdpGQVr.js → dist-BGuMTs1i.js} +118 -117
  40. package/dist/{dist-BK4Oj99o.js → dist-BHW11fni.js} +18 -17
  41. package/dist/dist-BLY4m1Wi.js +850 -0
  42. package/dist/{dist-PXYI_yuP.js → dist-BNlcVoxs.js} +24 -23
  43. package/dist/{dist-D6d86eNJ.js → dist-BQYe5Bju.js} +47 -46
  44. package/dist/{dist-CkTTIdBe.js → dist-BX1mn8na.js} +337 -337
  45. package/dist/{dist-DiDibOYr.js → dist-Bh0PTKUW.js} +151 -150
  46. package/dist/{dist-CSJ0MDRw.js → dist-CKaXK92p.js} +56 -55
  47. package/dist/{dist-C8fAKSH1.js → dist-CLhwfhpJ.js} +53 -52
  48. package/dist/{dist-DoE4XJBC.js → dist-CYeqK4Xw.js} +9801 -10649
  49. package/dist/{dist-BLfKmR-l.js → dist-Cxlp3WH6.js} +16 -15
  50. package/dist/{dist-D-wwqlzJ.js → dist-DSJPGj42.js} +158 -157
  51. package/dist/{dist-BorMD-uX.js → dist-DU9ICsWZ.js} +75 -74
  52. package/dist/{dist-DBtSl3sf.js → dist-DWv0ALBi.js} +47 -46
  53. package/dist/{dist-OR1OnN-y.js → dist-DiBpWEsB.js} +31 -30
  54. package/dist/{dist-CrSP_H1M.js → dist-DiLFTlnl.js} +242 -242
  55. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  56. package/dist/{dist-CSbh1PNP.js → dist-cVDV5IuI.js} +23 -22
  57. package/dist/{dist-BuaRHxOc.js → dist-fRfaOoq8.js} +44 -43
  58. package/dist/{dist-Cg7gzw-a.js → dist-gTTI-9Px.js} +78 -77
  59. package/dist/dropdown-menu-CSNdPSnS.js +6083 -0
  60. package/dist/{ebnfDiagram-PWID7BFC-CQRK5_eT.js → ebnfDiagram-PWID7BFC-BI1ZmjVm.js} +2 -2
  61. package/dist/{erDiagram-RLTQ6QDP-BKtWrDVh.js → erDiagram-RLTQ6QDP-BtWjj9xy.js} +1 -1
  62. package/dist/{error-banner-CFPHFw4h.js → error-banner-IsonnvA0.js} +84 -83
  63. package/dist/error-entries-CRPfxMqm.js +2505 -0
  64. package/dist/{esm-D2gTsXEV.js → esm-BgKjMvWw.js} +530 -529
  65. package/dist/{esm-AMFssoNp.js → esm-CHjVSexr.js} +328 -329
  66. package/dist/feedback-button-CAxVqhvl.js +374 -0
  67. package/dist/{flowDiagram-HODETNUW-1IN-ih2E.js → flowDiagram-HODETNUW-DQvZh96A.js} +2 -2
  68. package/dist/{formats-X4mMQWzX.js → formats-BK4VefeF.js} +6 -6
  69. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  70. package/dist/{glide-data-editor-CSYHMRDu.js → glide-data-editor-CBX2wLtn.js} +417 -415
  71. package/dist/{glide-utils-DM9zBO4W.js → glide-utils-CQddGpa-.js} +16 -16
  72. package/dist/{globals-Fpiwkv4D.js → globals-DuCA4LSq.js} +3 -3
  73. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  74. package/dist/{error-entries-Damuuclv.js → html-to-image-CgAnxFi8.js} +26911 -26769
  75. package/dist/{infoDiagram-27XIBGKW-CkB-zr4p.js → infoDiagram-27XIBGKW-BdAObnc_.js} +1 -1
  76. package/dist/{ishikawaDiagram-5VMMS53U-wlyLjBmM.js → ishikawaDiagram-5VMMS53U-DP-jE8dw.js} +1 -1
  77. package/dist/{kanban-definition-UXKFOSKX-C2usY0i-.js → kanban-definition-UXKFOSKX-BkMgPjfm.js} +1 -1
  78. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  79. package/dist/{loader-BQOfjTIJ.js → loader-BisjOLiW.js} +12 -12
  80. package/dist/main.js +10128 -8127
  81. package/dist/{mermaid-BA-Z6wGL.js → mermaid-B-OFqheA.js} +52 -52
  82. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  83. package/dist/{mindmap-definition-YA3MSWOX-nKOWS8RR.js → mindmap-definition-YA3MSWOX-Du7toAZX.js} +1 -1
  84. package/dist/{number-overlay-editor-BOjqsq7D.js → number-overlay-editor-KvS7Rgw9.js} +3 -3
  85. package/dist/{dist-CN8zI-XC.js → objectWithoutPropertiesLoose-ai5NUqGa.js} +262 -240
  86. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  87. package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
  88. package/dist/{pegDiagram-XKGWAZYB-Dac9EIKD.js → pegDiagram-XKGWAZYB-CX_729j0.js} +2 -2
  89. package/dist/{pieDiagram-E7YTZNPT-B7S-DsW_.js → pieDiagram-E7YTZNPT-dtTFJcVI.js} +1 -1
  90. package/dist/precisionRound-DhAzeRcm.js +49 -0
  91. package/dist/{process-output-CTPTtxXB.js → process-output-Bmev5azU.js} +4 -4
  92. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  93. package/dist/{railroadDiagram-O6MQD6OU-Cfa5Q-hr.js → railroadDiagram-O6MQD6OU-Dsc2Cf4c.js} +2 -2
  94. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  95. package/dist/{requirementDiagram-BXWQKSXE-d8zXCJIk.js → requirementDiagram-BXWQKSXE-D3g0c60I.js} +1 -1
  96. package/dist/{reveal-component-Brpo7CP8.js → reveal-component-CqBvRKJz.js} +426 -403
  97. package/dist/schemas-CdscWNy_.js +4747 -0
  98. package/dist/select-BSxlITBo.js +1200 -0
  99. package/dist/{sequenceDiagram-WJ2MYXX4-b6pei3lJ.js → sequenceDiagram-WJ2MYXX4-w1pWbIpk.js} +1 -1
  100. package/dist/{spec-BJzgmvVa.js → spec-Dq8RNplp.js} +41 -11
  101. package/dist/{stateDiagram-D77RDMKH-Be-xSpaZ.js → stateDiagram-D77RDMKH-BCv7kP4H.js} +2 -2
  102. package/dist/{stateDiagram-v2-MP3YSRHH-5Y-FxesJ.js → stateDiagram-v2-MP3YSRHH-D1cTOt0x.js} +2 -2
  103. package/dist/static-state-BldGd99T.js +72 -0
  104. package/dist/strings-BGW-fXVJ.js +507 -0
  105. package/dist/style.css +1 -1
  106. package/dist/{swimlanes-42K2YHIH-nRRl4NU0.js → swimlanes-42K2YHIH-DNO6jDnd.js} +1 -1
  107. package/dist/{swimlanesDiagram-VR7AAH4N-BS79510V.js → swimlanesDiagram-VR7AAH4N-CkSWsxYJ.js} +2 -2
  108. package/dist/{swiper-component-DKntyn8p.js → swiper-component-Dir1o8ml.js} +2 -2
  109. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  110. package/dist/{timeline-definition-24CTP7MA-Cfzf8WPf.js → timeline-definition-24CTP7MA-DQvqGFM9.js} +1 -1
  111. package/dist/toast-BWIPi3aF.js +491 -0
  112. package/dist/{tooltip-CtBZ5q8p.js → tooltip-C3UnvsRe.js} +329 -305
  113. package/dist/use-restore-focus-BWO0z1lo.js +1672 -0
  114. package/dist/{useAsyncData-BD534XmW.js → useAsyncData-DsZMvNXn.js} +15 -14
  115. package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-ChB4eyim.js} +2 -2
  116. package/dist/{useDeepCompareMemoize-C72_RNsu.js → useDeepCompareMemoize-KMBBux8C.js} +1 -1
  117. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-cMNQ80CK.js} +1 -1
  118. package/dist/useLifecycle-BquH9ET-.js +112 -0
  119. package/dist/useTheme-B9C1JIy9.js +307 -0
  120. package/dist/utils-DXkj82sK.js +813 -0
  121. package/dist/{vega-component-DfcYgj-Y.js → vega-component-9NOEITbg.js} +170 -169
  122. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  123. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  124. package/dist/{vennDiagram-4TSXK5OY-CeY6Z1xZ.js → vennDiagram-4TSXK5OY-BfzXp4SH.js} +1 -1
  125. package/dist/{wardleyDiagram-VM6X3IG4-Cxs9NtVi.js → wardleyDiagram-VM6X3IG4-CiqEE8eq.js} +1 -1
  126. package/dist/{xychartDiagram-S5SC5T6Z-DNWbvPK7.js → xychartDiagram-S5SC5T6Z-BTIHCVOI.js} +2 -2
  127. package/package.json +16 -20
  128. package/src/__mocks__/document.tsx +63 -0
  129. package/src/__mocks__/notebook.ts +3 -4
  130. package/src/__mocks__/partial.ts +26 -0
  131. package/src/__mocks__/requests.ts +1 -4
  132. package/src/__tests__/main.test.tsx +24 -1
  133. package/src/__tests__/module-entry.test.ts +44 -0
  134. package/src/__tests__/mount.test.ts +1 -21
  135. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  136. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  137. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  138. package/src/components/app-config/ai-config.tsx +7 -2
  139. package/src/components/app-config/app-config-form.tsx +5 -9
  140. package/src/components/app-config/user-config-form.tsx +35 -56
  141. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  142. package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
  143. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  144. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  145. package/src/components/chat/acp/blocks.tsx +3 -2
  146. package/src/components/chat/acp/session-tabs.tsx +8 -3
  147. package/src/components/chat/chat-components.tsx +2 -0
  148. package/src/components/chat/chat-panel.tsx +20 -101
  149. package/src/components/chat/chat-utils.ts +4 -8
  150. package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
  151. package/src/components/chat/notebook-access-selector.tsx +100 -0
  152. package/src/components/data-table/TableBottomBar.tsx +4 -1
  153. package/src/components/data-table/TableTopBar.tsx +2 -0
  154. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  155. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  156. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  157. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  158. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  159. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  160. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  161. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  162. package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
  163. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  164. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  165. package/src/components/data-table/cell-selection/feature.ts +2 -2
  166. package/src/components/data-table/cell-selection/types.ts +2 -2
  167. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  168. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  169. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  170. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  171. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  172. package/src/components/data-table/charts/charts.tsx +40 -30
  173. package/src/components/data-table/charts/storage.ts +16 -5
  174. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  175. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  176. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  177. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  178. package/src/components/data-table/columns.tsx +45 -46
  179. package/src/components/data-table/context-menu.tsx +36 -20
  180. package/src/components/data-table/data-table.tsx +17 -1
  181. package/src/components/data-table/date-popover.tsx +6 -4
  182. package/src/components/data-table/export-actions.tsx +76 -48
  183. package/src/components/data-table/pagination.tsx +44 -33
  184. package/src/components/data-table/range-focus/atoms.ts +4 -6
  185. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  186. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  187. package/src/components/data-table/renderers.tsx +16 -7
  188. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  189. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  190. package/src/components/data-table/search-highlight.tsx +79 -0
  191. package/src/components/data-table/types.ts +1 -0
  192. package/src/components/data-table/url-detector.tsx +49 -9
  193. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  194. package/src/components/datasources/__tests__/column-preview.test.tsx +96 -5
  195. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  196. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  197. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  198. package/src/components/datasources/column-preview.tsx +17 -12
  199. package/src/components/datasources/datasources.tsx +56 -43
  200. package/src/components/datasources/utils.ts +32 -23
  201. package/src/components/debugger/debugger-code.tsx +5 -0
  202. package/src/components/dependency-graph/custom-node.tsx +1 -1
  203. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  204. package/src/components/dependency-graph/elements.ts +24 -21
  205. package/src/components/dependency-graph/minimap-content.tsx +13 -19
  206. package/src/components/dependency-graph/panels.tsx +4 -2
  207. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  208. package/src/components/editor/SortableCell.tsx +1 -3
  209. package/src/components/editor/__tests__/Output.test.tsx +50 -32
  210. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  211. package/src/components/editor/__tests__/data-attributes.test.tsx +28 -14
  212. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  213. package/src/components/editor/__tests__/output-persistence.test.tsx +6 -2
  214. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  215. package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
  216. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +34 -8
  217. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +2 -6
  218. package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +113 -0
  219. package/src/components/editor/actions/name-cell-input.tsx +4 -3
  220. package/src/components/editor/actions/pair-with-agent-commands.ts +2 -2
  221. package/src/components/editor/actions/pair-with-agent-modal.tsx +19 -16
  222. package/src/components/editor/actions/useCellActionButton.tsx +36 -31
  223. package/src/components/editor/actions/useConfigActions.tsx +3 -4
  224. package/src/components/editor/actions/useNotebookActions.tsx +19 -23
  225. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  226. package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
  227. package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
  228. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  229. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  230. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  231. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  232. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  233. package/src/components/editor/alerts/stdin-blocking-alert.tsx +1 -1
  234. package/src/components/editor/app-container.tsx +1 -1
  235. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  236. package/src/components/editor/cell/CreateCellButton.tsx +15 -21
  237. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  238. package/src/components/editor/cell/RunButton.tsx +2 -2
  239. package/src/components/editor/cell/StagedAICell.tsx +10 -2
  240. package/src/components/editor/cell/StopButton.tsx +2 -2
  241. package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +4 -2
  242. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  243. package/src/components/editor/cell/cell-actions.tsx +12 -1
  244. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  245. package/src/components/editor/cell/code/cell-editor.tsx +46 -165
  246. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  247. package/src/components/editor/cell/collapse.tsx +11 -4
  248. package/src/components/editor/cell/useAddCell.ts +4 -8
  249. package/src/components/editor/cell/useDeleteCell.tsx +10 -36
  250. package/src/components/editor/cell/useRunCells.ts +2 -5
  251. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  252. package/src/components/editor/cell/useSplitCell.tsx +10 -6
  253. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  254. package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
  255. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  256. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  257. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  258. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  259. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
  260. package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
  261. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  262. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  263. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  264. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  265. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  266. package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
  267. package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
  268. package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
  269. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +6 -9
  270. package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
  271. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +62 -3
  272. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  273. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  274. package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
  275. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  276. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  277. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  278. package/src/components/editor/chrome/wrapper/footer.tsx +2 -2
  279. package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
  280. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  281. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  282. package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
  283. package/src/components/editor/columns/cell-column.tsx +1 -1
  284. package/src/components/editor/columns/sortable-column.tsx +2 -2
  285. package/src/components/editor/connections/components.tsx +5 -10
  286. package/src/components/editor/controls/Controls.tsx +4 -4
  287. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  288. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  289. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +10 -4
  290. package/src/components/editor/controls/command-palette.tsx +22 -10
  291. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  292. package/src/components/editor/documentation.css +34 -11
  293. package/src/components/editor/dynamic-favicon.tsx +21 -40
  294. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +25 -20
  295. package/src/components/editor/errors/auto-fix.tsx +4 -8
  296. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  297. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  298. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  299. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  300. package/src/components/editor/file-tree/file-explorer.tsx +48 -15
  301. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  302. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  303. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  304. package/src/components/editor/header/__tests__/filename-form.test.tsx +1 -4
  305. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  306. package/src/components/editor/header/app-header.tsx +1 -1
  307. package/src/components/editor/header/filename-form.tsx +1 -1
  308. package/src/components/editor/header/status.tsx +40 -20
  309. package/src/components/editor/links/__tests__/cell-link.test.tsx +148 -0
  310. package/src/components/editor/links/cell-link-list.tsx +1 -1
  311. package/src/components/editor/links/cell-link.tsx +17 -7
  312. package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
  313. package/src/components/editor/navigation/__tests__/navigation.test.ts +108 -85
  314. package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
  315. package/src/components/editor/navigation/clipboard.ts +17 -14
  316. package/src/components/editor/navigation/focus-utils.ts +23 -4
  317. package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
  318. package/src/components/editor/navigation/navigation.ts +71 -70
  319. package/src/components/editor/navigation/selection.ts +30 -29
  320. package/src/components/editor/notebook-banner.tsx +1 -0
  321. package/src/components/editor/notebook-cell.tsx +29 -32
  322. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  323. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  324. package/src/components/editor/output/Outputs.css +8 -0
  325. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  326. package/src/components/editor/output/ansi-reduce.ts +33 -20
  327. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  328. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
  329. package/src/components/editor/package-alert.tsx +14 -7
  330. package/src/components/editor/renderers/cell-array.tsx +22 -33
  331. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  332. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -1
  333. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
  334. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
  335. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  336. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
  337. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
  338. package/src/components/editor/stdin-blocking-alert.tsx +1 -1
  339. package/src/components/home/components.tsx +17 -31
  340. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  341. package/src/components/icons/large-spinner.tsx +3 -14
  342. package/src/components/icons/spinner.tsx +1 -1
  343. package/src/components/markdown/markdown-renderer.tsx +4 -8
  344. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  345. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  346. package/src/components/pages/edit-page.tsx +19 -17
  347. package/src/components/pages/home-page.tsx +164 -91
  348. package/src/components/scratchpad/scratchpad.test.tsx +89 -0
  349. package/src/components/scratchpad/scratchpad.tsx +43 -32
  350. package/src/components/scratchpad/state.ts +7 -0
  351. package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
  352. package/src/components/slides/__tests__/minimap.test.ts +38 -19
  353. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
  354. package/src/components/slides/minimap.tsx +17 -12
  355. package/src/components/slides/reveal-component.tsx +58 -26
  356. package/src/components/slides/reveal-slides.css +5 -4
  357. package/src/components/slides/slide-cell-view.tsx +4 -5
  358. package/src/components/slides/slide-form.tsx +1 -0
  359. package/src/components/slides/slide-scroll-hint.tsx +3 -1
  360. package/src/components/sort/SortableCellsProvider.tsx +8 -25
  361. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  362. package/src/components/tracing/tracing.tsx +46 -42
  363. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  364. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  365. package/src/components/ui/alert-dialog.tsx +1 -1
  366. package/src/components/ui/draggable-popover.tsx +24 -2
  367. package/src/components/ui/range-slider.tsx +22 -9
  368. package/src/core/MarimoApp.tsx +1 -1
  369. package/src/core/ai/__tests__/staged-cells.test.ts +32 -33
  370. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
  371. package/src/core/ai/context/providers/cell-output.ts +2 -2
  372. package/src/core/ai/context/providers/datasource.ts +6 -2
  373. package/src/core/ai/staged-cells.ts +18 -19
  374. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +40 -88
  375. package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
  376. package/src/core/ai/tools/base.ts +18 -15
  377. package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
  378. package/src/core/ai/tools/registry.ts +13 -10
  379. package/src/core/ai/tools/sample-tool.ts +6 -7
  380. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -37
  381. package/src/core/cells/__tests__/actions.test.ts +624 -35
  382. package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
  383. package/src/core/cells/__tests__/arrange.test.ts +432 -0
  384. package/src/core/cells/__tests__/cell.test.ts +39 -0
  385. package/src/core/cells/__tests__/cells.test.ts +251 -2540
  386. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  387. package/src/core/cells/__tests__/document.test.ts +164 -0
  388. package/src/core/cells/__tests__/editor.test.ts +57 -0
  389. package/src/core/cells/__tests__/flush-document.test.ts +40 -0
  390. package/src/core/cells/__tests__/harness.ts +106 -0
  391. package/src/core/cells/__tests__/layout.test.ts +177 -0
  392. package/src/core/cells/__tests__/notebook-outline.test.ts +122 -0
  393. package/src/core/cells/__tests__/outputs.test.tsx +71 -53
  394. package/src/core/cells/__tests__/session.test.ts +445 -211
  395. package/src/core/cells/__tests__/utils.test.ts +9 -108
  396. package/src/core/cells/actions.ts +675 -6
  397. package/src/core/cells/add-missing-import.ts +47 -43
  398. package/src/core/cells/arrange.ts +529 -0
  399. package/src/core/cells/cell.ts +14 -3
  400. package/src/core/cells/cells.ts +126 -1363
  401. package/src/core/cells/columns.ts +38 -0
  402. package/src/core/cells/document.ts +178 -0
  403. package/src/core/cells/edit.ts +30 -0
  404. package/src/core/cells/editor.ts +82 -0
  405. package/src/core/cells/layout.ts +221 -0
  406. package/src/core/cells/outputs.ts +12 -28
  407. package/src/core/cells/pending-delete-service.ts +3 -7
  408. package/src/core/cells/session.ts +76 -53
  409. package/src/core/cells/types.ts +22 -6
  410. package/src/core/cells/utils.ts +10 -8
  411. package/src/core/codemirror/__tests__/format.test.ts +0 -34
  412. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  413. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  414. package/src/core/codemirror/ai/resources.ts +1 -1
  415. package/src/core/codemirror/cells/__tests__/extensions.test.ts +2 -6
  416. package/src/core/codemirror/cells/extensions.ts +30 -28
  417. package/src/core/codemirror/cells/state.ts +1 -6
  418. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
  419. package/src/core/codemirror/copilot/getCodes.ts +2 -2
  420. package/src/core/codemirror/format.ts +6 -23
  421. package/src/core/codemirror/keymaps/vim.ts +4 -8
  422. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  423. package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
  424. package/src/core/codemirror/language/cell-code.ts +114 -0
  425. package/src/core/codemirror/language/extension.ts +52 -35
  426. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  427. package/src/core/codemirror/language/languages/python.ts +16 -10
  428. package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
  429. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  430. package/src/core/codemirror/language/types.ts +7 -7
  431. package/src/core/codemirror/language/utils.ts +9 -39
  432. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
  433. package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
  434. package/src/core/codemirror/lsp/utils.ts +1 -1
  435. package/src/core/codemirror/misc/__tests__/paste.test.ts +3 -1
  436. package/src/core/codemirror/misc/paste.ts +1 -1
  437. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  438. package/src/core/codemirror/readonly/extension.ts +2 -2
  439. package/src/core/codemirror/utils.ts +1 -0
  440. package/src/core/config/__tests__/app-config.test.ts +64 -0
  441. package/src/core/config/__tests__/config-schema.test.ts +13 -6
  442. package/src/core/config/config-schema.ts +13 -4
  443. package/src/core/config/config.ts +26 -12
  444. package/src/core/config/feature-flag.tsx +0 -2
  445. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  446. package/src/core/datasets/data-source-discovery.ts +4 -6
  447. package/src/core/documentation/doc-lookup.ts +1 -1
  448. package/src/core/edit-app.tsx +21 -28
  449. package/src/core/errors/error-entries.ts +4 -1
  450. package/src/core/export/hooks.ts +1 -1
  451. package/src/core/export/layout.ts +2 -2
  452. package/src/core/hotkeys/actions.ts +2 -4
  453. package/src/core/islands/__tests__/bootstrap.test.ts +69 -17
  454. package/src/core/islands/__tests__/bridge.test.ts +72 -25
  455. package/src/core/islands/bootstrap.ts +46 -53
  456. package/src/core/islands/bridge.ts +75 -24
  457. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  458. package/src/core/islands/components/web-components.tsx +1 -1
  459. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  460. package/src/core/islands/worker/controller.ts +4 -10
  461. package/src/core/islands/worker/worker.tsx +33 -33
  462. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  463. package/src/core/kernel/__tests__/handlers.test.ts +7 -153
  464. package/src/core/kernel/handlers.ts +19 -72
  465. package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
  466. package/src/core/meta/code-visibility.ts +18 -9
  467. package/src/core/network/__tests__/connection.test.ts +1 -1
  468. package/src/core/network/__tests__/requests-lazy.test.ts +1 -3
  469. package/src/core/network/connection-notice.ts +1 -1
  470. package/src/core/network/connection.ts +1 -1
  471. package/src/core/network/requests-lazy.ts +2 -5
  472. package/src/core/network/requests-network.ts +5 -31
  473. package/src/core/network/requests-static.ts +1 -4
  474. package/src/core/network/requests-toasting.tsx +1 -4
  475. package/src/core/network/types.ts +6 -14
  476. package/src/core/network/useConnectionNotice.ts +8 -2
  477. package/src/core/notebook/__tests__/operations.test.ts +51 -0
  478. package/src/core/notebook/attachments.ts +38 -0
  479. package/src/core/notebook/document/__tests__/codemirror.test.ts +758 -0
  480. package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
  481. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  482. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  483. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  484. package/src/core/notebook/document/__tests__/model.test.ts +247 -0
  485. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  486. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  487. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  488. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  489. package/src/core/notebook/document/__tests__/state.test.ts +459 -0
  490. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  491. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  492. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  493. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  494. package/src/core/notebook/document/__tests__/user.ts +61 -0
  495. package/src/core/notebook/document/codemirror.ts +216 -0
  496. package/src/core/notebook/document/draft.ts +502 -0
  497. package/src/core/notebook/document/hooks.tsx +118 -0
  498. package/src/core/notebook/document/index.ts +24 -0
  499. package/src/core/notebook/document/model.ts +102 -0
  500. package/src/core/notebook/document/select.ts +41 -0
  501. package/src/core/notebook/document/state.ts +378 -0
  502. package/src/core/notebook/document/sync.ts +369 -0
  503. package/src/core/notebook/index.ts +19 -0
  504. package/src/core/notebook/operations.ts +30 -0
  505. package/src/core/notebook/replica/AGENTS.md +11 -0
  506. package/src/core/{host → notebook/replica}/__tests__/attachments.test.ts +9 -10
  507. package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
  508. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  509. package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
  510. package/src/core/notebook/replica/backend.ts +19 -0
  511. package/src/core/notebook/replica/connection.ts +42 -0
  512. package/src/core/notebook/replica/index.ts +13 -0
  513. package/src/core/notebook/replica/replica.ts +286 -0
  514. package/src/core/{host → notebook/replica}/resources/attachments.ts +6 -3
  515. package/src/core/{host → notebook/replica}/resources/document.ts +4 -4
  516. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  517. package/src/core/packages/useSandboxController.ts +1 -1
  518. package/src/core/run-app.tsx +48 -51
  519. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  520. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  521. package/src/core/runtime/__tests__/runtime.test.ts +32 -74
  522. package/src/core/runtime/adapter.ts +1 -1
  523. package/src/core/runtime/config.ts +2 -2
  524. package/src/core/runtime/runtime.ts +33 -46
  525. package/src/core/runtime/types.ts +0 -2
  526. package/src/core/saving/__tests__/document.test.tsx +123 -0
  527. package/src/core/saving/__tests__/state.test.ts +111 -0
  528. package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
  529. package/src/core/saving/document.ts +33 -0
  530. package/src/core/saving/filename.ts +1 -1
  531. package/src/core/saving/save-component.tsx +39 -60
  532. package/src/core/saving/state.ts +38 -39
  533. package/src/core/saving/useAutoSave.ts +17 -53
  534. package/src/core/session/__tests__/backend.test.ts +236 -0
  535. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +184 -0
  536. package/src/core/{websocket → session}/__tests__/useNotebookSession.hook.test.tsx +213 -262
  537. package/src/core/session/active-notebook.ts +28 -0
  538. package/src/core/session/backend.ts +123 -0
  539. package/src/core/session/embedded.ts +7 -0
  540. package/src/core/{websocket → session}/types.ts +2 -2
  541. package/src/core/session/useNotebookReplica.ts +74 -0
  542. package/src/core/{websocket → session}/useNotebookSession.tsx +77 -64
  543. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  544. package/src/core/state/jotai.ts +1 -1
  545. package/src/core/static/__tests__/files.test.ts +38 -10
  546. package/src/core/static/files.ts +2 -0
  547. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  548. package/src/core/transports/__tests__/server.test.ts +408 -0
  549. package/src/core/transports/__tests__/static.test.ts +306 -0
  550. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  551. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  552. package/src/core/transports/server.ts +152 -0
  553. package/src/core/transports/static.ts +166 -0
  554. package/src/core/transports/wasm.ts +97 -0
  555. package/src/core/wasm/__tests__/bridge.test.ts +105 -65
  556. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  557. package/src/core/wasm/bridge.ts +60 -71
  558. package/src/core/wasm/rpc.ts +15 -3
  559. package/src/core/wasm/store.ts +3 -3
  560. package/src/core/wasm/worker/bootstrap.ts +55 -51
  561. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  562. package/src/core/wasm/worker/save-worker.ts +9 -10
  563. package/src/core/wasm/worker/types.ts +29 -18
  564. package/src/core/wasm/worker/worker.ts +89 -45
  565. package/src/css/app/codemirror.css +1 -1
  566. package/src/css/globals.css +66 -22
  567. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  568. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  569. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  570. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  571. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  572. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  573. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  574. package/src/hooks/useAsyncData.ts +3 -3
  575. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  576. package/src/hooks/useDebounce.ts +6 -10
  577. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  578. package/src/hooks/useDelayElapsed.ts +14 -10
  579. package/src/hooks/useElapsedTime.ts +3 -3
  580. package/src/hooks/useEventListener.ts +1 -2
  581. package/src/hooks/useInputHistory.ts +4 -7
  582. package/src/hooks/useInternalStateWithSync.ts +6 -6
  583. package/src/hooks/useResizeObserver.ts +4 -7
  584. package/src/hooks/useScript.ts +67 -70
  585. package/src/hooks/useStateForKey.ts +93 -0
  586. package/src/mount.tsx +20 -15
  587. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  588. package/src/plugins/core/registerReactComponent.tsx +1 -1
  589. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  590. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  591. package/src/plugins/impl/DataTablePlugin.tsx +69 -37
  592. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  593. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  594. package/src/plugins/impl/FormPlugin.tsx +1 -1
  595. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  596. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  597. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  598. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
  599. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  600. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  601. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  602. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  603. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  604. package/src/plugins/impl/anywidget/model.ts +3 -1
  605. package/src/plugins/impl/anywidget/registry.ts +18 -14
  606. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  607. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  608. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  609. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  610. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  611. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  612. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  613. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  614. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  615. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  616. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  617. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  618. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  619. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  620. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  621. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  622. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  623. package/src/plugins/impl/panel/utils.ts +17 -0
  624. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  625. package/src/plugins/impl/plotly/selection.ts +25 -19
  626. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  627. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  628. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  629. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  630. package/src/stories/button.stories.tsx +1 -0
  631. package/src/stories/cell.stories.tsx +2 -5
  632. package/src/stories/data-table.stories.tsx +31 -0
  633. package/src/stories/editor.stories.tsx +24 -17
  634. package/src/stories/form-wrapper.stories.tsx +2 -2
  635. package/src/stories/layout/vertical/one-column.stories.tsx +28 -23
  636. package/src/stories/runtime-story.tsx +23 -17
  637. package/src/stories/select.stories.tsx +2 -2
  638. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  639. package/src/utils/__tests__/arrays.test.ts +35 -0
  640. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  641. package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +29 -0
  642. package/src/utils/__tests__/numbers.test.ts +105 -1
  643. package/src/utils/__tests__/objects.test.ts +21 -0
  644. package/src/utils/arrays.ts +11 -2
  645. package/src/utils/blob.ts +1 -1
  646. package/src/utils/createReducer.ts +53 -26
  647. package/src/utils/maps.ts +0 -3
  648. package/src/utils/numbers.ts +79 -18
  649. package/src/utils/objects.ts +4 -9
  650. package/src/utils/once.ts +19 -19
  651. package/src/utils/tracer.ts +9 -5
  652. package/src/utils/zod-utils.ts +1 -3
  653. package/dist/any-language-editor-D4q-IFcM.js +0 -76
  654. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  655. package/dist/assets/worker-HPY9fbhz.js +0 -114
  656. package/dist/code-visibility-DPm4oWK1.js +0 -138
  657. package/dist/dropdown-menu-DHP9P4VE.js +0 -4678
  658. package/dist/feedback-button-DVgw4Y7F.js +0 -379
  659. package/dist/html-to-image-BdA59IUD.js +0 -3251
  660. package/dist/label-DoysmLMW.js +0 -281
  661. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  662. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +0 -23
  663. package/dist/precisionRound-DMIVQrt2.js +0 -97
  664. package/dist/select-DemoKT4G.js +0 -1344
  665. package/dist/toDate-B5mIgxwZ.js +0 -1185
  666. package/dist/toast-PkdZraM8.js +0 -1830
  667. package/dist/use-restore-focus-CKjfFjLM.js +0 -6369
  668. package/dist/useLifecycle-BGWzTwHK.js +0 -169
  669. package/dist/useTheme-BhQvec43.js +0 -904
  670. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
  671. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
  672. package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
  673. package/src/components/editor/navigation/state.ts +0 -65
  674. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
  675. package/src/core/ai/tools/run-cells-tool.ts +0 -303
  676. package/src/core/attachments/state.ts +0 -18
  677. package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
  678. package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
  679. package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
  680. package/src/core/cells/document-changes.ts +0 -944
  681. package/src/core/codemirror/rtc/extension.ts +0 -453
  682. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
  683. package/src/core/codemirror/rtc/loro/awareness.ts +0 -531
  684. package/src/core/codemirror/rtc/loro/colors.ts +0 -38
  685. package/src/core/codemirror/rtc/loro/sync.ts +0 -168
  686. package/src/core/host/AGENTS.md +0 -11
  687. package/src/core/host/__tests__/events.test.ts +0 -46
  688. package/src/core/host/__tests__/fixtures.ts +0 -39
  689. package/src/core/host/__tests__/notebook-client.test.ts +0 -433
  690. package/src/core/host/__tests__/protocol.test.ts +0 -214
  691. package/src/core/host/__tests__/stream.test.ts +0 -211
  692. package/src/core/host/connection.ts +0 -81
  693. package/src/core/host/events.ts +0 -61
  694. package/src/core/host/notebook-client.ts +0 -290
  695. package/src/core/host/protocol.ts +0 -1943
  696. package/src/core/host/resources/resource.ts +0 -59
  697. package/src/core/host/stream.ts +0 -213
  698. package/src/core/rtc/state.ts +0 -34
  699. package/src/core/state/__tests__/jotai.test.ts +0 -25
  700. package/src/core/wasm/worker/message-buffer.ts +0 -33
  701. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  702. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -170
  703. package/src/core/websocket/state.ts +0 -7
  704. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  705. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  706. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  707. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  708. package/src/core/websocket/transports/basic.ts +0 -102
  709. package/src/core/websocket/transports/create.ts +0 -31
  710. package/src/core/websocket/transports/sse.ts +0 -308
  711. package/src/core/websocket/transports/transport.ts +0 -50
  712. package/src/core/websocket/transports/ws.ts +0 -98
  713. package/src/core/websocket/useNotebookClient.ts +0 -88
  714. package/src/utils/__tests__/id-tree.test.ts +0 -2145
  715. package/src/utils/id-tree.tsx +0 -1134
  716. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  717. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -21,8 +21,8 @@ import {
21
21
  vi,
22
22
  } from "vitest";
23
23
 
24
- vi.mock("../transports/create", () => ({
25
- createConnectionTransport: vi.fn(),
24
+ vi.mock("../backend", () => ({
25
+ createEditorBackend: vi.fn(),
26
26
  }));
27
27
 
28
28
  vi.mock("@/core/runtime/config", async () => {
@@ -36,8 +36,6 @@ vi.mock("@/core/runtime/config", async () => {
36
36
  });
37
37
 
38
38
  import { MockNotebook } from "@/__mocks__/notebook";
39
- import * as Toast from "@/components/ui/use-toast";
40
- import { Logger } from "@/utils/Logger";
41
39
  import { Deferred } from "@/utils/Deferred";
42
40
  import { cellId } from "@/__tests__/branded";
43
41
  import { alertAtom, getPackageAlert } from "@/core/alerts/state";
@@ -45,7 +43,6 @@ import { notebookAtom } from "@/core/cells/cells";
45
43
  import { AppConfigSchema } from "@/core/config/config-schema";
46
44
  import { ConnectionNotice } from "@/components/editor/alerts/connection-notice";
47
45
  import { kernelStartupErrorAtom } from "@/core/errors/state";
48
- import type { RunEvent } from "@/core/host/protocol";
49
46
  import type { NotificationPayload } from "@/core/kernel/messages";
50
47
  import { useRuntimeManager } from "@/core/runtime/config";
51
48
  import { initialRunCompletedAtom } from "../../kernel/state";
@@ -53,54 +50,78 @@ import { connectionAtom, startupProgressAtom } from "../../network/connection";
53
50
  import { generateSessionId } from "../../kernel/session";
54
51
  import { RuntimeManager } from "../../runtime/runtime";
55
52
  import { WebSocketClosedReason, ConnectionState } from "../types";
56
- import type { IConnectionTransport } from "../transports/transport";
53
+ import { classifyCloseEvent } from "../../transports/connection-state";
54
+ import { createEditorBackend } from "../backend";
55
+ import {
56
+ fakeBackend,
57
+ fixtureMessages,
58
+ } from "../../notebook/replica/__tests__/fixtures";
57
59
  import { useNotebookSession } from "../useNotebookSession";
58
- import { createConnectionTransport } from "../transports/create";
60
+ import { type NotebookTransport, StreamStopped } from "@marimo-team/client";
59
61
 
60
62
  const SESSION_ID = generateSessionId();
61
63
 
62
- interface MockTransport {
63
- readyState: 0 | 1 | 2 | 3;
64
- reconnect: Mock<IConnectionTransport["reconnect"]>;
65
- close: Mock<IConnectionTransport["close"]>;
66
- send: Mock<IConnectionTransport["send"]>;
67
- addEventListener: Mock<IConnectionTransport["addEventListener"]>;
68
- removeEventListener: Mock<IConnectionTransport["removeEventListener"]>;
64
+ /** One connection the fake transport opened. */
65
+ interface Attempt {
66
+ open(): void;
67
+ receive(message: unknown): void;
68
+ drop(): void;
69
+ stop(error: StreamStopped): void;
69
70
  }
70
71
 
71
- function makeTransport(
72
- readyState: 0 | 1 | 2 | 3 = WebSocket.CLOSED,
73
- ): MockTransport {
74
- return {
75
- readyState,
76
- reconnect: vi.fn(),
77
- close: vi.fn(),
78
- send: vi.fn(),
79
- addEventListener: vi.fn(),
80
- removeEventListener: vi.fn(),
81
- };
72
+ /** A transport the test drives, one connection at a time. */
73
+ function makeTransport() {
74
+ const attempts: Attempt[] = [];
75
+ const transport: NotebookTransport = ({ signal }, handlers) =>
76
+ new Promise((resolve, reject) => {
77
+ attempts.push({
78
+ open: handlers.open,
79
+ receive: handlers.message,
80
+ drop: resolve,
81
+ stop: reject,
82
+ });
83
+ signal.addEventListener("abort", () => resolve(), { once: true });
84
+ });
85
+ return { transport, attempts };
82
86
  }
83
87
 
84
- function getTransportHandlers() {
85
- const result = vi.mocked(createConnectionTransport).mock.results.at(-1);
86
- if (!result || result.type !== "return") {
87
- throw new Error("No connection transport was created");
88
- }
89
- const transport = result.value;
90
- function emit(
91
- event: "open" | "close" | "error" | "message",
92
- message: Event | CloseEvent | MessageEvent,
93
- ) {
94
- const callback = vi
95
- .mocked(transport.addEventListener)
96
- .mock.calls.find(([name]) => name === event)?.[1];
97
- callback?.(message);
98
- }
88
+ type FakeTransport = ReturnType<typeof makeTransport>;
89
+
90
+ /** Use a fake transport for the next session the hook follows. */
91
+ function withTransport(fake: FakeTransport = makeTransport()) {
92
+ vi.mocked(createEditorBackend).mockImplementation(({ checkHealth }) =>
93
+ fakeBackend({ transport: fake.transport, checkHealth }),
94
+ );
95
+ return fake;
96
+ }
97
+
98
+ /** Let the stream open its first connection. */
99
+ const started = () => act(() => Promise.resolve());
100
+
101
+ /** Drive the latest connection the fake transport opened. */
102
+ function connection(fake: FakeTransport) {
103
+ const current = () => {
104
+ const attempt = fake.attempts.at(-1);
105
+ if (attempt === undefined) {
106
+ throw new Error("No connection was opened");
107
+ }
108
+ return attempt;
109
+ };
99
110
  return {
100
- onError: (event: Event) => emit("error", event),
101
- onOpen: (event: Event) => emit("open", event),
102
- onClose: (event: CloseEvent) => emit("close", event),
103
- onMessage: (event: MessageEvent) => emit("message", event),
111
+ open: () => current().open(),
112
+ receive: (message: unknown) => current().receive(message),
113
+ /** Deliver a notification as the session routes frame it. */
114
+ send: (notification: unknown) =>
115
+ current().receive({ event: "marimo", data: { marimo: notification } }),
116
+ /** End the connection so the stream reconnects. */
117
+ drop: () => current().drop(),
118
+ /** Close the connection with a reason the editor treats as final. */
119
+ close: (reason: string) =>
120
+ current().stop(
121
+ new StreamStopped(reason, {
122
+ cause: classifyCloseEvent({ reason }).status,
123
+ }),
124
+ ),
104
125
  };
105
126
  }
106
127
 
@@ -124,7 +145,10 @@ function makeRuntimeManager(
124
145
  return runtime;
125
146
  }
126
147
 
127
- function renderConnectionHook(store: ReturnType<typeof createStore>) {
148
+ function renderConnectionHook(
149
+ store: ReturnType<typeof createStore>,
150
+ { reactStrictMode = false } = {},
151
+ ) {
128
152
  const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
129
153
  <JotaiProvider store={store}>
130
154
  <ErrorBoundary fallback={null}>{children}</ErrorBoundary>
@@ -135,19 +159,18 @@ function renderConnectionHook(store: ReturnType<typeof createStore>) {
135
159
  useNotebookSession({
136
160
  sessionId: SESSION_ID,
137
161
  autoInstantiate: false,
138
- setCells: vi.fn(),
139
162
  }),
140
- { wrapper },
163
+ { wrapper, reactStrictMode },
141
164
  );
142
165
  }
143
166
 
144
167
  describe("useNotebookSession.reconnect()", () => {
145
- let transport: MockTransport;
168
+ let fake: FakeTransport;
146
169
  let isHealthy: Mock<() => Promise<boolean>>;
147
170
  let store: ReturnType<typeof createStore>;
148
171
 
149
172
  beforeEach(() => {
150
- transport = makeTransport(WebSocket.CLOSED);
173
+ fake = withTransport();
151
174
  isHealthy = vi.fn<() => Promise<boolean>>().mockResolvedValue(true);
152
175
  store = createStore();
153
176
  store.set(connectionAtom, {
@@ -155,55 +178,53 @@ describe("useNotebookSession.reconnect()", () => {
155
178
  code: WebSocketClosedReason.KERNEL_DISCONNECTED,
156
179
  reason: "kernel not found",
157
180
  });
158
- vi.mocked(createConnectionTransport).mockReturnValue(transport);
159
181
  vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager(isHealthy));
160
182
  });
161
183
 
162
- function renderUseHook() {
163
- return renderConnectionHook(store);
184
+ async function renderStopped() {
185
+ const hook = renderConnectionHook(store);
186
+ await started();
187
+ await act(async () => connection(fake).close("MARIMO_SHUTDOWN"));
188
+ return hook;
164
189
  }
165
190
 
166
- it("is a no-op when the transport is already OPEN", async () => {
167
- transport.readyState = WebSocket.OPEN;
168
- const { result } = renderUseHook();
169
- await act(async () => {
170
- await result.current.reconnect();
171
- });
172
- expect(isHealthy).not.toHaveBeenCalled();
173
- expect(transport.reconnect).not.toHaveBeenCalled();
174
- });
175
-
176
- it("is a no-op when the transport is already CONNECTING", async () => {
177
- transport.readyState = WebSocket.CONNECTING;
178
- const { result } = renderUseHook();
179
- await act(async () => {
180
- await result.current.reconnect();
181
- });
182
- expect(isHealthy).not.toHaveBeenCalled();
183
- expect(transport.reconnect).not.toHaveBeenCalled();
184
- });
191
+ it.each(["connecting", "connected"])(
192
+ "is a no-op while the stream is %s",
193
+ async (state) => {
194
+ const { result } = renderConnectionHook(store);
195
+ await started();
196
+ if (state === "connected") {
197
+ act(() => connection(fake).open());
198
+ }
199
+ await act(async () => {
200
+ await result.current.reconnect();
201
+ });
202
+ expect(isHealthy).not.toHaveBeenCalled();
203
+ expect(fake.attempts).toHaveLength(1);
204
+ },
205
+ );
185
206
 
186
207
  it("probes /health and reconnects when the runtime is healthy", async () => {
187
208
  isHealthy.mockResolvedValue(true);
188
- const { result } = renderUseHook();
209
+ const { result } = await renderStopped();
189
210
  await act(async () => {
190
211
  await result.current.reconnect();
191
212
  });
192
213
  expect(isHealthy).toHaveBeenCalledOnce();
193
- expect(transport.reconnect).toHaveBeenCalledOnce();
214
+ expect(fake.attempts).toHaveLength(2);
194
215
  expect(store.get(connectionAtom)).toEqual({
195
216
  state: ConnectionState.CONNECTING,
196
217
  });
197
218
  });
198
219
 
199
- it("transitions to CLOSED and does not call ws.reconnect when the probe fails", async () => {
220
+ it("transitions to CLOSED and does not reconnect when the probe fails", async () => {
200
221
  isHealthy.mockResolvedValue(false);
201
- const { result } = renderUseHook();
222
+ const { result } = await renderStopped();
202
223
  await act(async () => {
203
224
  await result.current.reconnect();
204
225
  });
205
226
  expect(isHealthy).toHaveBeenCalledOnce();
206
- expect(transport.reconnect).not.toHaveBeenCalled();
227
+ expect(fake.attempts).toHaveLength(1);
207
228
  expect(store.get(connectionAtom)).toEqual({
208
229
  state: ConnectionState.CLOSED,
209
230
  code: WebSocketClosedReason.KERNEL_DISCONNECTED,
@@ -212,124 +233,86 @@ describe("useNotebookSession.reconnect()", () => {
212
233
  });
213
234
  });
214
235
 
236
+ describe("useNotebookSession document model", () => {
237
+ it("keeps drafts while the connection drops and discards them when the session ends", async () => {
238
+ const fake = withTransport();
239
+ vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
240
+ const store = createStore();
241
+ const { result, unmount } = renderConnectionHook(store, {
242
+ reactStrictMode: true,
243
+ });
244
+ await started();
245
+ act(() => {
246
+ connection(fake).open();
247
+ fixtureMessages("notebook-events.sse").forEach(connection(fake).receive);
248
+ });
249
+ const model = result.current.documentModel;
250
+ const code = () => store.get(model.documentAtom)?.cells.get("c1")?.code;
251
+ act(() => store.set(model.editAtom, (tx) => tx.setCode("c1", "local")));
252
+ expect(code()).toBe("local");
253
+
254
+ await act(async () => connection(fake).drop());
255
+ expect(result.current.documentModel).toBe(model);
256
+ expect(code()).toBe("local");
257
+
258
+ unmount();
259
+ expect(code()).toBeUndefined();
260
+ await expect(model.flush()).rejects.toThrow("not started");
261
+ });
262
+
263
+ it("follows the host document into the notebook's cells", async () => {
264
+ const fake = withTransport();
265
+ vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
266
+ const store = createStore();
267
+ const { result, unmount } = renderConnectionHook(store);
268
+ await started();
269
+ act(() => {
270
+ connection(fake).open();
271
+ fixtureMessages("notebook-events.sse").forEach(connection(fake).receive);
272
+ });
273
+
274
+ let notebook = store.get(notebookAtom);
275
+ expect(notebook.cellIds).toEqual(["c1", "c3", "k7f2"]);
276
+ expect(notebook.cellData[cellId("k7f2")]).toMatchObject({
277
+ code: "y = x * 2",
278
+ config: { hide_code: true },
279
+ });
280
+
281
+ const model = result.current.documentModel;
282
+ act(() => store.set(model.editAtom, (tx) => tx.setCode("c3", "x = 42")));
283
+ notebook = store.get(notebookAtom);
284
+ expect(notebook.cellData[cellId("c3")].code).toBe("x = 42");
285
+
286
+ unmount();
287
+ });
288
+ });
289
+
215
290
  describe("useNotebookSession messages", () => {
216
291
  let store: ReturnType<typeof createStore>;
292
+ let fake: FakeTransport;
217
293
 
218
- beforeEach(() => {
294
+ beforeEach(async () => {
219
295
  store = createStore();
220
- vi.mocked(createConnectionTransport).mockClear();
221
- vi.mocked(createConnectionTransport).mockReturnValue(
222
- makeTransport(WebSocket.OPEN),
223
- );
296
+ fake = withTransport();
224
297
  vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
225
298
  renderConnectionHook(store);
299
+ await started();
226
300
  });
227
301
 
228
302
  function receive(payload: unknown) {
229
- const options = getTransportHandlers();
230
- act(() => {
231
- options.onMessage(
232
- new MessageEvent("message", { data: JSON.stringify(payload) }),
233
- );
234
- });
303
+ act(() => connection(fake).receive(payload));
235
304
  }
236
305
 
237
- it.each(["{broken", "null"])(
238
- "reports a malformed legacy frame and continues applying notifications: %s",
239
- (data) => {
240
- const toast = vi.spyOn(Toast, "toast");
241
- try {
242
- receive({ data: { op: "reconnected" } });
243
- act(() =>
244
- getTransportHandlers().onMessage(
245
- new MessageEvent("message", { data }),
246
- ),
247
- );
248
- expect(toast).toHaveBeenCalledExactlyOnceWith({
249
- title: "Failed to handle message",
250
- description: expect.any(String),
251
- variant: "danger",
252
- });
253
- expect(store.get(connectionAtom)).toEqual({
254
- state: ConnectionState.OPEN,
255
- });
256
- receive({
257
- data: {
258
- op: "completed-run",
259
- run_id: "r1",
260
- outcome: "succeeded",
261
- error: null,
262
- },
263
- });
264
- expect(store.get(initialRunCompletedAtom)).toBe(true);
265
- } finally {
266
- toast.mockRestore();
267
- }
268
- },
269
- );
270
-
271
- it.each(["session", "host"])(
272
- "records completion of the initial run from the %s stream",
273
- (stream) => {
274
- const notification = {
275
- op: "completed-run",
276
- run_id: null,
277
- outcome: "succeeded",
278
- error: null,
279
- } satisfies NotificationPayload["data"];
280
- expect(store.get(initialRunCompletedAtom)).toBe(false);
281
- receive(
282
- stream === "host"
283
- ? { id: "42", event: "marimo", data: { marimo: notification } }
284
- : { op: notification.op, data: notification },
285
- );
286
- expect(store.get(initialRunCompletedAtom)).toBe(true);
287
- },
288
- );
289
-
290
- it("ignores other host events before handling the next notification", () => {
291
- const errors = vi.spyOn(Logger, "error").mockImplementation(vi.fn());
292
- try {
293
- receive({ id: "1", event: "ready", data: {} });
294
- receive({
295
- id: "2",
296
- event: "run",
297
- data: {
298
- run: {
299
- id: "r1",
300
- notebook_id: "n1",
301
- caused_by: null,
302
- status: "completed",
303
- outcome: "succeeded",
304
- started_at: "2026-10-19T12:00:00Z",
305
- completed_at: "2026-10-19T12:00:01Z",
306
- },
307
- },
308
- } satisfies RunEvent);
309
- receive({
310
- id: "3",
311
- event: "future-event",
312
- data: { marimo: { op: "completed-run", run_id: "r1" } },
313
- });
314
- receive({ id: "4", event: "another-event", data: null });
315
- expect(store.get(initialRunCompletedAtom)).toBe(false);
316
- receive({
317
- id: "5",
318
- event: "marimo",
319
- data: {
320
- marimo: {
321
- op: "completed-run",
322
- run_id: "r1",
323
- outcome: "succeeded",
324
- error: null,
325
- },
326
- },
327
- });
328
- expect(store.get(initialRunCompletedAtom)).toBe(true);
329
- expect(errors).not.toHaveBeenCalled();
330
- } finally {
331
- errors.mockRestore();
332
- }
306
+ it("records completion of the initial run", () => {
307
+ const notification = {
308
+ op: "completed-run",
309
+ run_id: null,
310
+ outcome: "succeeded",
311
+ error: null,
312
+ } satisfies NotificationPayload["data"];
313
+ expect(store.get(initialRunCompletedAtom)).toBe(false);
314
+ receive({ id: "42", event: "marimo", data: { marimo: notification } });
315
+ expect(store.get(initialRunCompletedAtom)).toBe(true);
333
316
  });
334
317
  });
335
318
 
@@ -338,45 +321,30 @@ it.each(["kernel-ready", "reconnected"])(
338
321
  async (op) => {
339
322
  const store = createStore();
340
323
  store.set(connectionAtom, { state: ConnectionState.CONNECTING });
341
- vi.mocked(createConnectionTransport).mockClear();
342
- vi.mocked(createConnectionTransport).mockReturnValue(
343
- makeTransport(WebSocket.OPEN),
344
- );
324
+ const fake = withTransport();
345
325
  vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
346
326
  renderConnectionHook(store);
347
- const options = getTransportHandlers();
327
+ await started();
328
+ const conn = connection(fake);
348
329
 
349
- await act(async () => {
350
- await options.onOpen(new Event("open"));
351
- });
330
+ await act(async () => conn.open());
352
331
  expect(store.get(connectionAtom).state).toBe(ConnectionState.CONNECTING);
353
332
 
354
- act(() => {
355
- options.onMessage(
356
- new MessageEvent("message", {
357
- data: JSON.stringify({
358
- op,
359
- data: {
360
- op,
361
- cell_ids: [],
362
- codes: [],
363
- names: [],
364
- configs: [],
365
- layout: null,
366
- resumed: true,
367
- ui_values: {},
368
- last_executed_code: {},
369
- last_execution_time: {},
370
- app_config: { width: "normal" },
371
- kiosk: false,
372
- capabilities: { terminal: false },
373
- auto_instantiated: false,
374
- consumer_capabilities: { edit: true, interact: true },
375
- },
376
- }),
377
- }),
378
- );
379
- });
333
+ act(() =>
334
+ conn.send({
335
+ op,
336
+ layout: null,
337
+ resumed: true,
338
+ ui_values: {},
339
+ last_executed_code: {},
340
+ last_execution_time: {},
341
+ app_config: { width: "normal" },
342
+ kiosk: false,
343
+ capabilities: { terminal: false },
344
+ auto_instantiated: false,
345
+ consumer_capabilities: { edit: true, interact: true },
346
+ }),
347
+ );
380
348
  expect(store.get(connectionAtom).state).toBe(ConnectionState.OPEN);
381
349
  },
382
350
  );
@@ -385,17 +353,15 @@ describe("connection notice", () => {
385
353
  beforeEach(() => vi.useFakeTimers());
386
354
  afterEach(() => vi.useRealTimers());
387
355
 
388
- function renderNotice() {
356
+ async function renderNotice() {
389
357
  const store = createStore();
390
358
  store.set(connectionAtom, { state: ConnectionState.CONNECTING });
391
- const transport = makeTransport(WebSocket.OPEN);
392
- vi.mocked(createConnectionTransport).mockReturnValue(transport);
359
+ const fake = withTransport();
393
360
  vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
394
361
  const Connection = () => {
395
362
  const { reconnect } = useNotebookSession({
396
363
  sessionId: SESSION_ID,
397
364
  autoInstantiate: false,
398
- setCells: vi.fn(),
399
365
  });
400
366
  return (
401
367
  <ConnectionNotice
@@ -411,20 +377,17 @@ describe("connection notice", () => {
411
377
  </ErrorBoundary>
412
378
  </JotaiProvider>,
413
379
  );
414
- const options = getTransportHandlers();
380
+ await started();
381
+ const conn = connection(fake);
382
+ // Messages arrive on an open connection.
383
+ act(() => conn.open());
415
384
  const send = (data: NotificationPayload["data"]) =>
416
- act(() => {
417
- options.onMessage(
418
- new MessageEvent("message", {
419
- data: JSON.stringify({ op: data.op, data }),
420
- }),
421
- );
422
- });
423
- return { store, transport, options, send };
385
+ act(() => conn.send(data));
386
+ return { store, fake, conn, send };
424
387
  }
425
388
 
426
- it("keeps elapsed time across startup phases and leaves reconnection to the footer once cells are available", () => {
427
- const { store, options, send } = renderNotice();
389
+ it("keeps elapsed time across startup phases and leaves reconnection to the footer once cells are available", async () => {
390
+ const { store, conn, send } = await renderNotice();
428
391
  send({
429
392
  op: "startup-progress",
430
393
  phase: "preparing-environment",
@@ -464,7 +427,7 @@ describe("connection notice", () => {
464
427
  expect(
465
428
  screen.queryByRole("region", { name: "Notebook startup" }),
466
429
  ).not.toBeInTheDocument();
467
- act(() => options.onClose(new CloseEvent("close")));
430
+ await act(async () => conn.drop());
468
431
  act(() => vi.advanceTimersByTime(500));
469
432
  expect(store.get(connectionAtom)).toEqual({
470
433
  state: ConnectionState.CONNECTING,
@@ -475,8 +438,8 @@ describe("connection notice", () => {
475
438
  ).not.toBeInTheDocument();
476
439
  });
477
440
 
478
- it("restores startup output before appending live chunks and resets it for a new attempt", () => {
479
- const { store, send } = renderNotice();
441
+ it("restores startup output before appending live chunks and resets it for a new attempt", async () => {
442
+ const { store, send } = await renderNotice();
480
443
  const snapshot = {
481
444
  op: "startup-progress",
482
445
  phase: "starting-kernel",
@@ -502,7 +465,7 @@ describe("connection notice", () => {
502
465
  });
503
466
 
504
467
  it("restores completed startup output without putting a connected kernel back into startup", async () => {
505
- const { store, options, send } = renderNotice();
468
+ const { store, conn, send } = await renderNotice();
506
469
  send({ op: "reconnected" });
507
470
  send({
508
471
  op: "startup-progress",
@@ -520,13 +483,15 @@ describe("connection notice", () => {
520
483
  screen.queryByRole("region", { name: "Notebook startup" }),
521
484
  ).not.toBeInTheDocument();
522
485
 
523
- // A new transport starts from the next session's authoritative snapshot.
524
- await act(async () => options.onOpen(new Event("open")));
486
+ // A new connection starts from the next session's authoritative snapshot.
487
+ await act(async () => conn.drop());
488
+ await act(async () => vi.advanceTimersByTime(2000));
489
+ await act(async () => conn.open());
525
490
  expect(store.get(startupProgressAtom)).toBeNull();
526
491
  });
527
492
 
528
- it("does not flash a notice when startup finishes within the delay", () => {
529
- const { send } = renderNotice();
493
+ it("does not flash a notice when startup finishes within the delay", async () => {
494
+ const { send } = await renderNotice();
530
495
  send({
531
496
  op: "startup-progress",
532
497
  phase: "preparing-environment",
@@ -554,16 +519,11 @@ describe("connection notice", () => {
554
519
  it.each(["preparing-environment", "starting-kernel"] as const)(
555
520
  "keeps a %s failure available until the user retries",
556
521
  async (phase) => {
557
- const { store, transport, options, send } = renderNotice();
522
+ const { store, fake, conn, send } = await renderNotice();
558
523
  send({ op: "startup-progress", phase, logs: "", log_mode: "replace" });
559
524
  const error = "A full diagnostic\nwith <stderr> details";
560
525
  send({ op: "kernel-startup-error", error });
561
- transport.readyState = WebSocket.CLOSED;
562
- act(() =>
563
- options.onClose(
564
- new CloseEvent("close", { reason: "MARIMO_KERNEL_STARTUP_ERROR" }),
565
- ),
566
- );
526
+ await act(async () => conn.close("MARIMO_KERNEL_STARTUP_ERROR"));
567
527
  expect(screen.getByRole("status")).toHaveTextContent(
568
528
  "Kernel failed to start",
569
529
  );
@@ -574,11 +534,11 @@ describe("connection notice", () => {
574
534
  expect(screen.getByLabelText("Error details")).toHaveTextContent(error, {
575
535
  normalizeWhitespace: false,
576
536
  });
577
- expect(transport.reconnect).not.toHaveBeenCalled();
537
+ expect(fake.attempts).toHaveLength(1);
578
538
  await act(async () =>
579
539
  fireEvent.click(screen.getByRole("button", { name: "Try again" })),
580
540
  );
581
- expect(transport.reconnect).toHaveBeenCalledOnce();
541
+ expect(fake.attempts).toHaveLength(2);
582
542
  expect(store.get(kernelStartupErrorAtom)).toBeNull();
583
543
  expect(
584
544
  screen.queryByRole("button", { name: "Try again" }),
@@ -598,23 +558,14 @@ describe("connection notice", () => {
598
558
  );
599
559
  });
600
560
 
601
- it("replaces environment state from snapshots, then continues live progress", () => {
561
+ it("replaces environment state from snapshots, then continues live progress", async () => {
602
562
  const store = createStore();
603
- vi.mocked(createConnectionTransport).mockClear();
604
- vi.mocked(createConnectionTransport).mockReturnValue(
605
- makeTransport(WebSocket.OPEN),
606
- );
563
+ const fake = withTransport();
607
564
  vi.mocked(useRuntimeManager).mockReturnValue(makeRuntimeManager());
608
565
  renderConnectionHook(store);
609
- const options = getTransportHandlers();
566
+ await started();
610
567
  function receive(data: NotificationPayload["data"]) {
611
- act(() =>
612
- options?.onMessage(
613
- new MessageEvent("message", {
614
- data: JSON.stringify({ op: data.op, data }),
615
- }),
616
- ),
617
- );
568
+ act(() => connection(fake).send(data));
618
569
  }
619
570
  receive({
620
571
  op: "environment-operation",