@marimo-team/islands 0.25.3-dev17 → 0.25.3-dev173

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (549) hide show
  1. package/dist/{ConnectedDataExplorerComponent-CNMliVzw.js → ConnectedDataExplorerComponent-Le_OBfmt.js} +21 -19
  2. package/dist/{ErrorBoundary-jaGao4LA.js → ErrorBoundary-wT3f3iJ1.js} +19 -19
  3. package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Tf1ghyQQ.js} +2 -2
  4. package/dist/any-language-editor-B92WMzoC.js +75 -0
  5. package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-xlnbTG0T.js} +1 -1
  6. package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
  7. package/dist/assets/__vite-browser-external-DVeFf2e7.js +1 -0
  8. package/dist/assets/worker-C1pfNBsx.js +113 -0
  9. package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
  10. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CI4xUPsp.js} +2 -2
  11. package/dist/{chat-ui-DaHynk8g.js → chat-ui-CuORr6fL.js} +1142 -1141
  12. package/dist/{check-EDwSwP89.js → check-C9Mp9eCK.js} +1 -1
  13. package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-Cmd4a5jy.js} +1 -1
  14. package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-mSNp-WpO.js} +1 -1
  15. package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-CWC49D8X.js} +1 -1
  16. package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-De9FINtG.js} +1 -1
  17. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  18. package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-DweTkYdp.js} +2 -2
  19. package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-A6MR2TiE.js} +2 -2
  20. package/dist/{code-visibility-Bub8tnaA.js → code-visibility-ZReaeMaF.js} +25 -25
  21. package/dist/{common-CdT0nyN1.js → common-DCevHg1m.js} +6917 -6738
  22. package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-De584pZ4.js} +3 -3
  23. package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-BSvo5le-.js} +1 -1
  24. package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-tXRQslO6.js} +1 -1
  25. package/dist/{data-grid-overlay-editor-Dbcss6_2.js → data-grid-overlay-editor-CTC-bJus.js} +5 -5
  26. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  27. package/dist/{diagram-S7CK7UJ4-BsSJJldB.js → diagram-S7CK7UJ4-r3t5VtwI.js} +1 -1
  28. package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-qgbC8YnT.js} +1 -1
  29. package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-CiHxEwtp.js} +1 -1
  30. package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-D95u15Ev.js} +1 -1
  31. package/dist/{dialog-CEBFZNyc.js → dialog-DVRfQuhD.js} +25 -25
  32. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  33. package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-DCMbbQ35.js} +1481 -1433
  34. package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-P7e4bryK.js} +2 -2
  35. package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-CUHZcmRj.js} +1 -1
  36. package/dist/{error-banner-D-WCIiMt.js → error-banner-DxJ3s8YO.js} +86 -86
  37. package/dist/{error-entries-Bv6bZPF3.js → error-entries-CmWMEsY_.js} +5756 -5643
  38. package/dist/{feedback-button-B3Wrnsf_.js → feedback-button-DwXkmewo.js} +35 -35
  39. package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-BGZ95AzI.js} +2 -2
  40. package/dist/{formats-27CW_UP4.js → formats-DI7HEVv7.js} +3 -3
  41. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  42. package/dist/{glide-data-editor-BDYKJdqK.js → glide-data-editor-BlmcP-lw.js} +370 -368
  43. package/dist/{glide-utils-DJyqh0EM.js → glide-utils-D98laidb.js} +16 -16
  44. package/dist/{globals-DGTE1S0_.js → globals-BdRitZ4p.js} +3 -3
  45. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  46. package/dist/{html-to-image-Bf8QMGi4.js → html-to-image-bpiQh7ND.js} +639 -602
  47. package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-BF0YX70D.js} +1 -1
  48. package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-_itsAAn-.js} +1 -1
  49. package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-VNW2Beqh.js} +1 -1
  50. package/dist/{label-BDKF3Afc.js → label-Qvw1E97W.js} +3 -3
  51. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  52. package/dist/{loader-BQOfjTIJ.js → loader-DOVB0Syl.js} +12 -12
  53. package/dist/main.js +9672 -7674
  54. package/dist/{mermaid-CHo49Yv-.js → mermaid-CZ6FrClS.js} +38 -38
  55. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  56. package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-DR4ripvd.js} +1 -1
  57. package/dist/{number-overlay-editor-S8UJY0i5.js → number-overlay-editor-DQG-hFHT.js} +3 -3
  58. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  59. package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
  60. package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-CFr3XlGl.js} +2 -2
  61. package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-j91XYSLY.js} +1 -1
  62. package/dist/precisionRound-DhAzeRcm.js +49 -0
  63. package/dist/{process-output-BZg56CCb.js → process-output-BzloOI7F.js} +4 -4
  64. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  65. package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-Cd47ZV9E.js} +2 -2
  66. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  67. package/dist/{requirementDiagram-BXWQKSXE-a_MxGvxe.js → requirementDiagram-BXWQKSXE-eJH6gLtX.js} +1 -1
  68. package/dist/{reveal-component-De4Pvf4V.js → reveal-component-D3r3vSTK.js} +14 -14
  69. package/dist/{select-BButFi-d.js → select-2KOiReNY.js} +536 -457
  70. package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-DdfFEIrm.js} +1 -1
  71. package/dist/{spec-BwarBpUJ.js → spec-h69nC3SI.js} +41 -11
  72. package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-DkjDvip8.js} +2 -2
  73. package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-DBHACnOo.js} +2 -2
  74. package/dist/style.css +1 -1
  75. package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-ogImlOmp.js} +1 -1
  76. package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-D6x-zsci.js} +2 -2
  77. package/dist/{swiper-component-DKntyn8p.js → swiper-component-BkCm-kLg.js} +2 -2
  78. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  79. package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-DQpLtsHD.js} +1 -1
  80. package/dist/{toDate-UtiwmnH2.js → toDate-CDzoofJo.js} +37 -36
  81. package/dist/{toast-B9UMEi8u.js → toast-B5t9o6s_.js} +219 -201
  82. package/dist/{tooltip-BO1REbqs.js → tooltip-s4zZxwKe.js} +325 -301
  83. package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-BgDTd2tc.js} +1482 -1433
  84. package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-Bn8SxUqM.js} +15 -14
  85. package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-D3Tkfzej.js} +2 -2
  86. package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-CC2tnPCk.js} +1 -1
  87. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
  88. package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-BJlxHqWa.js} +28 -25
  89. package/dist/{useTheme-CRnjkku0.js → useTheme-DMfQYmlG.js} +301 -297
  90. package/dist/{vega-component-BeF9dfyO.js → vega-component-CovWHi60.js} +148 -148
  91. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  92. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  93. package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-BD-SL_vq.js} +1 -1
  94. package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-BDgJV4ah.js} +1 -1
  95. package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-1hIHN6Rl.js} +2 -2
  96. package/package.json +16 -16
  97. package/src/__mocks__/requests.ts +0 -1
  98. package/src/__tests__/module-entry.test.ts +44 -0
  99. package/src/__tests__/mount.test.ts +1 -21
  100. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  101. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  102. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  103. package/src/components/app-config/ai-config.tsx +7 -2
  104. package/src/components/app-config/user-config-form.tsx +35 -0
  105. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  106. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  107. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  108. package/src/components/chat/acp/blocks.tsx +3 -2
  109. package/src/components/chat/acp/session-tabs.tsx +8 -3
  110. package/src/components/chat/chat-components.tsx +2 -0
  111. package/src/components/chat/chat-panel.tsx +9 -8
  112. package/src/components/chat/chat-utils.ts +4 -8
  113. package/src/components/data-table/TableBottomBar.tsx +4 -1
  114. package/src/components/data-table/TableTopBar.tsx +2 -0
  115. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  116. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  117. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  118. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  119. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  120. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  121. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  122. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  123. package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
  124. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  125. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  126. package/src/components/data-table/cell-selection/feature.ts +2 -2
  127. package/src/components/data-table/cell-selection/types.ts +2 -2
  128. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  129. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  130. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  131. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  132. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  133. package/src/components/data-table/charts/charts.tsx +40 -30
  134. package/src/components/data-table/charts/storage.ts +16 -5
  135. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  136. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  137. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  138. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  139. package/src/components/data-table/columns.tsx +45 -46
  140. package/src/components/data-table/context-menu.tsx +36 -20
  141. package/src/components/data-table/data-table.tsx +17 -1
  142. package/src/components/data-table/date-popover.tsx +6 -4
  143. package/src/components/data-table/export-actions.tsx +76 -48
  144. package/src/components/data-table/pagination.tsx +44 -33
  145. package/src/components/data-table/range-focus/atoms.ts +4 -6
  146. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  147. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  148. package/src/components/data-table/renderers.tsx +16 -7
  149. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  150. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  151. package/src/components/data-table/search-highlight.tsx +79 -0
  152. package/src/components/data-table/types.ts +1 -0
  153. package/src/components/data-table/url-detector.tsx +49 -9
  154. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  155. package/src/components/datasources/__tests__/column-preview.test.tsx +98 -5
  156. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  157. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  158. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  159. package/src/components/datasources/column-preview.tsx +13 -4
  160. package/src/components/datasources/datasources.tsx +51 -39
  161. package/src/components/datasources/utils.ts +32 -23
  162. package/src/components/debugger/debugger-code.tsx +5 -0
  163. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  164. package/src/components/dependency-graph/elements.ts +24 -21
  165. package/src/components/dependency-graph/panels.tsx +2 -1
  166. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  167. package/src/components/editor/SortableCell.tsx +1 -3
  168. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  169. package/src/components/editor/__tests__/data-attributes.test.tsx +6 -2
  170. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  171. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  172. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +24 -0
  173. package/src/components/editor/actions/pair-with-agent-modal.tsx +18 -15
  174. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  175. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  176. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  177. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  178. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  179. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  180. package/src/components/editor/app-container.tsx +1 -1
  181. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  182. package/src/components/editor/cell/CreateCellButton.tsx +10 -12
  183. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  184. package/src/components/editor/cell/RunButton.tsx +2 -2
  185. package/src/components/editor/cell/StagedAICell.tsx +10 -2
  186. package/src/components/editor/cell/StopButton.tsx +2 -2
  187. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  188. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  189. package/src/components/editor/cell/code/cell-editor.tsx +9 -16
  190. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  191. package/src/components/editor/cell/collapse.tsx +5 -3
  192. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  193. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  194. package/src/components/editor/chrome/components/feedback-button.tsx +1 -1
  195. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  196. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  197. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  198. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  199. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  200. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  201. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  202. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  203. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  204. package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -1
  205. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +9 -18
  206. package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
  207. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
  208. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  209. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  210. package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
  211. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  212. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  213. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  214. package/src/components/editor/chrome/wrapper/footer.tsx +2 -0
  215. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  216. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  217. package/src/components/editor/connections/components.tsx +1 -1
  218. package/src/components/editor/controls/Controls.tsx +2 -2
  219. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  220. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  221. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +1 -1
  222. package/src/components/editor/controls/command-palette.tsx +22 -10
  223. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  224. package/src/components/editor/dynamic-favicon.tsx +21 -40
  225. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +9 -23
  226. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  227. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  228. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  229. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  230. package/src/components/editor/file-tree/file-explorer.tsx +45 -8
  231. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  232. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  233. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  234. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  235. package/src/components/editor/header/app-header.tsx +1 -1
  236. package/src/components/editor/header/status.tsx +40 -20
  237. package/src/components/editor/links/__tests__/cell-link.test.tsx +146 -0
  238. package/src/components/editor/links/cell-link.tsx +14 -5
  239. package/src/components/editor/navigation/focus-utils.ts +4 -4
  240. package/src/components/editor/notebook-banner.tsx +1 -0
  241. package/src/components/editor/notebook-cell.tsx +12 -3
  242. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  243. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  244. package/src/components/editor/output/Outputs.css +8 -0
  245. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  246. package/src/components/editor/output/ansi-reduce.ts +33 -20
  247. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  248. package/src/components/editor/package-alert.tsx +14 -7
  249. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  250. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  251. package/src/components/home/components.tsx +17 -31
  252. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  253. package/src/components/icons/large-spinner.tsx +3 -14
  254. package/src/components/icons/spinner.tsx +1 -1
  255. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  256. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  257. package/src/components/pages/home-page.tsx +164 -91
  258. package/src/components/scratchpad/scratchpad.test.tsx +95 -0
  259. package/src/components/scratchpad/scratchpad.tsx +16 -3
  260. package/src/components/slides/reveal-component.tsx +4 -2
  261. package/src/components/slides/slide-cell-view.tsx +1 -1
  262. package/src/components/slides/slide-form.tsx +1 -0
  263. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  264. package/src/components/tracing/tracing.tsx +45 -41
  265. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  266. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  267. package/src/components/ui/alert-dialog.tsx +1 -1
  268. package/src/components/ui/draggable-popover.tsx +24 -2
  269. package/src/components/ui/range-slider.tsx +22 -9
  270. package/src/core/ai/__tests__/staged-cells.test.ts +8 -5
  271. package/src/core/ai/context/providers/datasource.ts +6 -2
  272. package/src/core/ai/staged-cells.ts +7 -2
  273. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +3 -15
  274. package/src/core/ai/tools/base.ts +16 -7
  275. package/src/core/ai/tools/edit-notebook-tool.ts +61 -48
  276. package/src/core/ai/tools/registry.ts +13 -8
  277. package/src/core/ai/tools/sample-tool.ts +6 -7
  278. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
  279. package/src/core/cells/__tests__/cell.test.ts +39 -0
  280. package/src/core/cells/__tests__/cells.test.ts +83 -346
  281. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  282. package/src/core/cells/__tests__/document.test.ts +444 -0
  283. package/src/core/cells/__tests__/flush-document.test.ts +40 -0
  284. package/src/core/cells/__tests__/notebook-outline.test.ts +108 -0
  285. package/src/core/cells/__tests__/session.test.ts +117 -36
  286. package/src/core/cells/__tests__/with-document-save.test.ts +67 -0
  287. package/src/core/cells/cell.ts +14 -3
  288. package/src/core/cells/cells.ts +65 -190
  289. package/src/core/cells/columns.ts +38 -0
  290. package/src/core/cells/document.ts +389 -0
  291. package/src/core/cells/pending-delete-service.ts +2 -6
  292. package/src/core/cells/session.ts +1 -1
  293. package/src/core/cells/types.ts +22 -1
  294. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  295. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  296. package/src/core/codemirror/ai/resources.ts +1 -1
  297. package/src/core/codemirror/cells/__tests__/extensions.test.ts +42 -1
  298. package/src/core/codemirror/cells/extensions.ts +21 -3
  299. package/src/core/codemirror/format.ts +6 -5
  300. package/src/core/codemirror/keymaps/vim.ts +2 -6
  301. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  302. package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
  303. package/src/core/codemirror/language/cell-code.ts +114 -0
  304. package/src/core/codemirror/language/extension.ts +52 -35
  305. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  306. package/src/core/codemirror/language/languages/python.ts +16 -10
  307. package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
  308. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  309. package/src/core/codemirror/language/types.ts +7 -7
  310. package/src/core/codemirror/language/utils.ts +9 -39
  311. package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
  312. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  313. package/src/core/codemirror/readonly/extension.ts +2 -2
  314. package/src/core/codemirror/rtc/extension.ts +24 -13
  315. package/src/core/codemirror/rtc/loro/awareness.ts +34 -19
  316. package/src/core/codemirror/rtc/loro/sync.ts +1 -0
  317. package/src/core/codemirror/utils.ts +1 -0
  318. package/src/core/config/__tests__/config-schema.test.ts +5 -3
  319. package/src/core/config/config-schema.ts +3 -0
  320. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  321. package/src/core/datasets/data-source-discovery.ts +4 -6
  322. package/src/core/edit-app.tsx +13 -9
  323. package/src/core/errors/error-entries.ts +3 -0
  324. package/src/core/export/hooks.ts +1 -1
  325. package/src/core/export/layout.ts +2 -2
  326. package/src/core/hotkeys/actions.ts +2 -4
  327. package/src/core/islands/__tests__/bootstrap.test.ts +73 -43
  328. package/src/core/islands/__tests__/bridge.test.ts +72 -25
  329. package/src/core/islands/bootstrap.ts +46 -53
  330. package/src/core/islands/bridge.ts +74 -21
  331. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  332. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  333. package/src/core/islands/worker/controller.ts +4 -10
  334. package/src/core/islands/worker/worker.tsx +33 -33
  335. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  336. package/src/core/kernel/__tests__/handlers.test.ts +7 -153
  337. package/src/core/kernel/handlers.ts +18 -59
  338. package/src/core/network/__tests__/connection.test.ts +1 -1
  339. package/src/core/network/connection-notice.ts +1 -1
  340. package/src/core/network/connection.ts +5 -3
  341. package/src/core/network/requests-lazy.ts +1 -2
  342. package/src/core/network/requests-network.ts +0 -9
  343. package/src/core/network/requests-static.ts +0 -1
  344. package/src/core/network/requests-toasting.tsx +0 -1
  345. package/src/core/network/types.ts +0 -5
  346. package/src/core/network/useConnectionNotice.ts +8 -2
  347. package/src/core/notebook/attachments.ts +38 -0
  348. package/src/core/notebook/document/__tests__/codemirror.test.ts +547 -0
  349. package/src/core/notebook/document/__tests__/draft.test.ts +322 -0
  350. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  351. package/src/core/notebook/document/__tests__/hold.test.ts +88 -0
  352. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  353. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  354. package/src/core/notebook/document/__tests__/model.test.ts +247 -0
  355. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  356. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  357. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  358. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  359. package/src/core/notebook/document/__tests__/state.test.ts +438 -0
  360. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  361. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  362. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  363. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  364. package/src/core/notebook/document/__tests__/user.ts +61 -0
  365. package/src/core/notebook/document/codemirror.ts +216 -0
  366. package/src/core/notebook/document/draft.ts +472 -0
  367. package/src/core/notebook/document/hooks.tsx +118 -0
  368. package/src/core/notebook/document/index.ts +23 -0
  369. package/src/core/notebook/document/model.ts +105 -0
  370. package/src/core/notebook/document/select.ts +41 -0
  371. package/src/core/notebook/document/state.ts +374 -0
  372. package/src/core/notebook/document/sync.ts +418 -0
  373. package/src/core/notebook/index.ts +18 -0
  374. package/src/core/notebook/replica/AGENTS.md +11 -0
  375. package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
  376. package/src/core/notebook/replica/__tests__/document.test.ts +126 -0
  377. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  378. package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
  379. package/src/core/notebook/replica/backend.ts +19 -0
  380. package/src/core/notebook/replica/connection.ts +42 -0
  381. package/src/core/notebook/replica/index.ts +13 -0
  382. package/src/core/notebook/replica/replica.ts +286 -0
  383. package/src/core/notebook/replica/resources/attachments.ts +22 -0
  384. package/src/core/notebook/replica/resources/document.ts +101 -0
  385. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  386. package/src/core/packages/useSandboxController.ts +1 -1
  387. package/src/core/run-app.tsx +48 -51
  388. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  389. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  390. package/src/core/runtime/__tests__/runtime.test.ts +32 -58
  391. package/src/core/runtime/adapter.ts +1 -1
  392. package/src/core/runtime/config.ts +2 -2
  393. package/src/core/runtime/runtime.ts +38 -42
  394. package/src/core/runtime/types.ts +0 -2
  395. package/src/core/saving/filename.ts +1 -1
  396. package/src/core/saving/save-component.tsx +10 -4
  397. package/src/core/saving/useAutoSave.ts +1 -1
  398. package/src/core/session/__tests__/backend.test.ts +235 -0
  399. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +183 -0
  400. package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +663 -0
  401. package/src/core/session/active-notebook.ts +11 -0
  402. package/src/core/session/backend.ts +125 -0
  403. package/src/core/{websocket → session}/types.ts +2 -2
  404. package/src/core/session/useNotebookReplica.ts +72 -0
  405. package/src/core/{websocket → session}/useNotebookSession.tsx +70 -68
  406. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  407. package/src/core/state/jotai.ts +1 -1
  408. package/src/core/static/__tests__/files.test.ts +38 -10
  409. package/src/core/static/files.ts +2 -0
  410. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  411. package/src/core/transports/__tests__/server.test.ts +408 -0
  412. package/src/core/transports/__tests__/static.test.ts +175 -0
  413. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  414. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  415. package/src/core/transports/server.ts +152 -0
  416. package/src/core/transports/static.ts +84 -0
  417. package/src/core/transports/wasm.ts +97 -0
  418. package/src/core/wasm/__tests__/bridge.test.ts +213 -50
  419. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  420. package/src/core/wasm/bridge.ts +75 -53
  421. package/src/core/wasm/rpc.ts +15 -3
  422. package/src/core/wasm/store.ts +3 -3
  423. package/src/core/wasm/worker/bootstrap.ts +55 -51
  424. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  425. package/src/core/wasm/worker/save-worker.ts +9 -10
  426. package/src/core/wasm/worker/types.ts +29 -18
  427. package/src/core/wasm/worker/worker.ts +88 -44
  428. package/src/css/globals.css +10 -0
  429. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  430. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  431. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  432. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  433. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  434. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  435. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  436. package/src/hooks/useAsyncData.ts +3 -3
  437. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  438. package/src/hooks/useDebounce.ts +6 -10
  439. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  440. package/src/hooks/useDelayElapsed.ts +14 -10
  441. package/src/hooks/useElapsedTime.ts +3 -3
  442. package/src/hooks/useEventListener.ts +1 -2
  443. package/src/hooks/useInputHistory.ts +4 -7
  444. package/src/hooks/useInternalStateWithSync.ts +6 -6
  445. package/src/hooks/useResizeObserver.ts +4 -7
  446. package/src/hooks/useScript.ts +67 -70
  447. package/src/hooks/useStateForKey.ts +93 -0
  448. package/src/mount.tsx +1 -5
  449. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  450. package/src/plugins/core/registerReactComponent.tsx +1 -1
  451. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  452. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  453. package/src/plugins/impl/DataTablePlugin.tsx +69 -37
  454. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  455. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  456. package/src/plugins/impl/FormPlugin.tsx +1 -1
  457. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  458. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  459. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  460. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
  461. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  462. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  463. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  464. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  465. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  466. package/src/plugins/impl/anywidget/model.ts +3 -1
  467. package/src/plugins/impl/anywidget/registry.ts +18 -14
  468. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  469. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  470. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  471. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  472. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  473. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  474. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  475. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  476. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  477. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  478. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  479. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  480. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  481. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  482. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  483. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  484. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  485. package/src/plugins/impl/panel/utils.ts +17 -0
  486. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  487. package/src/plugins/impl/plotly/selection.ts +25 -19
  488. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  489. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  490. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  491. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  492. package/src/stories/button.stories.tsx +1 -0
  493. package/src/stories/cell.stories.tsx +1 -1
  494. package/src/stories/data-table.stories.tsx +31 -0
  495. package/src/stories/editor.stories.tsx +24 -17
  496. package/src/stories/form-wrapper.stories.tsx +2 -2
  497. package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
  498. package/src/stories/runtime-story.tsx +1 -1
  499. package/src/stories/select.stories.tsx +2 -2
  500. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  501. package/src/utils/__tests__/arrays.test.ts +35 -0
  502. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  503. package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +29 -0
  504. package/src/utils/__tests__/numbers.test.ts +105 -1
  505. package/src/utils/__tests__/objects.test.ts +21 -0
  506. package/src/utils/arrays.ts +11 -2
  507. package/src/utils/blob.ts +1 -1
  508. package/src/utils/createReducer.ts +53 -26
  509. package/src/utils/maps.ts +0 -3
  510. package/src/utils/numbers.ts +79 -18
  511. package/src/utils/objects.ts +4 -9
  512. package/src/utils/once.ts +19 -19
  513. package/src/utils/tracer.ts +9 -5
  514. package/src/utils/zod-utils.ts +1 -3
  515. package/dist/any-language-editor-DZ_YTVus.js +0 -76
  516. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  517. package/dist/assets/worker-HPY9fbhz.js +0 -114
  518. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  519. package/dist/precisionRound-DMIVQrt2.js +0 -97
  520. package/src/core/attachments/state.ts +0 -21
  521. package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
  522. package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
  523. package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
  524. package/src/core/cells/document-changes.ts +0 -944
  525. package/src/core/host/AGENTS.md +0 -6
  526. package/src/core/host/__tests__/events.test.ts +0 -46
  527. package/src/core/host/__tests__/notebook-client.test.ts +0 -191
  528. package/src/core/host/__tests__/protocol.test.ts +0 -214
  529. package/src/core/host/connection.ts +0 -81
  530. package/src/core/host/events.ts +0 -60
  531. package/src/core/host/notebook-client.ts +0 -226
  532. package/src/core/host/protocol.ts +0 -1943
  533. package/src/core/state/__tests__/jotai.test.ts +0 -25
  534. package/src/core/wasm/worker/message-buffer.ts +0 -33
  535. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  536. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -140
  537. package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +0 -883
  538. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  539. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  540. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  541. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  542. package/src/core/websocket/transports/basic.ts +0 -102
  543. package/src/core/websocket/transports/create.ts +0 -31
  544. package/src/core/websocket/transports/sse.ts +0 -308
  545. package/src/core/websocket/transports/transport.ts +0 -50
  546. package/src/core/websocket/transports/ws.ts +0 -98
  547. package/src/core/websocket/useNotebookClient.ts +0 -80
  548. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  549. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -0,0 +1,125 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ /** The backend the editor follows, chosen once for its mode. */
4
+
5
+ import { NotebookClient, StreamStopped } from "@marimo-team/client";
6
+ import type { NotebookId } from "@marimo-team/client/protocol";
7
+ import type { NotebookBackend } from "../notebook/replica";
8
+ import { PyodideBridge } from "../wasm/bridge";
9
+ import { isWasm } from "../wasm/utils";
10
+ import { sessionSse, websocket, withHeaders } from "../transports/server";
11
+ import { idle } from "../transports/static";
12
+
13
+ /** How the editor follows its notebook. */
14
+ export interface EditorBackendOptions {
15
+ static: boolean;
16
+ transportType: "websocket" | "sse";
17
+ /** The session route, read before each connection. */
18
+ url: () => string;
19
+ /** The runtime's headers, read before each request. */
20
+ headers: () => Record<string, string>;
21
+ /** The host URL of a notebook the stream reported. */
22
+ notebookUrl: (notebookId: NotebookId) => URL;
23
+ /** Wait until the host can accept the first connection. */
24
+ waitUntilReady: () => Promise<void>;
25
+ /** Whether the host is reachable before an explicit reconnect. */
26
+ checkHealth: () => Promise<boolean>;
27
+ }
28
+
29
+ /**
30
+ * Read the session route once the host has started.
31
+ *
32
+ * Every connection waits for the same startup. Once it settles, even by
33
+ * giving up, connections read the route directly. An explicit reconnect
34
+ * checks the host's health instead.
35
+ */
36
+ function afterStartup({
37
+ url,
38
+ waitUntilReady,
39
+ }: Pick<EditorBackendOptions, "url" | "waitUntilReady">) {
40
+ let startup: Promise<void> | undefined;
41
+ let settled = false;
42
+ return async () => {
43
+ if (!settled) {
44
+ startup ??= waitUntilReady().finally(() => {
45
+ settled = true;
46
+ });
47
+ try {
48
+ await startup;
49
+ } catch (error) {
50
+ throw new StreamStopped("Healthy connection never made", {
51
+ cause: error,
52
+ });
53
+ }
54
+ }
55
+ return url();
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Follow the notebook running in the WASM worker.
61
+ *
62
+ * The worker's backend exists once the worker has started, so the first
63
+ * connection creates it. Commands are only for a notebook its stream reported.
64
+ */
65
+ function wasm(): NotebookBackend {
66
+ let backend: Promise<NotebookBackend> | undefined;
67
+ let started: NotebookBackend | undefined;
68
+ return {
69
+ transport: async (attempt, handlers) => {
70
+ backend ??= PyodideBridge.INSTANCE.createNotebookBackend();
71
+ try {
72
+ started = await backend;
73
+ } catch (error) {
74
+ throw new StreamStopped("The WASM notebook did not start", {
75
+ cause: error,
76
+ });
77
+ }
78
+ return started.transport(attempt, handlers);
79
+ },
80
+ notebook: (id) => {
81
+ if (started === undefined) {
82
+ throw new Error("The WASM notebook has not started");
83
+ }
84
+ return started.notebook(id);
85
+ },
86
+ };
87
+ }
88
+
89
+ /** Commands for a notebook the editor cannot change through its backend. */
90
+ function uneditable(): ReturnType<NotebookBackend["notebook"]> {
91
+ const unsupported: NotebookClient["save"] = async () => ({
92
+ ok: false,
93
+ status: 501,
94
+ problem: {
95
+ type: "tag:marimo.io,2026:host/unsupported-operation",
96
+ title: "Document mutations are unavailable on this connection",
97
+ status: 501,
98
+ },
99
+ });
100
+ return { edit: () => unsupported(), save: unsupported };
101
+ }
102
+
103
+ /** Choose the backend for the editor's notebook. */
104
+ export function createEditorBackend(
105
+ options: EditorBackendOptions,
106
+ ): NotebookBackend {
107
+ if (options.static) {
108
+ return { transport: idle, notebook: uneditable };
109
+ }
110
+ if (isWasm()) {
111
+ return wasm();
112
+ }
113
+ const url = afterStartup(options);
114
+ return {
115
+ transport:
116
+ options.transportType === "sse"
117
+ ? sessionSse(url, options.headers)
118
+ : websocket(url),
119
+ notebook: (id) =>
120
+ new NotebookClient(options.notebookUrl(id), {
121
+ fetch: withHeaders(options.headers),
122
+ }),
123
+ checkHealth: options.checkHealth,
124
+ };
125
+ }
@@ -1,12 +1,12 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import type { ConnectionStatus as HostConnectionStatus } from "../host/connection";
3
+ import type { ConnectionStatus as HostConnectionStatus } from "../notebook/replica";
4
4
  import type { NotificationMessageData } from "../kernel/messages";
5
5
 
6
6
  export {
7
7
  ConnectionState,
8
8
  ConnectionClosedReason as WebSocketClosedReason,
9
- } from "../host/connection";
9
+ } from "../notebook/replica";
10
10
 
11
11
  export type ConnectionPhase =
12
12
  | NotificationMessageData<"startup-progress">["phase"]
@@ -0,0 +1,72 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ /** The editor session's replica, following its backend while mounted. */
4
+
5
+ import { useStore } from "jotai";
6
+ import { useEffect, useMemo } from "react";
7
+ import useEvent from "react-use-event-hook";
8
+ import type {
9
+ NotificationMessage,
10
+ NotificationPayload,
11
+ } from "../kernel/messages";
12
+ import {
13
+ createNotebookReplica,
14
+ type NotebookReplica,
15
+ } from "../notebook/replica";
16
+ import { activeNotebookReplicaAtom } from "./active-notebook";
17
+ import { createEditorBackend, type EditorBackendOptions } from "./backend";
18
+
19
+ type Options = EditorBackendOptions & {
20
+ onNotification: (notification: NotificationPayload) => void;
21
+ };
22
+
23
+ export function useNotebookReplica(options: Options): NotebookReplica {
24
+ const store = useStore();
25
+ const { static: isStatic, transportType } = options;
26
+ const replica = useMemo(() => createNotebookReplica(store), [store]);
27
+ const url = useEvent(options.url);
28
+ const headers = useEvent(options.headers);
29
+ const notebookUrl = useEvent(options.notebookUrl);
30
+ const waitUntilReady = useEvent(options.waitUntilReady);
31
+ const checkHealth = useEvent(options.checkHealth);
32
+ const onNotification = useEvent(options.onNotification);
33
+ // Opens nothing until the replica follows it.
34
+ const backend = useMemo(
35
+ () =>
36
+ createEditorBackend({
37
+ static: isStatic,
38
+ transportType,
39
+ url,
40
+ headers,
41
+ notebookUrl,
42
+ waitUntilReady,
43
+ checkHealth,
44
+ }),
45
+ [
46
+ isStatic,
47
+ transportType,
48
+ url,
49
+ headers,
50
+ notebookUrl,
51
+ waitUntilReady,
52
+ checkHealth,
53
+ ],
54
+ );
55
+
56
+ useEffect(() => {
57
+ store.set(activeNotebookReplicaAtom, replica);
58
+ const disconnect = replica.connect(backend, {
59
+ // The host validates the envelope, not the native notification contents.
60
+ onNotification: (notification) =>
61
+ onNotification({ data: notification as NotificationMessage }),
62
+ });
63
+ return () => {
64
+ disconnect();
65
+ if (store.get(activeNotebookReplicaAtom) === replica) {
66
+ store.set(activeNotebookReplicaAtom, null);
67
+ }
68
+ };
69
+ }, [replica, backend, store, onNotification]);
70
+
71
+ return replica;
72
+ }
@@ -2,18 +2,15 @@
2
2
 
3
3
  import { invalidatePackageData } from "@/core/packages/package-data";
4
4
  import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
5
- import { useLayoutEffect } from "react";
5
+ import { useEffect, useLayoutEffect, useMemo } from "react";
6
6
  import { useErrorBoundary } from "react-error-boundary";
7
7
  import { toast } from "@/components/ui/use-toast";
8
- import { attachmentsAtom } from "@/core/attachments/state";
9
- import { getNotebook, useCellActions } from "@/core/cells/cells";
10
- import { applyTransactionChanges } from "@/core/cells/document-changes";
8
+ import { getNotebook, notebookAtom, useCellActions } from "@/core/cells/cells";
9
+ import { followDocument } from "@/core/cells/document";
11
10
  import { AUTOCOMPLETER } from "@/core/codemirror/completion/Autocompleter";
12
- import type {
13
- NotificationMessageData,
14
- NotificationPayload,
15
- } from "@/core/kernel/messages";
16
- import { useNotebookClient } from "@/core/websocket/useNotebookClient";
11
+ import { createDocumentModel } from "@/core/notebook/document";
12
+ import type { NotificationPayload } from "@/core/kernel/messages";
13
+ import { useNotebookReplica } from "@/core/session/useNotebookReplica";
17
14
  import { renderHTML } from "@/plugins/core/RenderHTML";
18
15
  import {
19
16
  handleWidgetMessage,
@@ -26,14 +23,13 @@ import { Logger } from "@/utils/Logger";
26
23
  import { reloadSafe } from "@/utils/reload-safe";
27
24
  import { useAlertActions } from "../alerts/state";
28
25
  import { cacheInfoAtom } from "../cache/requests";
29
- import { SCRATCH_CELL_ID } from "../cells/ids";
30
26
  import { useRunsActions } from "../cells/runs";
31
27
  import { focusAndScrollCellOutputIntoView } from "../cells/scrollCellIntoView";
32
28
  import {
33
29
  resyncBreakpoints,
34
30
  setActiveLine,
35
31
  } from "../codemirror/cells/debugger-state";
36
- import type { CellData } from "../cells/types";
32
+ import { notebookCells } from "../cells/utils";
37
33
  import { capabilitiesAtom } from "../config/capabilities";
38
34
  import { connectionTransportTypeAtom, useSetAppConfig } from "../config/config";
39
35
  import { useDataSourceActions } from "../datasets/data-source-connections";
@@ -66,7 +62,7 @@ import { type LayoutState, useLayoutActions } from "../layout/state";
66
62
  import { kioskModeAtom } from "../mode";
67
63
  import { connectionAtom, startupProgressAtom } from "../network/connection";
68
64
  import type { RequestId } from "../network/DeferredRequestRegistry";
69
- import { runtimeConfigAtom, useRuntimeManager } from "../runtime/config";
65
+ import { useRuntimeManager } from "../runtime/config";
70
66
  import { SECRETS_REGISTRY } from "../secrets/request-registry";
71
67
  import { isStaticNotebook } from "../static/static-state";
72
68
  import {
@@ -76,43 +72,26 @@ import {
76
72
  import { useStorageActions } from "../storage/state";
77
73
  import { useVariablesActions } from "../variables/state";
78
74
  import type { VariableName } from "../variables/types";
79
- import { isWasm } from "../wasm/utils";
75
+ import { activeDocumentModelAtom } from "./active-notebook";
80
76
  import { WebSocketClosedReason, ConnectionState } from "./types";
81
77
 
82
- const SUPPORTS_LAZY_KERNELS = true;
83
-
84
- function getExistingCells(): CellData[] | undefined {
85
- if (!SUPPORTS_LAZY_KERNELS) {
86
- return undefined;
87
- }
88
-
89
- // Remove scratch pad
90
- return Object.values(getNotebook().cellData).filter(
91
- (cell) => cell.id !== SCRATCH_CELL_ID,
92
- );
93
- }
94
-
95
78
  /** Coordinate session startup and apply notifications to the editor. */
96
79
  export function useNotebookSession(opts: {
97
80
  sessionId: SessionId;
98
81
  autoInstantiate: boolean;
99
- setCells: (cells: CellData[], layout: LayoutState) => void;
82
+ /** Called with the layout the kernel reported, after its cells are ready. */
83
+ onKernelReady?: (layout: LayoutState) => void;
100
84
  }) {
101
- const { autoInstantiate, sessionId, setCells } = opts;
85
+ const { autoInstantiate, sessionId, onKernelReady } = opts;
102
86
  const { showBoundary } = useErrorBoundary();
87
+ const store = useStore();
103
88
 
104
- const { handleCellMessage } = useCellActions();
105
- const actionsWithoutMiddleware = useCellActions({ skipMiddleware: true });
106
-
107
- const handleDocumentTransaction = (
108
- transaction: NotificationMessageData<"notebook-document-transaction">["transaction"],
109
- ) => {
110
- applyTransactionChanges(
111
- transaction.changes,
112
- actionsWithoutMiddleware,
113
- () => getNotebook().cellIds.inOrderIds,
114
- );
115
- };
89
+ const {
90
+ handleCellMessage,
91
+ reconcileDocument,
92
+ setLastRun,
93
+ resetCellRuntimes,
94
+ } = useCellActions();
116
95
  const { addCellNotification } = useRunsActions();
117
96
  const setKernelState = useSetAtom(kernelStateAtom);
118
97
  const setInitialRunCompleted = useSetAtom(initialRunCompletedAtom);
@@ -136,11 +115,9 @@ export function useNotebookSession(opts: {
136
115
  const setStableSessionId = useSetAtom(stableSessionIdAtom);
137
116
  const setCapabilities = useSetAtom(capabilitiesAtom);
138
117
  const runtimeManager = useRuntimeManager();
139
- const { notebookId } = useAtomValue(runtimeConfigAtom);
140
118
  const transportType = useAtomValue(connectionTransportTypeAtom);
141
119
  const setCacheInfo = useSetAtom(cacheInfoAtom);
142
120
  const setKernelStartupError = useSetAtom(kernelStartupErrorAtom);
143
- const setAttachments = useSetAtom(attachmentsAtom);
144
121
  const {
145
122
  setNamespaces: setStorageNamespaces,
146
123
  filterFromVariables: filterStorageFromVariables,
@@ -148,9 +125,6 @@ export function useNotebookSession(opts: {
148
125
 
149
126
  const handleNotification = (msg: NotificationPayload) => {
150
127
  switch (msg.data.op) {
151
- case "attachments":
152
- setAttachments(msg.data.attachments);
153
- return;
154
128
  case "reload":
155
129
  reloadSafe();
156
130
  return;
@@ -172,20 +146,19 @@ export function useNotebookSession(opts: {
172
146
  setInitialRunCompleted(
173
147
  Boolean(msg.data.resumed || msg.data.auto_instantiated),
174
148
  );
175
- const existingCells = getExistingCells();
176
-
177
- handleKernelReady(msg.data, {
149
+ const layout = handleKernelReady(msg.data, {
178
150
  autoInstantiate,
179
- setCells,
151
+ cells: notebookCells(store.get(notebookAtom)),
152
+ setLastRun,
153
+ resetCellRuntimes,
180
154
  setLayoutData,
181
155
  setAppConfig,
182
156
  setCapabilities,
183
157
  setKernelState,
184
158
  onError: showBoundary,
185
- existingCells,
186
159
  });
160
+ onKernelReady?.(layout);
187
161
  if (!msg.data.resumed) {
188
- setAttachments([]);
189
162
  // A freshly started kernel may expose a different environment
190
163
  // (e.g. new env vars); re-run discovery instead of reusing stale
191
164
  // suggestions from the previous kernel instance.
@@ -271,13 +244,18 @@ export function useNotebookSession(opts: {
271
244
  filterStorageFromVariables(variableNames);
272
245
  return;
273
246
  case "variable-values":
274
- setMetadata(
275
- msg.data.variables.map((v) => ({
247
+ setMetadata([
248
+ ...(msg.data.removed ?? []).map((v) => ({
249
+ name: v.name as VariableName,
250
+ dataType: undefined,
251
+ value: undefined,
252
+ })),
253
+ ...msg.data.variables.map((v) => ({
276
254
  name: v.name as VariableName,
277
255
  dataType: v.datatype,
278
256
  value: v.value,
279
257
  })),
280
- );
258
+ ]);
281
259
  return;
282
260
  case "alert":
283
261
  toast({
@@ -398,7 +376,7 @@ export function useNotebookSession(opts: {
398
376
  );
399
377
  return;
400
378
  case "notebook-document-transaction":
401
- handleDocumentTransaction(msg.data.transaction);
379
+ // Edits reach the notebook through the host document.
402
380
  return;
403
381
  case "consumer-capabilities":
404
382
  setKioskMode(!msg.data.consumer_capabilities.edit);
@@ -408,7 +386,6 @@ export function useNotebookSession(opts: {
408
386
  }
409
387
  };
410
388
 
411
- const store = useStore();
412
389
  const onMessageError = (error: unknown) => {
413
390
  toast({
414
391
  title: "Failed to handle message",
@@ -416,25 +393,23 @@ export function useNotebookSession(opts: {
416
393
  variant: "danger",
417
394
  });
418
395
  };
419
- const notebook = useNotebookClient({
420
- sessionId,
396
+ const replica = useNotebookReplica({
421
397
  static: isStaticNotebook(),
422
398
  transportType,
423
- messageFormat:
424
- notebookId && transportType === "websocket" ? "host" : "session",
425
399
  url: () =>
426
400
  transportType === "sse"
427
401
  ? runtimeManager.getSseURL(sessionId).toString()
428
402
  : runtimeManager.getWsURL(sessionId).toString(),
429
403
  // SSE uses headers for auth. WebSockets carry the token in the URL.
430
404
  headers: () => runtimeManager.headers(),
405
+ notebookUrl: (notebookId) => runtimeManager.getNotebookURL(notebookId),
406
+ // Only the host's transports read the URL, so static and WASM never wait.
431
407
  waitUntilReady: async () => {
432
- if (!isStaticNotebook() && !isWasm() && !runtimeManager.isSameOrigin) {
408
+ if (!runtimeManager.isSameOrigin) {
433
409
  await runtimeManager.waitForHealthy();
434
410
  }
435
411
  },
436
412
  checkHealth: () => runtimeManager.reconcileFromHealth(),
437
- onMessageError,
438
413
  onNotification: (notification) => {
439
414
  try {
440
415
  handleNotification(notification);
@@ -445,14 +420,42 @@ export function useNotebookSession(opts: {
445
420
  },
446
421
  });
447
422
 
423
+ const documentModel = useMemo(
424
+ () =>
425
+ createDocumentModel({
426
+ store,
427
+ documentAtom: replica.documentAtom,
428
+ backendAtom: replica.backendAtom,
429
+ }),
430
+ [store, replica],
431
+ );
432
+ // Edits outlive reconnects and end with the session. The notebook's cells
433
+ // follow the document for as long as the session is mounted.
434
+ useEffect(() => {
435
+ const controller = new AbortController();
436
+ documentModel.start({ signal: controller.signal });
437
+ store.set(activeDocumentModelAtom, documentModel);
438
+ followDocument({
439
+ store,
440
+ model: documentModel,
441
+ reconcile: reconcileDocument,
442
+ signal: controller.signal,
443
+ });
444
+ return () => {
445
+ controller.abort();
446
+ if (store.get(activeDocumentModelAtom) === documentModel) {
447
+ store.set(activeDocumentModelAtom, null);
448
+ }
449
+ };
450
+ }, [documentModel, store, reconcileDocument]);
451
+
448
452
  // Subscribe before passive connection setup: static/WASM transports can emit synchronously.
449
453
  useLayoutEffect(() => {
450
454
  const updateConnection = () => {
451
- const status = store.get(notebook.connectionAtom);
455
+ const status = store.get(replica.connectionAtom);
452
456
  if (status.state === ConnectionState.NOT_STARTED) {
453
457
  return;
454
458
  }
455
- setAttachments([]);
456
459
  if (status.state === ConnectionState.OPEN) {
457
460
  updateStartupProgress(null);
458
461
  return; // kernel-ready, not the socket, establishes session readiness.
@@ -480,17 +483,16 @@ export function useNotebookSession(opts: {
480
483
  return status;
481
484
  });
482
485
  };
483
- const unsubscribe = store.sub(notebook.connectionAtom, updateConnection);
486
+ const unsubscribe = store.sub(replica.connectionAtom, updateConnection);
484
487
  updateConnection();
485
488
  return unsubscribe;
486
489
  }, [
487
- notebook,
490
+ replica,
488
491
  store,
489
492
  setConnection,
490
- setAttachments,
491
493
  setKernelStartupError,
492
494
  updateStartupProgress,
493
495
  ]);
494
496
 
495
- return { notebook, connection, reconnect: notebook.reconnect };
497
+ return { replica, documentModel, connection, reconnect: replica.reconnect };
496
498
  }
@@ -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
+ });
@@ -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;
@@ -654,19 +654,47 @@ describe("error handling and edge cases", () => {
654
654
  unpatch();
655
655
  });
656
656
 
657
- it("should handle malformed URLs gracefully", async () => {
658
- const virtualFiles = {};
659
- const unpatch = patchFetch(virtualFiles);
657
+ it("forwards relative URLs and options to the original fetch", async () => {
658
+ const response = new Response("relative content");
659
+ const originalFetch = vi.spyOn(window, "fetch").mockResolvedValue(response);
660
+ const unpatch = patchFetch({});
661
+ const options = { headers: { Accept: "text/plain" } };
662
+
663
+ try {
664
+ expect(await window.fetch("relative-file.txt", options)).toBe(response);
665
+ expect(originalFetch).toHaveBeenCalledExactlyOnceWith(
666
+ "relative-file.txt",
667
+ options,
668
+ );
669
+ } finally {
670
+ unpatch();
671
+ originalFetch.mockRestore();
672
+ }
673
+ });
660
674
 
661
- // Mock Logger.error to avoid test output
675
+ it("preserves the original fetch rejection for malformed URLs", async () => {
676
+ const error = new TypeError("Invalid URL");
677
+ const originalFetch = vi.spyOn(window, "fetch").mockRejectedValue(error);
662
678
  const loggerSpy = vi
663
679
  .spyOn(console, "error")
664
680
  .mockImplementation(Functions.NOOP);
665
-
666
- // This should catch the error and fallback to original fetch
667
- await window.fetch("not-a-valid-url").catch(() => undefined);
668
-
669
- unpatch();
670
- loggerSpy.mockRestore();
681
+ const unpatch = patchFetch({});
682
+ const options = { headers: { Accept: "text/plain" } };
683
+
684
+ try {
685
+ await expect(window.fetch("http://[", options)).rejects.toBe(error);
686
+ expect(originalFetch).toHaveBeenCalledExactlyOnceWith(
687
+ "http://[",
688
+ options,
689
+ );
690
+ expect(loggerSpy).toHaveBeenCalledWith(
691
+ "Error parsing URL",
692
+ expect.any(TypeError),
693
+ );
694
+ } finally {
695
+ unpatch();
696
+ originalFetch.mockRestore();
697
+ loggerSpy.mockRestore();
698
+ }
671
699
  });
672
700
  });
@@ -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
  */