@marimo-team/islands 0.24.3-dev9 → 0.25.1-dev1

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 (440) hide show
  1. package/dist/{ConnectedDataExplorerComponent-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
  2. package/dist/ErrorBoundary-pXXIvlr3.js +200 -0
  3. package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-Dlm5aWnH.js} +4 -4
  4. package/dist/{Plot-C-9MQeGP.js → Plot-CTyjbQDT.js} +21032 -20666
  5. package/dist/_baseMerge-BiGRwuqv.js +165 -0
  6. package/dist/{abnfDiagram-N423BO3Z-CQKwzX8t.js → abnfDiagram-VCTEODGH-CpN0FRda.js} +17 -18
  7. package/dist/{any-language-editor-DmQ7dyCx.js → any-language-editor-CycIVIeP.js} +17 -17
  8. package/dist/arc-7ra3iNdN.js +81 -0
  9. package/dist/architecture-7GRP2DOG-BWLylgiA.js +3 -0
  10. package/dist/{architectureDiagram-T3A2C74G-CncrDpfa.js → architectureDiagram-5GKGNRK7-DDyj5SRB.js} +25 -25
  11. package/dist/assets/__vite-browser-external-C9iR87Zl.js +1 -0
  12. package/dist/assets/worker-D7hWi02M.js +109 -0
  13. package/dist/blockDiagram-I7D4REHJ-BbXEXJRu.js +1922 -0
  14. package/dist/{button-CKBkqR9J.js → button-DdXAm8iz.js} +5 -5
  15. package/dist/{c4Diagram-5PPSVZJV-DarUk3Yq.js → c4Diagram-7LVT6UL2-DcLsbQmR.js} +696 -668
  16. package/dist/{capabilities-CMBBJTcc.js → capabilities-B3ce_GNu.js} +1 -1
  17. package/dist/{html-to-image-BtFMe_Nq.js → cells-DYIkSxs6.js} +6757 -10137
  18. package/dist/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
  19. package/dist/chat-ui-BXj3uYjy.js +5786 -0
  20. package/dist/{check-CHig47QV.js → check-B7cIK6gb.js} +1 -1
  21. package/dist/{chunk-2Q5K7J3B-BMuJl2jB.js → chunk-2Q5K7J3B-BMkUkeuy.js} +2 -2
  22. package/dist/chunk-4HAMMTFA-D2qv8E0X.js +4188 -0
  23. package/dist/{chunk-5VM5RSS4-Bcq0ftdy.js → chunk-5VM5RSS4-DKsmPCL6.js} +2 -2
  24. package/dist/{chunk-NSK5VX7P-CDTMcJB0.js → chunk-75Z2AOVW-5_HsvXwr.js} +23 -23
  25. package/dist/{chunk-I66GZJ75-BqyTCAPf.js → chunk-DU6HZSFF-BUgAHvnM.js} +21 -4
  26. package/dist/{chunk-2GRJ4B5K-DgO8Qudq.js → chunk-F27PBJKO-DHmYWZXr.js} +4 -4
  27. package/dist/{chunk-KEIR6QF5-C4KX3XYh.js → chunk-FOHPRMQF-BpYR8RqP.js} +4 -4
  28. package/dist/{chunk-WRU74C26-BpWsbiDK.js → chunk-GMAD6QVW-Czynz8aA.js} +486 -258
  29. package/dist/chunk-GVQU2GXP-yQEdulRS.js +37 -0
  30. package/dist/{chunk-5RXB4S5H-tLNUVDdO.js → chunk-IMKFNOWR-BfwTebD0.js} +11 -11
  31. package/dist/{chunk-JWPE2WC7-BJwjGUnF.js → chunk-JWPE2WC7-DJvv1t8U.js} +2 -2
  32. package/dist/chunk-L3NEJ4N5-DwRWnDDK.js +245 -0
  33. package/dist/{chunk-7Z6QIM7H-Dc18hFxH.js → chunk-OSK3NFVY-BBKU_Ign.js} +222 -144
  34. package/dist/{chunk-W5SLKNZC-DLnvpEtV.js → chunk-P2QGCYS3-C0iGU29N.js} +20 -20
  35. package/dist/{chunk-KBJHAD2P-BuqWqkcW.js → chunk-POPQ4Y6H-BCbS3Ozc.js} +4 -4
  36. package/dist/{chunk-4I5QYGJK-DpytHuZQ.js → chunk-PWAF6VOD-CTFCL0jI.js} +4 -4
  37. package/dist/{chunk-JQJVKLGR-CgqCwe8E.js → chunk-SHT3W25Y-BspJEJ5H.js} +109 -63
  38. package/dist/{chunk-6Q2QTUOP-DmTcEBMn.js → chunk-SVP7TREG-DX3rFNTe.js} +5 -5
  39. package/dist/{chunk-GF5L2VYU-B0wgCQgS.js → chunk-TICWLB2K-fVF7Uujg.js} +13 -13
  40. package/dist/{chunk-XXDRQBXY-D73H4IN0.js → chunk-XXDRQBXY-Dnl5VBqG.js} +3 -3
  41. package/dist/{chunk-Y2CYZVJY-DoegUj_e.js → chunk-Y2CYZVJY-DKKS1VyV.js} +1 -1
  42. package/dist/{chunk-5FQGJX7Z-B85XCPv6.js → chunk-YOKDWASO-DrWbKnxA.js} +6925 -5460
  43. package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +30 -0
  44. package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +30 -0
  45. package/dist/code-visibility-BC_yF09p.js +138 -0
  46. package/dist/{common-Cv-4hMa0.js → common-Dv227ygK.js} +8838 -12645
  47. package/dist/{compiler-runtime-CAH9RLw2.js → compiler-runtime-Cj8ZWiNS.js} +2 -2
  48. package/dist/copy-icon-CLdENY__.js +190 -0
  49. package/dist/{cose-bilkent-JH36ORCC-FUWHkXFX.js → cose-bilkent-JH36ORCC-_LyRKVqm.js} +2 -2
  50. package/dist/cubic-OaEBhQPK.js +1404 -0
  51. package/dist/cynefin-OW5HDTMX-obq-i80l.js +3 -0
  52. package/dist/{cynefinDiagram-MW4NZA55-BXSFK93J.js → cynefinDiagram-5FMLGOSQ-CFQrqzSX.js} +10 -10
  53. package/dist/{dagre-CGyalH38.js → dagre-BGSfXNEb.js} +678 -537
  54. package/dist/dagre-GXQ25YYZ-xHNAUTyG.js +425 -0
  55. package/dist/{data-grid-overlay-editor-DZM4BAaI.js → data-grid-overlay-editor-B-I2K7z3.js} +8 -9
  56. package/dist/{data-grid-types-BnZwWG8z.js → data-grid-types-BucVmDDp.js} +1 -1
  57. package/dist/{defaultLocale-DKaU_opG.js → defaultLocale-JI_lnoCe.js} +1 -1
  58. package/dist/{diagram-7IWD3JNH-BjfzDNvj.js → diagram-S7CK7UJ4-Bt1rPbAx.js} +40 -39
  59. package/dist/{diagram-UB23O5K3-DDg-7wLA.js → diagram-UQ7AKVKN-D1sq5FoZ.js} +10 -10
  60. package/dist/{diagram-B4RE2ZJO-CKccR9eE.js → diagram-VSXAHHWV-BKpmG23x.js} +10 -10
  61. package/dist/{diagram-Q27KOJAE-Zhz01ss7.js → diagram-VX7I27RA-BMwGFVD6.js} +21 -21
  62. package/dist/{diagram-LBJQPF4R-CJ-bOruh.js → diagram-Z3DM3KII--KLDR9Pl.js} +10 -10
  63. package/dist/dialog-CgNq6y9-.js +94 -0
  64. package/dist/{dist-dAqZAPcF.js → dist-1HDa70oE.js} +3 -3
  65. package/dist/{dist-Re9sOPOx.js → dist-9x1ZRe-e.js} +2 -2
  66. package/dist/{dist-DEeLqRlU.js → dist-B1vYLK28.js} +1 -1
  67. package/dist/{dist-C5Bn52W4.js → dist-B8D7McG3.js} +3 -3
  68. package/dist/{dist-_XvgytiS.js → dist-BHCHt1NI.js} +1 -1
  69. package/dist/{dist-CRjAdnqF.js → dist-BRxfaJgs.js} +3 -3
  70. package/dist/{dist-Byj2bV8o.js → dist-BVGtK7Ht.js} +1 -1
  71. package/dist/{dist-BIN5LKyE.js → dist-BaHjhkpZ.js} +2 -2
  72. package/dist/{dist-DVFbIwc5.js → dist-BtKIs9N-.js} +1 -1
  73. package/dist/{dist-BrQGcfQ9.js → dist-C2KzV-vf.js} +2 -2
  74. package/dist/{dist-DJFiGP2k.js → dist-C2wDlYdD.js} +2 -2
  75. package/dist/{dist-BVRM2y1P.js → dist-C8xMLVYi.js} +2 -2
  76. package/dist/dist-CMh_W4y4.js +538 -0
  77. package/dist/{extends-BPB6_lTK.js → dist-CO1AwwG_.js} +516 -561
  78. package/dist/{dist-BzN60Z2s.js → dist-CPGxfVGX.js} +1 -1
  79. package/dist/{dist-C7v-9nUK.js → dist-Cm3iAFMD.js} +3 -3
  80. package/dist/{dist-CGAxEiaM.js → dist-Cs2FijYk.js} +2 -2
  81. package/dist/{dist-hXd65f0_.js → dist-D1PpnuZB.js} +1 -1
  82. package/dist/{dist-VdvbxG72.js → dist-DHOTQar0.js} +1 -1
  83. package/dist/{dist-DcgzXCfy.js → dist-DPcEtqmG.js} +2 -2
  84. package/dist/{dist-D4Z_qdP4.js → dist-Df0wKI0F.js} +1 -1
  85. package/dist/{dist-qhLI-SHd.js → dist-DszxuxS1.js} +2 -2
  86. package/dist/{dist-BEmkrGoQ.js → dist-Kxgjxakw.js} +1 -1
  87. package/dist/{dist-BbSMhhD2.js → dist-KzZ7WELx.js} +2 -2
  88. package/dist/{dist-jWUab2d1.js → dist-lA1Cttkb.js} +1 -1
  89. package/dist/dropdown-menu-CZgjYSAh.js +4502 -0
  90. package/dist/{ebnfDiagram-BXEA7PRR-Dm75pCAS.js → ebnfDiagram-PWID7BFC-WnG4cvSQ.js} +17 -18
  91. package/dist/{erDiagram-JOGREHBK-rVDG3VSQ.js → erDiagram-RLTQ6QDP-DhzKiYHc.js} +1037 -798
  92. package/dist/error-banner-B94dcDmP.js +391 -0
  93. package/dist/error-entries-C0NsUqXl.js +56 -0
  94. package/dist/{esm-CR1nhb1c.js → esm-BElI3qKH.js} +22 -22
  95. package/dist/{esm-C1d0g6Bv.js → esm-G4Fhsgng.js} +51 -37
  96. package/dist/{esm-CesmlDrs.js → esm-h8f7-1CJ.js} +423 -423
  97. package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +3 -0
  98. package/dist/feedback-button-D2hUXe09.js +380 -0
  99. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +16 -0
  100. package/dist/{formats-CslNOKy0.js → formats-BR5iGb4s.js} +8 -8
  101. package/dist/{ganttDiagram-PKOTCBZU-9D-LXF6P.js → ganttDiagram-EL5Y4UJY-DbzEBLbl.js} +15 -15
  102. package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +3 -0
  103. package/dist/{gitGraphDiagram-DS77QQ5N-BfpsXTLf.js → gitGraphDiagram-WWUBYQGX-BMf0iKi1.js} +10 -10
  104. package/dist/{glide-data-editor-sPZ8fUFn.js → glide-data-editor-B851uguN.js} +2143 -1910
  105. package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
  106. package/dist/globals-CmijFoIU.js +19 -0
  107. package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
  108. package/dist/html-to-image-CeYYvQNb.js +3272 -0
  109. package/dist/info-A6RAGUB7-DKoayiHY.js +3 -0
  110. package/dist/{infoDiagram-6WML65LV-DqCTXHVy.js → infoDiagram-27XIBGKW-BagtCX_5.js} +7 -7
  111. package/dist/{ishikawaDiagram-WSZJBQD7-BCUYmZ1v.js → ishikawaDiagram-5VMMS53U-DByDehYy.js} +8 -8
  112. package/dist/{journeyDiagram-NVQOT4AX-BXB6M4zN.js → journeyDiagram-3NMN7TZE-D2LcKDUO.js} +8 -8
  113. package/dist/{jsx-runtime-CpoKNRgu.js → jsx-runtime-DgDPJV9S.js} +1 -1
  114. package/dist/{kanban-definition-27J2QSJJ-CGRhrDUX.js → kanban-definition-UXKFOSKX-BxwkbBI_.js} +29 -29
  115. package/dist/katex-DFBiSucW.js +21840 -0
  116. package/dist/{label-lwzzBHUW.js → label-BJ49YTvk.js} +6 -6
  117. package/dist/{linear-D5r_1YqD.js → linear-Cnaq3Tfb.js} +4 -4
  118. package/dist/{loader-VZ__bv4g.js → loader-D2W4oM-3.js} +15 -15
  119. package/dist/main.js +8113 -13475
  120. package/dist/mermaid-DPNuhemn.js +3084 -0
  121. package/dist/mermaid-HWGCJPDP-DYCzSILp.js +2 -0
  122. package/dist/mermaid-parser.core-DxuSfYwJ.js +638 -0
  123. package/dist/{mhchem-BjwrxcV-.js → mhchem-DWCF06w9.js} +1 -1
  124. package/dist/{micromark-factory-space-DruVGzeG.js → micromark-factory-space-DGxAzmw8.js} +2 -2
  125. package/dist/{mindmap-definition-FAOFIHXS-C9gRhzZq.js → mindmap-definition-YA3MSWOX-Cgvojw3y.js} +17 -17
  126. package/dist/{node-sql-parser-DesT1xNw.js → node-sql-parser-BiZOJ-FS.js} +0 -3
  127. package/dist/{number-overlay-editor-De2CabLL.js → number-overlay-editor-BtdoxWiD.js} +5 -5
  128. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +23 -0
  129. package/dist/packet-AYTQ26CC-Yw7ajchJ.js +3 -0
  130. package/dist/{pegDiagram-VL7TDLO6-Df9IUjMD.js → pegDiagram-XKGWAZYB-DahHhYyN.js} +19 -20
  131. package/dist/{pick-SnHlmIBN.js → pick-CJeoxYOS.js} +1 -1
  132. package/dist/pie-WAS4IAKB-BKdKOAkL.js +3 -0
  133. package/dist/{pieDiagram-7S7Q4E2Y-BmRzQ8ZP.js → pieDiagram-E7YTZNPT-CCtX0oCK.js} +29 -31
  134. package/dist/{process-output-CPy0YKUe.js → process-output-BCTjlyuH.js} +7 -6
  135. package/dist/purify.es-DgKyQviY.js +805 -0
  136. package/dist/{quadrantDiagram-CIZ2JOQS-wFBvWcxS.js → quadrantDiagram-AXDQQJYC-DftINo6g.js} +5 -5
  137. package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +3 -0
  138. package/dist/railroad-74A4TZTK-DQvPSdo5.js +3 -0
  139. package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +3 -0
  140. package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +3 -0
  141. package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +3 -0
  142. package/dist/{railroadDiagram-AXF67PYL-DxbIatiN.js → railroadDiagram-O6MQD6OU-Du5NsPUb.js} +17 -18
  143. package/dist/{react-dom-C94wmq5w.js → react-dom-BUgJ-ab_.js} +3 -3
  144. package/dist/{react-DMWcHin-.js → react-ofJbxM4x.js} +2 -2
  145. package/dist/{react-vega-DSD5aT7_.js → react-vega-5AcMW8gG.js} +10012 -9369
  146. package/dist/{requirementDiagram-LRYGKXZP-X_x-Y713.js → requirementDiagram-BXWQKSXE-0pmmxL6_.js} +20 -19
  147. package/dist/{reveal-component-CVsYlb9J.js → reveal-component-DQq7NUGJ.js} +1303 -1237
  148. package/dist/{sankeyDiagram-W5VNT64P-BYJALbbm.js → sankeyDiagram-P5KCCOFB-CDKR5TJH.js} +4 -4
  149. package/dist/{select-3qHpFKF9.js → select-C6plhmZr.js} +317 -562
  150. package/dist/{sequenceDiagram-SI44F4Z6-BiPBe3Sv.js → sequenceDiagram-WJ2MYXX4-DB-ChWwU.js} +11 -11
  151. package/dist/{sizeCapture-X5ZJPWSS-BKLDeh5H.js → sizeCapture-INFHLROL-Dx5SpkQF.js} +2 -2
  152. package/dist/{spec-CutWdqo3.js → spec-CAYwFeV6.js} +4 -4
  153. package/dist/{src-C31ngt98.js → src-CA_m4ONl.js} +298 -303
  154. package/dist/{stateDiagram-OKZ733FA-B7QyNBxH.js → stateDiagram-D77RDMKH-orN6AwMx.js} +19 -20
  155. package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +30 -0
  156. package/dist/style.css +2 -2
  157. package/dist/{swimlanes-SLNWSIFB-B4f8VP3b.js → swimlanes-42K2YHIH-BkSDcqDT.js} +1501 -1591
  158. package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +30 -0
  159. package/dist/{swiper-component-C90YjhaV.js → swiper-component-IOUowglM.js} +39 -26
  160. package/dist/{time-aWGfjN8x.js → time-BieKwdYS.js} +42 -42
  161. package/dist/{timeline-definition-Z64GVDOM-Dacq_5lr.js → timeline-definition-24CTP7MA-BuqJUIRZ.js} +7 -7
  162. package/dist/{toDate-CpXBeDq0.js → toDate-WXg1yLcI.js} +7 -7
  163. package/dist/toast-DvY70eFX.js +1834 -0
  164. package/dist/tooltip-qB8NlSqV.js +1742 -0
  165. package/dist/treeView-Q6P3EWNA-DuRV97YF.js +3 -0
  166. package/dist/treemap-WGGIJYW6-AsLq-uwC.js +3 -0
  167. package/dist/use-restore-focus-D5D9xEjZ.js +5946 -0
  168. package/dist/{use-vega-container-remeasure-DUW4tRxq.js → use-vega-container-remeasure-4DwJbPWu.js} +2 -2
  169. package/dist/{useAsyncData-CH6-CgJF.js → useAsyncData-BD6AStMt.js} +3 -3
  170. package/dist/{useDateFormatter-Cp9Jdxls.js → useDateFormatter-BRTPsUK7.js} +8 -8
  171. package/dist/{useDeepCompareMemoize-JC87C_jO.js → useDeepCompareMemoize-D_HNdyvI.js} +2 -2
  172. package/dist/{useIframeCapabilities-De3C-9b4.js → useIframeCapabilities-CVtNkI3Y.js} +2 -2
  173. package/dist/{useLifecycle-B4RGlyf0.js → useLifecycle-DPgiiwwU.js} +6 -6
  174. package/dist/useNumberFormatter-BfDpa21j.js +251 -0
  175. package/dist/useTheme-DzXmYZ5V.js +904 -0
  176. package/dist/{vega-component-ovBXgp91.js → vega-component-D0QXopU8.js} +34 -34
  177. package/dist/{vega-embed-container-TJ5z5dZw.js → vega-embed-container-CbnTccZi.js} +6 -6
  178. package/dist/vega-loader.browser-D95WfUcj.js +1139 -0
  179. package/dist/{vennDiagram-T6HMQDX7-D-Rcq3Iu.js → vennDiagram-4TSXK5OY-CTUlJ2PK.js} +9 -9
  180. package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +3 -0
  181. package/dist/{wardleyDiagram-T6FBY63Y-Z-Og7_Wd.js → wardleyDiagram-VM6X3IG4-3evLUb0M.js} +10 -10
  182. package/dist/{xychartDiagram-ELKLHX3M-BDJ2dITA.js → xychartDiagram-S5SC5T6Z-DL2E3K8-.js} +248 -139
  183. package/package.json +54 -57
  184. package/src/__mocks__/notebook.ts +1 -0
  185. package/src/__mocks__/requests.ts +7 -0
  186. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
  187. package/src/__tests__/fixtures/pair-preview.ts +19 -0
  188. package/src/__tests__/mount.test.ts +18 -0
  189. package/src/components/app-config/optional-features.tsx +6 -0
  190. package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +394 -0
  191. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +272 -0
  192. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  193. package/src/components/chat/acp/agent-panel.tsx +115 -74
  194. package/src/components/chat/acp/state.ts +1 -1
  195. package/src/components/data-table/__tests__/filters.test.ts +21 -21
  196. package/src/components/data-table/charts/__tests__/spec.test.ts +5 -10
  197. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
  198. package/src/components/data-table/column-summary/chart-spec-model.tsx +1 -1
  199. package/src/components/data-table/columns.tsx +64 -67
  200. package/src/components/editor/RecoveryButton.tsx +1 -0
  201. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
  202. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +115 -0
  203. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +218 -0
  204. package/src/components/editor/actions/pair-with-agent-commands.ts +46 -9
  205. package/src/components/editor/actions/pair-with-agent-modal.tsx +49 -23
  206. package/src/components/editor/ai/add-cell-with-ai.tsx +1 -0
  207. package/src/components/editor/ai/ai-completion-editor.tsx +3 -1
  208. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +186 -0
  209. package/src/components/editor/alerts/__tests__/startup-progress.test.tsx +185 -0
  210. package/src/components/editor/alerts/connecting-alert.tsx +1 -66
  211. package/src/components/editor/alerts/connection-notice.tsx +186 -0
  212. package/src/components/editor/alerts/startup-output.tsx +173 -0
  213. package/src/components/editor/alerts/startup-progress.tsx +204 -0
  214. package/src/components/editor/app-container.tsx +9 -3
  215. package/src/components/editor/boundary/ErrorBoundary.tsx +38 -16
  216. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +311 -0
  217. package/src/components/editor/cell/__tests__/toolbar.test.tsx +73 -0
  218. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +50 -0
  219. package/src/components/editor/cell/code/cell-editor.tsx +41 -42
  220. package/src/components/editor/cell/toolbar.tsx +11 -0
  221. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +94 -0
  222. package/src/components/editor/chrome/components/feedback-button.tsx +63 -42
  223. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +164 -8
  224. package/src/components/editor/chrome/panels/__tests__/sandbox-details.test.tsx +358 -0
  225. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +168 -0
  226. package/src/components/editor/chrome/panels/packages-panel.tsx +113 -175
  227. package/src/components/editor/chrome/panels/sandbox-controller.tsx +106 -0
  228. package/src/components/editor/chrome/panels/sandbox-details-state.ts +38 -0
  229. package/src/components/editor/chrome/panels/sandbox-panel.tsx +230 -0
  230. package/src/components/editor/chrome/panels/sandbox-toggle.tsx +52 -0
  231. package/src/components/editor/chrome/wrapper/app-chrome.tsx +7 -0
  232. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -1
  233. package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
  234. package/src/components/editor/code/readonly-diff.tsx +1 -1
  235. package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +98 -98
  236. package/src/components/editor/connections/database/__tests__/as-code.test.ts +11 -5
  237. package/src/components/editor/dynamic-favicon.tsx +17 -10
  238. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +13 -11
  239. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  240. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  241. package/src/components/editor/header/__tests__/status.test.tsx +8 -20
  242. package/src/components/editor/header/filename-input.tsx +2 -0
  243. package/src/components/editor/header/status.tsx +5 -3
  244. package/src/components/editor/navigation/clipboard.ts +1 -0
  245. package/src/components/editor/notebook-cell.tsx +4 -2
  246. package/src/components/editor/output/JsonOutput.tsx +182 -632
  247. package/src/components/editor/output/Outputs.css +49 -17
  248. package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
  249. package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
  250. package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
  251. package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
  252. package/src/components/editor/output/json-output/formatting.ts +167 -0
  253. package/src/components/editor/output/json-output/pagination.ts +155 -0
  254. package/src/components/editor/output/json-output/renderers.tsx +196 -0
  255. package/src/components/editor/output/json-output/themes.ts +52 -0
  256. package/src/components/editor/package-alert.tsx +112 -66
  257. package/src/components/editor/renderers/cell-array.tsx +1 -5
  258. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +3 -7
  259. package/src/components/slides/slide-form.tsx +1 -0
  260. package/src/components/slides/slide-notes-editor.tsx +1 -0
  261. package/src/components/tracing/tracing-spec.ts +1 -1
  262. package/src/components/ui/__tests__/badge.test.ts +6 -4
  263. package/src/components/ui/use-toast.ts +8 -0
  264. package/src/core/MarimoApp.tsx +0 -2
  265. package/src/core/ai/context/providers/__tests__/error.test.ts +16 -22
  266. package/src/core/alerts/__tests__/environment.test.ts +183 -0
  267. package/src/core/alerts/__tests__/state.test.tsx +240 -0
  268. package/src/core/alerts/environment.ts +57 -0
  269. package/src/core/alerts/state.ts +155 -99
  270. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +296 -259
  271. package/src/core/cells/__tests__/apply-transaction.test.ts +34 -0
  272. package/src/core/cells/__tests__/cell.test.ts +61 -0
  273. package/src/core/cells/__tests__/cells.test.ts +182 -37
  274. package/src/core/cells/__tests__/document-changes.test.ts +39 -1
  275. package/src/core/cells/__tests__/outputs.test.tsx +117 -0
  276. package/src/core/cells/__tests__/pending-delete-service.test.tsx +4 -3
  277. package/src/core/cells/__tests__/session.test.ts +7 -0
  278. package/src/core/cells/cell.ts +9 -1
  279. package/src/core/cells/cells.ts +13 -18
  280. package/src/core/cells/document-changes.ts +11 -1
  281. package/src/core/cells/outputs.ts +66 -9
  282. package/src/core/cells/pending-delete-service.ts +12 -16
  283. package/src/core/cells/session.ts +2 -0
  284. package/src/core/cells/types.ts +2 -0
  285. package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +8 -16
  286. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  287. package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +4 -8
  288. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  289. package/src/core/codemirror/rtc/extension.ts +5 -2
  290. package/src/core/config/pair.ts +19 -0
  291. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  292. package/src/core/datasets/data-source-connections.ts +15 -10
  293. package/src/core/edit-app.tsx +8 -5
  294. package/src/core/errors/state.ts +1 -2
  295. package/src/core/export/__tests__/hooks.test.ts +1 -6
  296. package/src/core/islands/bootstrap.ts +3 -1
  297. package/src/core/islands/bridge.ts +3 -0
  298. package/src/core/islands/worker-factory.ts +2 -12
  299. package/src/core/kernel/messages.ts +2 -2
  300. package/src/core/network/__tests__/requests-network.test.ts +4 -3
  301. package/src/core/network/connection-notice.ts +117 -0
  302. package/src/core/network/connection.ts +19 -0
  303. package/src/core/network/requests-lazy.ts +3 -0
  304. package/src/core/network/requests-network.ts +12 -0
  305. package/src/core/network/requests-static.ts +3 -0
  306. package/src/core/network/requests-toasting.tsx +3 -0
  307. package/src/core/network/resolve.ts +2 -1
  308. package/src/core/network/types.ts +7 -0
  309. package/src/core/network/useConnectionNotice.ts +53 -0
  310. package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
  311. package/src/core/packages/__tests__/useSandboxController.test.tsx +246 -0
  312. package/src/core/packages/package-data.ts +35 -0
  313. package/src/core/packages/sandbox-state.ts +67 -0
  314. package/src/core/packages/toast-components.tsx +11 -0
  315. package/src/core/packages/useInstallPackage.ts +1 -1
  316. package/src/core/packages/usePackageAction.ts +51 -0
  317. package/src/core/packages/usePackageDependencies.ts +22 -0
  318. package/src/core/packages/useSandboxController.ts +208 -0
  319. package/src/core/run-app.tsx +2 -0
  320. package/src/core/static/__tests__/files.test.ts +12 -30
  321. package/src/core/wasm/__tests__/bootstrap.test.ts +63 -0
  322. package/src/core/wasm/__tests__/bridge.test.ts +13 -4
  323. package/src/core/wasm/__tests__/fs.test.ts +22 -0
  324. package/src/core/wasm/__tests__/runtime-config.test.ts +65 -0
  325. package/src/core/wasm/bridge.ts +35 -23
  326. package/src/core/wasm/rpc.ts +2 -0
  327. package/src/core/wasm/runtime-config.ts +31 -0
  328. package/src/core/wasm/worker/bootstrap.ts +21 -11
  329. package/src/core/wasm/worker/constants.ts +1 -0
  330. package/src/core/wasm/worker/fs.ts +4 -0
  331. package/src/core/wasm/worker/getController.ts +3 -1
  332. package/src/core/wasm/worker/save-worker.ts +10 -9
  333. package/src/core/wasm/worker/types.ts +6 -4
  334. package/src/core/wasm/worker/worker.ts +9 -9
  335. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +404 -3
  336. package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +8 -6
  337. package/src/core/websocket/transports/transport.ts +1 -1
  338. package/src/core/websocket/transports/ws.ts +1 -1
  339. package/src/core/websocket/types.ts +11 -1
  340. package/src/core/websocket/useMarimoKernelConnection.tsx +63 -16
  341. package/src/hooks/useDebounce.ts +2 -0
  342. package/src/mount.tsx +3 -0
  343. package/src/plugins/core/BadPlugin.tsx +3 -14
  344. package/src/plugins/core/RenderHTML.tsx +22 -2
  345. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  346. package/src/plugins/core/registerReactComponent.tsx +0 -1
  347. package/src/plugins/impl/FileBrowserPlugin.tsx +10 -4
  348. package/src/plugins/impl/FormPlugin.tsx +2 -0
  349. package/src/plugins/impl/MatrixPlugin.tsx +2 -0
  350. package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
  351. package/src/plugins/impl/SliderPlugin.tsx +2 -0
  352. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +50 -1
  353. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
  354. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  355. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +1 -1
  356. package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +15 -0
  357. package/src/plugins/impl/vega/__tests__/make-selectable.test.ts +42 -48
  358. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  359. package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
  360. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  361. package/src/stories/sandbox.stories.tsx +488 -0
  362. package/src/utils/__tests__/path.test.ts +6 -5
  363. package/src/utils/__tests__/worker.test.ts +81 -0
  364. package/src/utils/worker.ts +22 -0
  365. package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
  366. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  367. package/dist/_initCloneObject---vediN2.js +0 -95
  368. package/dist/arc-DOVLrCPd.js +0 -82
  369. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  370. package/dist/array-CApNbSU9.js +0 -6
  371. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  372. package/dist/assets/worker-DlIBfp9S.js +0 -98
  373. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  374. package/dist/chat-ui-BSwr409J.js +0 -8455
  375. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  376. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  377. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  378. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  379. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  380. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  381. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  382. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  383. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  384. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  385. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  386. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  387. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  388. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  389. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  390. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  391. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  392. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  393. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  394. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  395. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  396. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  397. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  398. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  399. package/dist/click-outside-container-D_URcm3D.js +0 -167
  400. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  401. package/dist/copy-CD7S58CY.js +0 -141
  402. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  403. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  404. package/dist/dist-3_o3T78I.js +0 -1360
  405. package/dist/dist-ABQjhuek.js +0 -64
  406. package/dist/dist-CO5R6VMi.js +0 -538
  407. package/dist/dropdown-menu-DhCfcscX.js +0 -5858
  408. package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
  409. package/dist/error-banner-CsXbEEjo.js +0 -611
  410. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  411. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  412. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  413. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  414. package/dist/line-CuKjIQa1.js +0 -34
  415. package/dist/map-BJpOfPlL.js +0 -149
  416. package/dist/math-BXtKgYah.js +0 -10
  417. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  418. package/dist/mermaid-Bi23Ibnw.js +0 -1173
  419. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  420. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  421. package/dist/path-BNHuHZP8.js +0 -87
  422. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  423. package/dist/purify.es-CB-YO1Hn.js +0 -774
  424. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  425. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  426. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  427. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  428. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  429. package/dist/schemas-DzK6U94N.js +0 -6057
  430. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  431. package/dist/step-CKczO72Q.js +0 -670
  432. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  433. package/dist/timer-DpDyj9G0.js +0 -596
  434. package/dist/tooltip-Dt77sBeT.js +0 -390
  435. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  436. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  437. package/dist/useTheme-CVJ0UOf2.js +0 -841
  438. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  439. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
  440. package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
@@ -0,0 +1,208 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import { useAtom, useAtomValue, useSetAtom } from "jotai";
3
+ import { useEffect, useRef, useState } from "react";
4
+ import useEvent from "react-use-event-hook";
5
+ import { kernelStartupErrorAtom } from "@/core/errors/state";
6
+ import { connectionAtom } from "@/core/network/connection";
7
+ import { useRequestClient } from "@/core/network/requests";
8
+ import { useFilename } from "@/core/saving/filename";
9
+ import { waitFor } from "@/core/state/jotai";
10
+ import { isWasm } from "@/core/wasm/utils";
11
+ import { WebSocketState } from "@/core/websocket/types";
12
+ import { HTTPError, prettyError } from "@/utils/errors";
13
+ import { invalidatePackageData } from "./package-data";
14
+ import {
15
+ sandboxActionsAtom,
16
+ sandboxAtom,
17
+ sandboxSyncAtom,
18
+ } from "./sandbox-state";
19
+ import {
20
+ RESTART_REQUIRED_DESCRIPTION,
21
+ showPackageRestartToast,
22
+ showSandboxSyncToast,
23
+ } from "./toast-components";
24
+
25
+ /** Mount once with the editor so manifest drafts survive closing Packages. */
26
+ export function useSandboxController(onReconnect: () => Promise<void>) {
27
+ const requests = useRequestClient();
28
+ const filename = useFilename();
29
+ const connection = useAtomValue(connectionAtom);
30
+ const startupError = useAtomValue(kernelStartupErrorAtom);
31
+ const setSandbox = useSetAtom(sandboxAtom);
32
+ const [operation, setOperation] = useAtom(sandboxSyncAtom);
33
+ const setActions = useSetAtom(sandboxActionsAtom);
34
+ const [open, setOpen] = useState(false);
35
+ const [document, setDocument] = useState<{
36
+ original: string;
37
+ draft: string;
38
+ } | null>(null);
39
+ const [error, setError] = useState<string | null>(null);
40
+ const [saving, setSaving] = useState(false);
41
+ const [loading, setLoading] = useState(false);
42
+ const [conflict, setConflict] = useState(false);
43
+ const inFlight = useRef(false);
44
+ const dirty = document !== null && document.original !== document.draft;
45
+
46
+ useEffect(() => {
47
+ if (isWasm()) {
48
+ return;
49
+ }
50
+ let cancelled = false;
51
+ requests
52
+ .getSandbox({ fileKey: filename })
53
+ .then((value) => {
54
+ if (!cancelled) {
55
+ setSandbox(value);
56
+ }
57
+ })
58
+ .catch(() => {
59
+ /* A connection error is already shown by the editor. */
60
+ });
61
+ return () => {
62
+ cancelled = true;
63
+ };
64
+ }, [requests, filename, connection.state, setSandbox]);
65
+
66
+ const sync = useEvent(async () => {
67
+ if (
68
+ inFlight.current ||
69
+ operation.kind === "running" ||
70
+ connection.state === WebSocketState.CONNECTING
71
+ ) {
72
+ return false;
73
+ }
74
+ inFlight.current = true;
75
+ setOperation({ kind: "running" });
76
+ try {
77
+ const result = await requests.syncSandbox({ fileKey: filename });
78
+ if (result.restartRequired) {
79
+ setOperation({
80
+ kind: "restart-required",
81
+ reason: result.error ?? RESTART_REQUIRED_DESCRIPTION,
82
+ });
83
+ showPackageRestartToast();
84
+ return false;
85
+ }
86
+ if (!result.success) {
87
+ throw new Error(result.error ?? "Sandbox sync failed.");
88
+ }
89
+ if (result.reconnect) {
90
+ await onReconnect();
91
+ const status = await waitFor(
92
+ connectionAtom,
93
+ (value) =>
94
+ value.state === WebSocketState.OPEN ||
95
+ value.state === WebSocketState.CLOSED,
96
+ );
97
+ if (status.state === WebSocketState.CLOSED) {
98
+ setOperation({ kind: "idle" });
99
+ return false;
100
+ }
101
+ }
102
+ if (!result.reconnect) {
103
+ invalidatePackageData();
104
+ }
105
+ showSandboxSyncToast();
106
+ setOperation({ kind: "succeeded" });
107
+ return true;
108
+ } catch (cause) {
109
+ setOperation({ kind: "failed", error: prettyError(cause) });
110
+ return false;
111
+ } finally {
112
+ inFlight.current = false;
113
+ }
114
+ });
115
+
116
+ const loadManifest = useEvent(async () => {
117
+ setLoading(true);
118
+ setError(null);
119
+ setConflict(false);
120
+ try {
121
+ const result = await requests.getSandbox({ fileKey: filename });
122
+ setSandbox(result);
123
+ if (result.manifest === null) {
124
+ throw new Error("No notebook manifest is available yet.");
125
+ }
126
+ setDocument({ original: result.manifest, draft: result.manifest });
127
+ } catch (cause) {
128
+ setError(prettyError(cause));
129
+ } finally {
130
+ setLoading(false);
131
+ }
132
+ });
133
+
134
+ const editManifest = useEvent(async () => {
135
+ setOpen(true);
136
+ if (!dirty) {
137
+ await loadManifest();
138
+ }
139
+ });
140
+
141
+ useEffect(() => {
142
+ setActions({ sync, editManifest });
143
+ return () => {
144
+ setActions(null);
145
+ };
146
+ }, [sync, editManifest, setActions]);
147
+
148
+ const saveAndSync = async () => {
149
+ if (!document || loading || saving || operation.kind === "running") {
150
+ return;
151
+ }
152
+ setSaving(true);
153
+ setError(null);
154
+ try {
155
+ if (dirty) {
156
+ const result = await requests.updateManifest({
157
+ fileKey: filename,
158
+ contents: document.draft,
159
+ previous: document.original,
160
+ });
161
+ setSandbox(result);
162
+ if (result.manifest !== null) {
163
+ setDocument({ original: result.manifest, draft: result.manifest });
164
+ }
165
+ }
166
+ if (await sync()) {
167
+ setOpen(false);
168
+ }
169
+ } catch (cause) {
170
+ setError(prettyError(cause));
171
+ setConflict(cause instanceof HTTPError && cause.status === 409);
172
+ } finally {
173
+ setSaving(false);
174
+ }
175
+ };
176
+ const pending =
177
+ saving ||
178
+ loading ||
179
+ operation.kind === "running" ||
180
+ connection.state === WebSocketState.CONNECTING;
181
+ const diagnostic =
182
+ error ??
183
+ (operation.kind === "failed"
184
+ ? operation.error
185
+ : operation.kind === "restart-required"
186
+ ? operation.reason
187
+ : operation.kind === "cancelled"
188
+ ? "Sandbox sync was interrupted."
189
+ : null) ??
190
+ startupError;
191
+ return {
192
+ filename,
193
+ open,
194
+ setOpen,
195
+ draft: document?.draft ?? null,
196
+ setDraft: (draft: string) =>
197
+ setDocument((value) => value && { ...value, draft }),
198
+ dirty,
199
+ loading,
200
+ saving,
201
+ pending,
202
+ error,
203
+ diagnostic,
204
+ conflict,
205
+ loadManifest,
206
+ saveAndSync,
207
+ };
208
+ }
@@ -3,6 +3,7 @@
3
3
  import { atom, useAtomValue } from "jotai";
4
4
  import { ArrowLeftIcon } from "lucide-react";
5
5
  import { useEffect } from "react";
6
+ import { KernelStartupErrorModal } from "@/components/editor/KernelStartupErrorModal";
6
7
  import { AppContainer } from "@/components/editor/app-container";
7
8
  import { AppHeader } from "@/components/editor/header/app-header";
8
9
  import { ProgressiveBoundary } from "@/components/lifecycle/ProgressiveBoundary";
@@ -78,6 +79,7 @@ export const RunApp: React.FC<AppProps> = ({ appConfig, hideHeader }) => {
78
79
  width={appConfig.width}
79
80
  onReconnect={reconnect}
80
81
  >
82
+ <KernelStartupErrorModal />
81
83
  <AppHeader
82
84
  connection={connection}
83
85
  className={hideHeader ? "hidden" : "sm:pt-8"}
@@ -291,14 +291,10 @@ describe("patchVegaLoader - loader.load", () => {
291
291
  const loader = createLoader();
292
292
  const unpatch = patchVegaLoader(loader, virtualFiles);
293
293
 
294
- try {
295
- const content = await loader.load("file:///path/to/@file/vega-data.json");
296
- expect(content).toBe('{"values": [1, 2, 3]}');
297
- } catch (error) {
298
- // If it falls back to original loader and fails, that's expected for file:// URLs
299
- // The important thing is that the virtual file lookup was attempted
300
- expect(error).toBeDefined();
301
- }
294
+ const content = await loader
295
+ .load("file:///path/to/@file/vega-data.json")
296
+ .catch(() => undefined);
297
+ expect([undefined, '{"values": [1, 2, 3]}']).toContain(content);
302
298
 
303
299
  unpatch();
304
300
  });
@@ -340,15 +336,10 @@ describe("patchVegaLoader - loader.load", () => {
340
336
  }
341
337
 
342
338
  // Test file:// URL separately since it might fallback
343
- try {
344
- const content = await loader.load(
345
- "file:///local/path/@file/pattern-test.json",
346
- );
347
- expect(content).toBe('{"pattern": "test"}');
348
- } catch (error) {
349
- // Expected if it falls back to original loader
350
- expect(error).toBeDefined();
351
- }
339
+ const fileUrlContent = await loader
340
+ .load("file:///local/path/@file/pattern-test.json")
341
+ .catch(() => undefined);
342
+ expect([undefined, '{"pattern": "test"}']).toContain(fileUrlContent);
352
343
 
353
344
  unpatch();
354
345
  });
@@ -640,12 +631,9 @@ describe("error handling and edge cases", () => {
640
631
  expect(window.fetch).toBe(originalFetch);
641
632
 
642
633
  // Test that the loader functions are functional (they should work normally)
643
- try {
644
- await loader.load("http://example.com/test.json");
645
- } catch (error) {
646
- // Expected to fail for non-existent URLs, but the function should be callable
647
- expect(error).toBeDefined();
648
- }
634
+ // A network failure is expected for this non-existent URL. A custom loader
635
+ // may also handle it, so only verify that the restored method is callable.
636
+ await loader.load("http://example.com/test.json").catch(() => undefined);
649
637
  });
650
638
 
651
639
  it("should handle Request objects in patchFetch", async () => {
@@ -676,13 +664,7 @@ describe("error handling and edge cases", () => {
676
664
  .mockImplementation(Functions.NOOP);
677
665
 
678
666
  // This should catch the error and fallback to original fetch
679
- try {
680
- await window.fetch("not-a-valid-url");
681
- // If it doesn't throw, that's also fine (fallback behavior)
682
- } catch (error) {
683
- // Expected behavior - invalid URLs should be handled gracefully
684
- expect(error).toBeDefined();
685
- }
667
+ await window.fetch("not-a-valid-url").catch(() => undefined);
686
668
 
687
669
  unpatch();
688
670
  loggerSpy.mockRestore();
@@ -0,0 +1,63 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { loadPyodide } from "pyodide";
4
+ import type { PyodideInterface } from "pyodide";
5
+ import { beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { DefaultWasmController } from "../worker/bootstrap";
7
+
8
+ vi.mock("pyodide", () => ({ loadPyodide: vi.fn() }));
9
+ vi.mock("../worker/getMarimoWheel", () => ({
10
+ getMarimoWheel: () => "marimo-base",
11
+ }));
12
+
13
+ const micropip = { set_index_urls: vi.fn(), destroy: vi.fn() };
14
+ const pyodide = { pyimport: vi.fn(() => micropip) };
15
+
16
+ beforeEach(() => {
17
+ vi.clearAllMocks();
18
+ vi.mocked(loadPyodide).mockResolvedValue(
19
+ pyodide as unknown as PyodideInterface,
20
+ );
21
+ });
22
+
23
+ describe("WASM runtime sources", () => {
24
+ it("preserves the default runtime sources", async () => {
25
+ await new DefaultWasmController().bootstrap({
26
+ version: "0.24.2",
27
+ pyodideVersion: "v314.0.0",
28
+ });
29
+ expect(loadPyodide).toHaveBeenCalledWith(
30
+ expect.objectContaining({
31
+ indexURL: "https://cdn.jsdelivr.net/pyodide/v314.0.0/full/",
32
+ packageBaseUrl: "https://cdn.jsdelivr.net/pyodide/v314.0.0/full/",
33
+ lockFileURL:
34
+ "https://wasm.marimo.app/pyodide-lock.json?v=0.24.2&pyodide=v314.0.0",
35
+ }),
36
+ );
37
+ expect(pyodide.pyimport).not.toHaveBeenCalled();
38
+ });
39
+
40
+ it("configures runtime and package sources before returning the interpreter", async () => {
41
+ const controller = new DefaultWasmController();
42
+ await controller.bootstrap({
43
+ version: "0.24.2",
44
+ pyodideVersion: "v314.0.0",
45
+ pyodideIndexUrl: "https://example.com/runtime/",
46
+ pyodideLockfileUrl: "https://example.com/lock.json",
47
+ pypiIndexUrl: "https://example.com/pypi/{package_name}/json",
48
+ });
49
+ expect(loadPyodide).toHaveBeenCalledWith(
50
+ expect.objectContaining({
51
+ indexURL: "https://example.com/runtime/",
52
+ packageBaseUrl: "https://example.com/runtime/",
53
+ lockFileURL: "https://example.com/lock.json",
54
+ }),
55
+ );
56
+ expect(pyodide.pyimport).toHaveBeenCalledWith("micropip");
57
+ expect(micropip.set_index_urls).toHaveBeenCalledWith(
58
+ "https://example.com/pypi/{package_name}/json",
59
+ );
60
+ expect(micropip.destroy).toHaveBeenCalledOnce();
61
+ expect(controller.requirePyodide).toBe(pyodide);
62
+ });
63
+ });
@@ -9,12 +9,14 @@ const {
9
9
  mockNotebookReadFile,
10
10
  mockReadNotebook,
11
11
  mockSaveNotebook,
12
+ mockBootstrap,
12
13
  rpcListeners,
13
14
  } = vi.hoisted(() => ({
14
15
  mockBridge: vi.fn(),
15
16
  mockNotebookReadFile: vi.fn(),
16
17
  mockReadNotebook: vi.fn(),
17
18
  mockSaveNotebook: vi.fn(),
19
+ mockBootstrap: vi.fn(),
18
20
  rpcListeners: {} as Record<string, () => void>,
19
21
  }));
20
22
 
@@ -40,6 +42,7 @@ vi.stubGlobal("URL", MockURL);
40
42
 
41
43
  vi.mock("@/core/wasm/rpc", () => ({
42
44
  getWorkerRPC: () => ({
45
+ send: { bootstrap: mockBootstrap },
43
46
  proxy: {
44
47
  request: {
45
48
  bridge: mockBridge,
@@ -122,6 +125,12 @@ describe("PyodideBridge.readCode", () => {
122
125
 
123
126
  await PyodideBridge.INSTANCE.readCode();
124
127
 
128
+ expect(mockBootstrap).toHaveBeenCalledWith({
129
+ version: "0.0.0-test",
130
+ pyodideIndexUrl: undefined,
131
+ pyodideLockfileUrl: undefined,
132
+ pypiIndexUrl: undefined,
133
+ });
125
134
  expect(mockNotebookReadFile).not.toHaveBeenCalled();
126
135
  });
127
136
  });
@@ -215,21 +224,21 @@ describe("getWasmWorkerName", () => {
215
224
  .__MARIMO_HAS_WASM_CONTROLLER__;
216
225
  });
217
226
 
218
- it("returns the version without suffix by default", () => {
219
- expect(getWasmWorkerName()).toBe("0.0.0-test");
227
+ it("returns the default worker name without suffix", () => {
228
+ expect(getWasmWorkerName()).toBe("marimo");
220
229
  });
221
230
 
222
231
  it("appends ::controller when the host opts in", () => {
223
232
  (
224
233
  window as unknown as { __MARIMO_HAS_WASM_CONTROLLER__?: boolean }
225
234
  ).__MARIMO_HAS_WASM_CONTROLLER__ = true;
226
- expect(getWasmWorkerName()).toBe("0.0.0-test::controller");
235
+ expect(getWasmWorkerName()).toBe("marimo::controller");
227
236
  });
228
237
 
229
238
  it("does not append the suffix for non-true values", () => {
230
239
  (
231
240
  window as unknown as { __MARIMO_HAS_WASM_CONTROLLER__?: unknown }
232
241
  ).__MARIMO_HAS_WASM_CONTROLLER__ = "true";
233
- expect(getWasmWorkerName()).toBe("0.0.0-test");
242
+ expect(getWasmWorkerName()).toBe("marimo");
234
243
  });
235
244
  });
@@ -0,0 +1,22 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import type { PyodideInterface } from "pyodide";
3
+ import { afterEach, expect, it, vi } from "vitest";
4
+ import { WasmFileSystem } from "../worker/fs";
5
+
6
+ afterEach(() => vi.unstubAllGlobals());
7
+
8
+ it.each(["https://notebook.example", "null"])(
9
+ "mounts persistent storage only for a non-opaque origin: %s",
10
+ (origin) => {
11
+ vi.stubGlobal("origin", origin);
12
+ const mount = vi.fn();
13
+ const IDBFS = {};
14
+ const pyodide = {
15
+ FS: { mount, filesystems: { IDBFS } },
16
+ } as unknown as PyodideInterface;
17
+ WasmFileSystem.mountFS(pyodide);
18
+ expect(mount.mock.calls).toEqual(
19
+ origin === "null" ? [] : [[IDBFS, { root: "." }, "/marimo"]],
20
+ );
21
+ },
22
+ );
@@ -0,0 +1,65 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { afterEach, assert, describe, expect, it, vi } from "vitest";
4
+ import { getWasmRuntimeConfig } from "../runtime-config";
5
+
6
+ vi.mock("@/core/meta/globals", () => ({
7
+ getMarimoVersion: () => "0.0.0-test",
8
+ }));
9
+
10
+ afterEach(() => {
11
+ document.head.innerHTML = "";
12
+ });
13
+
14
+ describe("getWasmRuntimeConfig", () => {
15
+ it("uses runtime defaults when no URLs are configured", () => {
16
+ expect(getWasmRuntimeConfig()).toEqual({
17
+ version: "0.0.0-test",
18
+ pyodideIndexUrl: undefined,
19
+ pyodideLockfileUrl: undefined,
20
+ pypiIndexUrl: undefined,
21
+ });
22
+ });
23
+
24
+ it("resolves URLs against the page base and preserves micropip placeholders", () => {
25
+ document.head.innerHTML = `
26
+ <base href="https://example.com/blog/post/">
27
+ <marimo-wasm
28
+ data-pyodide-index-url="../runtime/"
29
+ data-pyodide-lockfile-url="/locks/pyodide.json?v=1&amp;x=2"
30
+ data-pypi-index-url="https://packages.example.com/{package_name}/json"
31
+ ></marimo-wasm>`;
32
+ expect(getWasmRuntimeConfig()).toEqual({
33
+ version: "0.0.0-test",
34
+ pyodideIndexUrl: "https://example.com/blog/runtime/",
35
+ pyodideLockfileUrl: "https://example.com/locks/pyodide.json?v=1&x=2",
36
+ pypiIndexUrl: "https://packages.example.com/{package_name}/json",
37
+ });
38
+ });
39
+
40
+ it.each(["pyodideIndexUrl", "pyodideLockfileUrl", "pypiIndexUrl"])(
41
+ "ignores malformed %s while preserving valid overrides",
42
+ (key) => {
43
+ document.head.innerHTML = `
44
+ <base href="https://example.com/notebook/">
45
+ <marimo-wasm
46
+ data-pyodide-index-url="./pyodide/"
47
+ data-pyodide-lockfile-url="./lockfile/pyodide.json"
48
+ data-pypi-index-url="./packages/{package_name}.json"
49
+ ></marimo-wasm>`;
50
+ const element = document.querySelector<HTMLElement>("marimo-wasm");
51
+ assert(element);
52
+ element.dataset[key] = "https://invalid host/";
53
+
54
+ expect(getWasmRuntimeConfig()).toEqual({
55
+ version: "0.0.0-test",
56
+ pyodideIndexUrl: "https://example.com/notebook/pyodide/",
57
+ pyodideLockfileUrl:
58
+ "https://example.com/notebook/lockfile/pyodide.json",
59
+ pypiIndexUrl:
60
+ "https://example.com/notebook/packages/{package_name}.json",
61
+ [key]: undefined,
62
+ });
63
+ },
64
+ );
65
+ });
@@ -9,9 +9,9 @@ import { throwNotImplemented } from "@/utils/functions";
9
9
  import { Logger } from "@/utils/Logger";
10
10
  import { reloadSafe } from "@/utils/reload-safe";
11
11
  import { generateUUID } from "@/utils/uuid";
12
+ import { createModuleWorker } from "@/utils/worker";
12
13
  import { notebookIsRunningAtom } from "../cells/cells";
13
14
  import type { CommandMessage } from "../kernel/messages";
14
- import { getMarimoVersion } from "../meta/globals";
15
15
  import { getInitialAppMode } from "../mode";
16
16
  import { API } from "../network/api";
17
17
  import type {
@@ -41,10 +41,14 @@ import { BasicTransport } from "../websocket/transports/basic";
41
41
  import type { IConnectionTransport } from "../websocket/transports/transport";
42
42
  import { PyodideRouter } from "./router";
43
43
  import { getWorkerRPC } from "./rpc";
44
+ import { getWasmRuntimeConfig } from "./runtime-config";
44
45
  import { createShareableLink } from "./share";
45
46
  import { wasmInitStateAtom } from "./state";
46
47
  import { fallbackFileStore, notebookFileStore } from "./store";
47
48
  import { isWasm } from "./utils";
49
+ import saveWorkerUrl from "./worker/save-worker.ts?worker&url";
50
+ import workerUrl from "./worker/worker.ts?worker&url";
51
+ import { CUSTOM_CONTROLLER_SUFFIX } from "./worker/constants";
48
52
  import type { SaveWorkerSchema } from "./worker/save-worker";
49
53
  import type { WorkerSchema } from "./worker/worker";
50
54
 
@@ -81,19 +85,20 @@ export class PyodideBridge implements RunRequests, EditRequests {
81
85
  };
82
86
  }
83
87
 
88
+ const runtimeConfig = getWasmRuntimeConfig();
89
+
84
90
  // Create save worker
85
- const saveWorker = new Worker(
86
- // oxlint-disable-next-line unicorn/relative-url-style
87
- new URL("./worker/save-worker.ts", import.meta.url),
91
+ const saveWorker = createModuleWorker(
92
+ new URL(saveWorkerUrl, import.meta.url),
88
93
  {
89
- type: "module",
90
- // Pass the version (and optional capability suffix) to the worker
91
- /* @vite-ignore */
94
+ // Pass the optional custom-controller capability to the worker.
92
95
  name: getWasmWorkerName(),
93
96
  },
94
97
  );
95
98
 
96
- return getWorkerRPC<SaveWorkerSchema>(saveWorker).proxy.request;
99
+ const rpc = getWorkerRPC<SaveWorkerSchema>(saveWorker);
100
+ rpc.send.bootstrap(runtimeConfig);
101
+ return rpc.proxy.request;
97
102
  }
98
103
 
99
104
  private constructor() {
@@ -101,20 +106,17 @@ export class PyodideBridge implements RunRequests, EditRequests {
101
106
  return;
102
107
  }
103
108
 
109
+ const runtimeConfig = getWasmRuntimeConfig();
110
+
104
111
  // Create a worker
105
- const worker = new Worker(
106
- // oxlint-disable-next-line unicorn/relative-url-style
107
- new URL("./worker/worker.ts", import.meta.url),
108
- {
109
- type: "module",
110
- // Pass the version (and optional capability suffix) to the worker
111
- /* @vite-ignore */
112
- name: getWasmWorkerName(),
113
- },
114
- );
112
+ const worker = createModuleWorker(new URL(workerUrl, import.meta.url), {
113
+ // Pass the optional custom-controller capability to the worker.
114
+ name: getWasmWorkerName(),
115
+ });
115
116
 
116
117
  // Create the RPC
117
118
  this.rpc = getWorkerRPC<WorkerSchema>(worker);
119
+ this.rpc.send.bootstrap(runtimeConfig);
118
120
 
119
121
  // Listeners
120
122
  this.rpc.addMessageListener("ready", () => {
@@ -640,6 +642,17 @@ export class PyodideBridge implements RunRequests, EditRequests {
640
642
  return response;
641
643
  };
642
644
 
645
+ getSandbox: EditRequests["getSandbox"] = async () => ({
646
+ backend: null,
647
+ manifest: null,
648
+ filename: null,
649
+ });
650
+ updateManifest: EditRequests["updateManifest"] = async () => {
651
+ throw new Error("Sandboxes are not supported in WebAssembly");
652
+ };
653
+ syncSandbox: EditRequests["syncSandbox"] = async () => {
654
+ throw new Error("Sandboxes are not supported in WebAssembly");
655
+ };
643
656
  getDependencyTree: EditRequests["getDependencyTree"] = async () => {
644
657
  // WASM doesn't support dependency trees yet
645
658
  return {
@@ -713,10 +726,9 @@ export function createPyodideConnection(): IConnectionTransport {
713
726
  });
714
727
  }
715
728
 
716
- // Compose the worker name. The version prefix is read by getMarimoVersion()
717
- // in the worker; the optional "::controller" suffix tells getController.ts
718
- // that the host page provides a custom /wasm/controller.js and that the
719
- // dynamic import should be attempted. Hosts opt in by setting
729
+ // Compose the worker name. The optional "::controller" suffix tells
730
+ // getController.ts that the host page provides a custom /wasm/controller.js
731
+ // and that the dynamic import should be attempted. Hosts opt in by setting
720
732
  // `window.__MARIMO_HAS_WASM_CONTROLLER__ = true` before
721
733
  // PyodideBridge/worker initialization.
722
734
  export function getWasmWorkerName(): string {
@@ -724,5 +736,5 @@ export function getWasmWorkerName(): string {
724
736
  typeof window !== "undefined" &&
725
737
  (window as unknown as { __MARIMO_HAS_WASM_CONTROLLER__?: boolean })
726
738
  .__MARIMO_HAS_WASM_CONTROLLER__ === true;
727
- return getMarimoVersion() + (hasCustomController ? "::controller" : "");
739
+ return `marimo${hasCustomController ? CUSTOM_CONTROLLER_SUFFIX : ""}`;
728
740
  }
@@ -6,11 +6,13 @@ import {
6
6
  type RPCSchema,
7
7
  } from "rpc-anywhere";
8
8
  import { Logger } from "@/utils/Logger";
9
+ import type { WasmRuntimeConfig } from "./runtime-config";
9
10
  import { TRANSPORT_ID } from "./worker/constants";
10
11
 
11
12
  export type ParentSchema = RPCSchema<{
12
13
  messages: {
13
14
  consumerReady: {};
15
+ bootstrap: WasmRuntimeConfig;
14
16
  };
15
17
  }>;
16
18
 
@@ -0,0 +1,31 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { getMarimoVersion } from "@/core/meta/globals";
4
+
5
+ export interface WasmRuntimeConfig {
6
+ version: string;
7
+ pyodideIndexUrl?: string;
8
+ pyodideLockfileUrl?: string;
9
+ pypiIndexUrl?: string;
10
+ }
11
+
12
+ export function getWasmRuntimeConfig(): WasmRuntimeConfig {
13
+ const element = document.querySelector<HTMLElement>("marimo-wasm");
14
+ const resolve = (url: string | undefined) => {
15
+ try {
16
+ return url ? new URL(url, document.baseURI).href : undefined;
17
+ } catch {
18
+ return undefined;
19
+ }
20
+ };
21
+ return {
22
+ version: getMarimoVersion(),
23
+ pyodideIndexUrl: resolve(element?.dataset.pyodideIndexUrl),
24
+ pyodideLockfileUrl: resolve(element?.dataset.pyodideLockfileUrl),
25
+ // URL serialization escapes the placeholder understood by micropip.
26
+ pypiIndexUrl: resolve(element?.dataset.pypiIndexUrl)?.replaceAll(
27
+ "%7Bpackage_name%7D",
28
+ "{package_name}",
29
+ ),
30
+ };
31
+ }