@marimo-team/islands 0.23.7-dev6 → 0.23.7-dev60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ConnectedDataExplorerComponent-PmilQqXR.js → ConnectedDataExplorerComponent-2lBNiUv6.js} +14 -14
- package/dist/{ErrorBoundary-Da4UeYxT.js → ErrorBoundary-D3wrPNma.js} +1 -1
- package/dist/{any-language-editor-BVR0l12r.js → any-language-editor-VWs_7v27.js} +15 -15
- package/dist/apl-Bdc61P1y.js +4 -0
- package/dist/{arc-CHF8PiiF.js → arc-DfkSnvZm.js} +2 -2
- package/dist/{architecture-7HQA4BMR-D0JB_3hE.js → architecture-7HQA4BMR-CS9jOrqM.js} +1 -1
- package/dist/{architectureDiagram-VXUJARFQ-BXQEUDtK.js → architectureDiagram-VXUJARFQ-CXVJxFhH.js} +16 -16
- package/dist/asciiarmor-DVRHDGzT.js +4 -0
- package/dist/asn1-BmuKfkfu.js +4 -0
- package/dist/assets/__vite-browser-external-CAdMKBac.js +1 -0
- package/dist/assets/worker-CpBbwbQo.js +73 -0
- package/dist/{blockDiagram-VD42YOAC-DhJe-Y9i.js → blockDiagram-VD42YOAC-DGDaxR8I.js} +11 -11
- package/dist/brainfuck-DPrRpyTV.js +4 -0
- package/dist/{button-CA5pI2YF.js → button-Dj4BTre0.js} +5 -0
- package/dist/{c4Diagram-YG6GDRKO-9dSfzOFR.js → c4Diagram-YG6GDRKO-C2hc6ne8.js} +5 -5
- package/dist/{capabilities-6laDasij.js → capabilities-C9rrYCzf.js} +1 -1
- package/dist/{channel-MqYIiKgS.js → channel-BBoIVUrJ.js} +1 -1
- package/dist/{chat-ui-B-gbqk_F.js → chat-ui-D3XBept8.js} +626 -234
- package/dist/{check-CFM2mVDr.js → check-BcUIXnUT.js} +1 -1
- package/dist/{chunk-4BX2VUAB-BwfrWBqN.js → chunk-4BX2VUAB-CzXltWHN.js} +1 -1
- package/dist/{chunk-55IACEB6-D8THf2mi.js → chunk-55IACEB6-B-1mjMMC.js} +1 -1
- package/dist/{chunk-5FQGJX7Z-CO1e63h_.js → chunk-5FQGJX7Z-BOg95xG5.js} +2 -2
- package/dist/{chunk-ABZYJK2D-BrBb_0yY.js → chunk-ABZYJK2D-D0cLy8Bb.js} +2 -2
- package/dist/{chunk-ATLVNIR6-D-0XqNah.js → chunk-ATLVNIR6-BXsEjlHF.js} +2 -2
- package/dist/{chunk-B4BG7PRW-8iRKvugR.js → chunk-B4BG7PRW-Q1usn6T3.js} +7 -7
- package/dist/{chunk-CVBHYZKI-B6xhgaBd.js → chunk-CVBHYZKI-B_c5YBcW.js} +1 -1
- package/dist/{chunk-DI55MBZ5-C0_2D4m4.js → chunk-DI55MBZ5-D1qLYNrb.js} +6 -6
- package/dist/{chunk-EXTU4WIE-Jiw9ca1u.js → chunk-EXTU4WIE-BKNXdLmD.js} +2 -2
- package/dist/{chunk-FMBD7UC4-CHdus51S.js → chunk-FMBD7UC4-Ie8M9q0W.js} +1 -1
- package/dist/{chunk-HN2XXSSU-2Vfbq-kU.js → chunk-HN2XXSSU-E3n-Ys7Z.js} +1 -1
- package/dist/{chunk-JA3XYJ7Z-6wbaigKe.js → chunk-JA3XYJ7Z-D6c6cOBG.js} +3 -3
- package/dist/{chunk-JZLCHNYA-_rfptlUP.js → chunk-JZLCHNYA-BvsPHJmL.js} +6 -6
- package/dist/{chunk-MI3HLSF2-Do0-KRc0.js → chunk-MI3HLSF2-CUYEasXO.js} +1 -1
- package/dist/{chunk-N4CR4FBY-DIZG9dVD.js → chunk-N4CR4FBY-8ycT-O9a.js} +7 -7
- package/dist/{chunk-QN33PNHL-Cc64y40m.js → chunk-QN33PNHL-Bb-eUBW3.js} +2 -2
- package/dist/{chunk-QXUST7PY-BDG0-0Or.js → chunk-QXUST7PY-DV8yRwBd.js} +10 -10
- package/dist/{chunk-QZHKN3VN-B_Mdb8GC.js → chunk-QZHKN3VN-DRjXVwuJ.js} +1 -1
- package/dist/{chunk-S3R3BYOJ-DphMP0FA.js → chunk-S3R3BYOJ-mQeCz5CE.js} +4 -4
- package/dist/{chunk-TZMSLE5B-C9LUoYkc.js → chunk-TZMSLE5B-BqW10dHe.js} +3 -3
- package/dist/classDiagram-2ON5EDUG--Yh__LHb.js +30 -0
- package/dist/classDiagram-v2-WZHVMYZB-BC7X7Xtc.js +30 -0
- package/dist/{clike-sBZrGeF8.js → clike-DTxNUn7l.js} +1 -1
- package/dist/clojure-DEttQW5T.js +4 -0
- package/dist/cmake-jNlx_DaM.js +4 -0
- package/dist/cobol-BvvIm5MJ.js +4 -0
- package/dist/{code-block-37QAKDTI-0JNwiPGv.js → code-block-37QAKDTI-BsGy1AOJ.js} +1 -1
- package/dist/{code-visibility-jLjZTWEO.js → code-visibility-aw0C3c0g.js} +13540 -4044
- package/dist/coffeescript-DTpBMyFU.js +4 -0
- package/dist/commonlisp-BmmUG8jb.js +4 -0
- package/dist/{copy-TGGAUEWp.js → copy-DLf4aN7I.js} +2 -2
- package/dist/{cose-bilkent-S5V4N54A-DXHZkJKX.js → cose-bilkent-S5V4N54A-kjoZoid4.js} +2 -2
- package/dist/crystal-BxyqmEWC.js +4 -0
- package/dist/css-BGoCtuG3.js +4 -0
- package/dist/cypher-BmCbdl3u.js +4 -0
- package/dist/d-CFrlbjZt.js +4 -0
- package/dist/{dagre-6UL2VRFP-tH87fkPA.js → dagre-6UL2VRFP-DRBWoQUw.js} +10 -10
- package/dist/{data-grid-overlay-editor-CWUN78-s.js → data-grid-overlay-editor-efe5ZagF.js} +2 -2
- package/dist/{diagram-PSM6KHXK-2VjPSCDn.js → diagram-PSM6KHXK-H66ATWP2.js} +18 -18
- package/dist/{diagram-QEK2KX5R-CiLmNyta.js → diagram-QEK2KX5R-DItl5Wns.js} +14 -14
- package/dist/{diagram-S2PKOQOG-Zha_1CLx.js → diagram-S2PKOQOG-CtuW_ZuL.js} +14 -14
- package/dist/diff-D6XwL6P8.js +4 -0
- package/dist/{dist-Brkazupz.js → dist--sWVZwjW.js} +1 -1
- package/dist/{dist-FN0ZA_8F.js → dist-21ButRCu.js} +1 -1
- package/dist/{dist-BetEKbPG.js → dist-B8RaFTRF.js} +1 -1
- package/dist/dist-BoHGySTM.js +5 -0
- package/dist/dist-ByAz19Qc.js +5 -0
- package/dist/dist-C93EysN4.js +5 -0
- package/dist/{dist-BHnX0ia_.js → dist-CY-lVor6.js} +1 -1
- package/dist/{dist-YP-G7W0f.js → dist-CYDuv4bR.js} +1 -1
- package/dist/{dist-CMjD5MQb.js → dist-Cfo5EE2t.js} +1 -1
- package/dist/dist-CjivSDvN.js +5 -0
- package/dist/dist-Cqwx-MH7.js +5 -0
- package/dist/{dist-ESg7xyoD.js → dist-D3ZI9nhS.js} +2 -2
- package/dist/{dist-DkC6YEo0.js → dist-DMZNjfX4.js} +1 -1
- package/dist/{dist-ChC1BhqM.js → dist-DbpcoFAV.js} +1 -1
- package/dist/dist-FUNenbiQ.js +5 -0
- package/dist/{dist-BEOU2g1b.js → dist-zhSud5X3.js} +1 -1
- package/dist/{dockerfile-COvlVLcE.js → dockerfile-twL37N91.js} +1 -1
- package/dist/dtd-Bw0lRN0-.js +4 -0
- package/dist/dylan-B55eBHTt.js +4 -0
- package/dist/ecl-C8G4p0wn.js +4 -0
- package/dist/eiffel-BmH46VJl.js +4 -0
- package/dist/elm-DhzeFqkl.js +4 -0
- package/dist/{erDiagram-Q2GNP2WA-biHZS05w.js → erDiagram-Q2GNP2WA--19X2kU5.js} +14 -14
- package/dist/erlang-CY-wdlsU.js +4 -0
- package/dist/{error-banner-DnBPzEWg.js → error-banner-CVkfBUT3.js} +2 -2
- package/dist/{esm-Dd1z1auZ.js → esm-CWp0KQeK.js} +1 -1
- package/dist/{esm-CYEyrE3Y.js → esm-DjNnlmpf.js} +96 -96
- package/dist/{extends-CzJgxo2J.js → extends-vAi97cpa.js} +4 -4
- package/dist/{factor-C2GT7jfQ.js → factor-CajWS6mS.js} +1 -1
- package/dist/factor-DWkgl0xw.js +4 -0
- package/dist/{flowDiagram-NV44I4VS-CWWlUpBR.js → flowDiagram-NV44I4VS-DQmWlo7f.js} +16 -16
- package/dist/{formats-CgaK7Gmx.js → formats-Dsy9kkZu.js} +3 -3
- package/dist/forth-Cij_ie2t.js +4 -0
- package/dist/fortran-Br3X9cfm.js +4 -0
- package/dist/{ganttDiagram-JELNMOA3-D7B2c4Z9.js → ganttDiagram-JELNMOA3-BOGXJ8Lk.js} +7 -7
- package/dist/gas-DYsGcMN2.js +4 -0
- package/dist/gherkin-eVgXQ0fQ.js +4 -0
- package/dist/{gitGraph-G5XIXVHT-BdepdFa_.js → gitGraph-G5XIXVHT-DGlbae5m.js} +1 -1
- package/dist/{gitGraphDiagram-V2S2FVAM-CtLvNR1S.js → gitGraphDiagram-V2S2FVAM-DjzxfF0P.js} +14 -14
- package/dist/{glide-data-editor-CvlvtPWJ.js → glide-data-editor-DucgdjRo.js} +13 -13
- package/dist/groovy-_NFHIXG7.js +4 -0
- package/dist/haskell-D6xNG_bH.js +4 -0
- package/dist/haxe-sU_rzAwn.js +5 -0
- package/dist/{html-to-image-hMMPiNe_.js → html-to-image-CpggM7u1.js} +2806 -2547
- package/dist/idl-Ds_VbrUx.js +4 -0
- package/dist/{info-VBDWY6EO--JNA2rNu.js → info-VBDWY6EO-D2lvLLw5.js} +1 -1
- package/dist/{infoDiagram-HS3SLOUP-BbZyOxsP.js → infoDiagram-HS3SLOUP-ChNufFsP.js} +12 -12
- package/dist/{input-BAOe64zx.js → input-D4kjoQUB.js} +8 -6
- package/dist/javascript-CztfIl0i.js +4 -0
- package/dist/{journeyDiagram-XKPGCS4Q-BU2mjjzl.js → journeyDiagram-XKPGCS4Q-BO_O4Ij1.js} +6 -6
- package/dist/julia-DDv40QMV.js +4 -0
- package/dist/{kanban-definition-3W4ZIXB7-BlmczUuw.js → kanban-definition-3W4ZIXB7-CPpiiiWk.js} +11 -11
- package/dist/{katex-qPqrBHZ8.js → katex-9-9QRhxz.js} +1 -1
- package/dist/{label-BCWi-Oqu.js → label-BLqV33b1.js} +2 -2
- package/dist/{line-BWRi3U3S.js → line-C5s_12ee.js} +3 -3
- package/dist/{linear-DnHwODZa.js → linear-2NnK4cxi.js} +2 -2
- package/dist/livescript-BEOngLLc.js +4 -0
- package/dist/{loader-BvW0-YWZ.js → loader-Dr8Qem8p.js} +1 -1
- package/dist/lua-9-7BhQ4Y.js +4 -0
- package/dist/main.js +2250 -10847
- package/dist/mathematica-DDa0Pfxm.js +4 -0
- package/dist/mbox-iO03mmoE.js +4 -0
- package/dist/{mermaid-4DMBBIKO-CG1ECj5W.js → mermaid-4DMBBIKO-B7VQMwJx.js} +1 -1
- package/dist/{mermaid-CEbzCxCc.js → mermaid-DO-Daq7u.js} +46 -46
- package/dist/{mermaid-parser.core-CleJseNW.js → mermaid-parser.core-DreccfmS.js} +7 -7
- package/dist/{mhchem-BwoRNwg_.js → mhchem-yiCCuiEF.js} +1 -1
- package/dist/{mindmap-definition-VGOIOE7T-CcSYqYP9.js → mindmap-definition-VGOIOE7T-CC1_Vl0f.js} +13 -13
- package/dist/mirc-C9z5LT4X.js +4 -0
- package/dist/mllike-jGJbdm_C.js +6 -0
- package/dist/modelica-DzF7oIEL.js +4 -0
- package/dist/mscgen-DB-u125o.js +6 -0
- package/dist/mumps-CRTFHhzh.js +4 -0
- package/dist/nsis-C4NPTuox.js +4 -0
- package/dist/{nsis-B5K1qoyo.js → nsis-ClF3r5Tr.js} +1 -1
- package/dist/ntriples-BCOoGph1.js +4 -0
- package/dist/{number-overlay-editor-_GnlYFHC.js → number-overlay-editor-CpKi64Fy.js} +1 -1
- package/dist/octave-DTwNlazz.js +4 -0
- package/dist/{ordinal-2jIulmcR.js → ordinal-B43ZeR68.js} +1 -1
- package/dist/oz-DD38AzSz.js +4 -0
- package/dist/{packet-DYOGHKS2-CBxXGWNr.js → packet-DYOGHKS2-CmWtF3uO.js} +1 -1
- package/dist/pascal-BohSp9jV.js +4 -0
- package/dist/perl-f5OutoPM.js +4 -0
- package/dist/{pie-VRWISCQL-Bmdnqjip.js → pie-VRWISCQL-B6u8vus8.js} +1 -1
- package/dist/{pieDiagram-ADFJNKIX-DNyLF5H2.js → pieDiagram-ADFJNKIX-Di34MOFQ.js} +19 -19
- package/dist/pig-Dv7wSmHb.js +4 -0
- package/dist/powershell-rYgjKB39.js +4 -0
- package/dist/{process-output-Bza_GK7Q.js → process-output-X8TR20AK.js} +30 -25
- package/dist/properties-BFUNLRDN.js +4 -0
- package/dist/protobuf-B9QJQPPv.js +4 -0
- package/dist/{pug-tjbzJCFk.js → pug-B_rby2yb.js} +1 -1
- package/dist/pug-DzvWpaMC.js +4 -0
- package/dist/puppet-B_K-n_xK.js +4 -0
- package/dist/python-CAiFcaA2.js +4 -0
- package/dist/q-cLeFIBLK.js +4 -0
- package/dist/{quadrantDiagram-AYHSOK5B-rXwjifrj.js → quadrantDiagram-AYHSOK5B-B9kVk1ny.js} +3 -3
- package/dist/r-04Y-Wco3.js +4 -0
- package/dist/{radar-ZZBFDIW7-BmCWDffL.js → radar-ZZBFDIW7-XAmXSa8s.js} +1 -1
- package/dist/{react-vega-B-rkEqtS.js → react-vega-Cavbrg4l.js} +1 -1
- package/dist/{react-vega-k9ODWPlI.js → react-vega-Dh6-UKKe.js} +13 -13
- package/dist/{requirementDiagram-UZGBJVZJ-DBdrMVbs.js → requirementDiagram-UZGBJVZJ-BxGfGYEx.js} +13 -13
- package/dist/{reveal-component-BMOBPyvh.js → reveal-component-BKHVGDOe.js} +10 -10
- package/dist/rpm-FUdrIia9.js +5 -0
- package/dist/ruby-DMjFXuEW.js +4 -0
- package/dist/{sankeyDiagram-TZEHDZUN-CxmzalGv.js → sankeyDiagram-TZEHDZUN-D09PBJ-n.js} +4 -4
- package/dist/sas-DzHZxjXK.js +4 -0
- package/dist/scheme-DxHd_Rb9.js +4 -0
- package/dist/semaphore-CNDGTzkX.js +46 -0
- package/dist/{sequenceDiagram-WL72ISMW-CVCDsJ9h.js → sequenceDiagram-WL72ISMW-t_Dpemj0.js} +7 -7
- package/dist/shell-C8Kwypgf.js +4 -0
- package/dist/sieve-DdyqOKXZ.js +4 -0
- package/dist/smalltalk-pB7X1D9y.js +4 -0
- package/dist/sparql-NhBO6oOa.js +4 -0
- package/dist/{spec-DSIuqd3f.js → spec-hVaaZsY5.js} +4 -4
- package/dist/{src-BY0BGg6V.js → src-Bf2iLOlr.js} +1 -1
- package/dist/{stateDiagram-FKZM4ZOC-D_2djEhW.js → stateDiagram-FKZM4ZOC-B18gTP_j.js} +16 -16
- package/dist/stateDiagram-v2-4FDKWEC3-B6e_t14A.js +29 -0
- package/dist/{step-DGAGWg3y.js → step-CWipAYTY.js} +1 -1
- package/dist/{strings-B_FOH6eV.js → strings-BiIhGaI8.js} +4 -4
- package/dist/style.css +1 -1
- package/dist/stylus-SfWSnzPv.js +4 -0
- package/dist/swift-jRPdq2zR.js +4 -0
- package/dist/{swiper-component-KkEVUDd3.js → swiper-component-DlD2GU2g.js} +2 -2
- package/dist/tcl-_hpTHGX3.js +4 -0
- package/dist/textile-C9h8slqH.js +4 -0
- package/dist/{time-CMdrp3hw.js → time-C1SGcFMH.js} +2 -2
- package/dist/{timeline-definition-IT6M3QCI-E4NzxCs3.js → timeline-definition-IT6M3QCI-DJnh1ks5.js} +3 -3
- package/dist/{toDate-CHtl9vts.js → toDate-CIpC_34u.js} +33 -20
- package/dist/toml-DWvtinD4.js +4 -0
- package/dist/{tooltip-B0mtKTXm.js → tooltip-DRaMBu06.js} +3 -3
- package/dist/{treemap-GDKQZRPO-CoKHPxa7.js → treemap-GDKQZRPO-Du95DV6u.js} +1 -1
- package/dist/troff-Dwo_A0y7.js +4 -0
- package/dist/ttcn-V--CPFKq.js +4 -0
- package/dist/ttcn-cfg-CPSMchTG.js +4 -0
- package/dist/turtle-B4rPGBWu.js +4 -0
- package/dist/{types-DBtDeUKD.js → types-Dzuoc3LN.js} +1 -1
- package/dist/{useAsyncData-B6hCGywC.js → useAsyncData-C56Khv_R.js} +1 -1
- package/dist/{useDateFormatter-B3mCQMP3.js → useDateFormatter-B_9k85Ex.js} +2 -2
- package/dist/{useDeepCompareMemoize-CmwDuYUH.js → useDeepCompareMemoize-Dt98v2ua.js} +1 -1
- package/dist/{useIframeCapabilities-DbdLoEDm.js → useIframeCapabilities-BkYHTrss.js} +1 -1
- package/dist/{useLifecycle-CjMjllqy.js → useLifecycle-BF6-z62y.js} +3 -3
- package/dist/{useTheme-CByZUW0p.js → useTheme-DykuNHR2.js} +2 -2
- package/dist/vb-DaMBBd4j.js +4 -0
- package/dist/vbscript-BMJQqcE2.js +4 -0
- package/dist/{vega-component-CC8TqWWV.js → vega-component-cSdqoAxe.js} +26 -24
- package/dist/velocity-CGq2QRq2.js +4 -0
- package/dist/verilog-CUNo8F5u.js +4 -0
- package/dist/vhdl-CCzA0msW.js +4 -0
- package/dist/webidl-CqIMDIBL.js +4 -0
- package/dist/xquery-XC5Kbr-1.js +4 -0
- package/dist/{xychartDiagram-PRI3JC2R-CuxTvjw5.js → xychartDiagram-PRI3JC2R-Dk2d_bX0.js} +10 -10
- package/dist/yacas-CGOv7Dzy.js +4 -0
- package/dist/z80-CXhVmi-f.js +4 -0
- package/dist/{zod-BxdsqRPd.js → zod-BWkcDORu.js} +1 -1
- package/package.json +3 -3
- package/src/components/chat/chat-components.tsx +47 -0
- package/src/components/chat/chat-display.tsx +41 -7
- package/src/components/chat/chat-panel.tsx +37 -10
- package/src/components/chat/chat-utils.ts +42 -20
- package/src/components/chat/reasoning-accordion.tsx +14 -3
- package/src/components/chat/tool-call/shared.ts +13 -0
- package/src/components/chat/tool-call/tool-approval-card.tsx +62 -0
- package/src/components/chat/tool-call/tool-args.tsx +26 -0
- package/src/components/chat/tool-call/tool-call-view.tsx +99 -0
- package/src/components/chat/tool-call/tool-error-card.tsx +81 -0
- package/src/components/chat/tool-call/tool-history-row.tsx +153 -0
- package/src/components/chat/tool-call/tool-result.tsx +101 -0
- package/src/components/data-table/TableTopBar.tsx +5 -1
- package/src/components/data-table/__tests__/column-header.test.ts +3 -1
- package/src/components/data-table/__tests__/column-header.test.tsx +308 -0
- package/src/components/data-table/__tests__/filter-by-values-picker.test.tsx +112 -0
- package/src/components/data-table/__tests__/filter-pill-editor.test.tsx +261 -0
- package/src/components/data-table/__tests__/filters.test.ts +196 -49
- package/src/components/data-table/charts/components/form-fields.tsx +1 -0
- package/src/components/data-table/column-header.tsx +349 -170
- package/src/components/data-table/data-table.tsx +5 -0
- package/src/components/data-table/date-filter-inputs.tsx +325 -0
- package/src/components/data-table/download-policy/atoms.ts +10 -0
- package/src/components/data-table/export-actions.tsx +31 -4
- package/src/components/data-table/filter-by-values-picker.tsx +70 -9
- package/src/components/data-table/filter-pill-editor.tsx +410 -156
- package/src/components/data-table/filter-pills.tsx +69 -54
- package/src/components/data-table/filters.ts +218 -101
- package/src/components/data-table/header-items.tsx +8 -1
- package/src/components/data-table/operator-labels.ts +25 -0
- package/src/components/data-table/regex-input.tsx +61 -0
- package/src/components/editor/actions/pair-with-agent-modal.tsx +140 -49
- package/src/components/editor/actions/useNotebookActions.tsx +3 -1
- package/src/components/editor/app-container.tsx +7 -1
- package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +10 -2
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +1 -0
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer.tsx +4 -1
- package/src/components/editor/chrome/wrapper/panels.tsx +4 -1
- package/src/components/editor/chrome/wrapper/sidebar.tsx +4 -1
- package/src/components/editor/controls/Controls.tsx +11 -3
- package/src/components/editor/file-tree/file-explorer.tsx +12 -2
- package/src/components/editor/file-tree/requesting-tree.tsx +27 -25
- package/src/components/editor/file-tree/upload.tsx +23 -24
- package/src/components/editor/header/__tests__/status.test.tsx +108 -0
- package/src/components/editor/header/status.tsx +44 -10
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +106 -0
- package/src/components/editor/navigation/__tests__/navigation.test.ts +70 -0
- package/src/components/editor/navigation/clipboard.ts +99 -25
- package/src/components/editor/navigation/navigation.ts +15 -1
- package/src/components/editor/notebook-cell.tsx +3 -0
- package/src/components/home/components.tsx +6 -0
- package/src/components/pages/run-page.tsx +4 -1
- package/src/components/ui/combobox.tsx +24 -5
- package/src/components/ui/number-field.tsx +2 -0
- package/src/core/ai/tools/__tests__/registry.test.ts +10 -12
- package/src/core/ai/tools/registry.ts +9 -5
- package/src/core/cells/__tests__/cells.test.ts +187 -0
- package/src/core/cells/__tests__/pending-cut-service.test.tsx +123 -0
- package/src/core/cells/cells.ts +102 -17
- package/src/core/cells/document-changes.ts +6 -1
- package/src/core/cells/pending-cut-service.ts +55 -0
- package/src/core/cells/utils.ts +11 -0
- package/src/core/codemirror/cells/extensions.ts +10 -0
- package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +152 -0
- package/src/core/codemirror/go-to-definition/__tests__/utils.test.ts +99 -0
- package/src/core/codemirror/go-to-definition/commands.ts +382 -22
- package/src/core/codemirror/go-to-definition/utils.ts +23 -5
- package/src/core/codemirror/markdown/__tests__/commands.test.ts +3 -3
- package/src/core/codemirror/markdown/commands.ts +1 -2
- package/src/core/edit-app.tsx +2 -1
- package/src/core/hotkeys/hotkeys.ts +5 -0
- package/src/core/islands/worker/worker.tsx +3 -2
- package/src/core/network/requests-network.ts +21 -3
- package/src/core/network/types.ts +12 -1
- package/src/core/run-app.tsx +2 -1
- package/src/core/runtime/__tests__/runtime.test.ts +38 -17
- package/src/core/runtime/runtime.ts +57 -34
- package/src/core/wasm/__tests__/utils.test.ts +34 -0
- package/src/core/wasm/bridge.ts +14 -1
- package/src/core/wasm/utils.ts +14 -0
- package/src/core/wasm/worker/bootstrap.ts +3 -2
- package/src/core/wasm/worker/worker.ts +3 -2
- package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +156 -0
- package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +101 -0
- package/src/core/websocket/transports/__tests__/ws.test.ts +125 -0
- package/src/core/websocket/transports/basic.ts +1 -1
- package/src/core/websocket/transports/ws.ts +96 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +133 -54
- package/src/core/websocket/useWebSocket.tsx +3 -15
- package/src/css/app/Cell.css +10 -0
- package/src/plugins/core/__test__/sanitize.test.ts +30 -0
- package/src/plugins/impl/DataTablePlugin.tsx +12 -0
- package/src/plugins/impl/DropdownPlugin.tsx +12 -1
- package/src/plugins/impl/MultiselectPlugin.tsx +4 -0
- package/src/plugins/impl/SearchableSelect.tsx +11 -1
- package/src/plugins/impl/TabsPlugin.tsx +35 -7
- package/src/plugins/impl/__tests__/DropdownPlugin.test.tsx +56 -0
- package/src/plugins/impl/__tests__/TabsPlugin.test.tsx +154 -0
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +6 -0
- package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +48 -36
- package/src/plugins/impl/data-frames/schema.ts +4 -1
- package/src/plugins/impl/vega/resolve-data.ts +8 -1
- package/src/utils/__tests__/id-tree.test.ts +71 -0
- package/src/utils/__tests__/semaphore.test.ts +218 -0
- package/src/utils/fileToBase64.ts +8 -7
- package/src/utils/id-tree.tsx +89 -0
- package/src/utils/semaphore.ts +88 -0
- package/dist/apl-BKoVld9y.js +0 -4
- package/dist/asciiarmor-DQrKIjoo.js +0 -4
- package/dist/asn1-BZvnj0dq.js +0 -4
- package/dist/assets/__vite-browser-external-rrUYDKRl.js +0 -1
- package/dist/assets/worker-Bfy15ViQ.js +0 -73
- package/dist/brainfuck-D558nlUv.js +0 -4
- package/dist/classDiagram-2ON5EDUG-CBHMR6ZU.js +0 -30
- package/dist/classDiagram-v2-WZHVMYZB-BsUtUGM_.js +0 -30
- package/dist/clojure-Cq8mTSrE.js +0 -4
- package/dist/cmake-D8HCovWK.js +0 -4
- package/dist/cobol-UolN-9iU.js +0 -4
- package/dist/coffeescript-VdNuWrt5.js +0 -4
- package/dist/commonlisp-ALX7fpDc.js +0 -4
- package/dist/crystal-PbyO9Q_s.js +0 -4
- package/dist/css-DFklJkr_.js +0 -4
- package/dist/cypher-BifNeYlv.js +0 -4
- package/dist/d-BA-JP4PJ.js +0 -4
- package/dist/diff-CtkDpav4.js +0 -4
- package/dist/dist-BuBwsFva.js +0 -5
- package/dist/dist-BzmEQ9u7.js +0 -5
- package/dist/dist-Cih01ssx.js +0 -5
- package/dist/dist-CqfONiY9.js +0 -5
- package/dist/dist-D0iD0Fi9.js +0 -5
- package/dist/dist-DtNLXm8d.js +0 -5
- package/dist/dtd-DW3_UFEG.js +0 -4
- package/dist/dylan-pDhodO2N.js +0 -4
- package/dist/ecl-BJT8-YD7.js +0 -4
- package/dist/eiffel-Dmns-9vS.js +0 -4
- package/dist/elm-Da4sO4Bz.js +0 -4
- package/dist/erlang-C-zBsDi7.js +0 -4
- package/dist/factor-4xPWlWB5.js +0 -4
- package/dist/forth-l-c75zSd.js +0 -4
- package/dist/fortran-DIujSODW.js +0 -4
- package/dist/gas-CXnG5g_b.js +0 -4
- package/dist/gherkin-VPeqd4-X.js +0 -4
- package/dist/groovy-CphhZQgg.js +0 -4
- package/dist/haskell-CCvlS5Iq.js +0 -4
- package/dist/haxe-C_bi66fP.js +0 -5
- package/dist/idl-1DcP4Dm8.js +0 -4
- package/dist/javascript-DUIGhBvO.js +0 -4
- package/dist/julia-Cs2G4PQi.js +0 -4
- package/dist/livescript-DMtVFaAN.js +0 -4
- package/dist/lua-BAoLtdJg.js +0 -4
- package/dist/mathematica-C_NoFtbo.js +0 -4
- package/dist/mbox-DcFJFYrH.js +0 -4
- package/dist/mirc-71dccf_u.js +0 -4
- package/dist/mllike-CWcOFVDq.js +0 -6
- package/dist/modelica-Ape2VXxx.js +0 -4
- package/dist/mscgen-Cc6TwbSN.js +0 -6
- package/dist/mumps-h-ZbdkJ9.js +0 -4
- package/dist/nsis-C0p3m7JW.js +0 -4
- package/dist/ntriples-c9lEeT5w.js +0 -4
- package/dist/octave-DzEgB_74.js +0 -4
- package/dist/oz-CAxvHkyQ.js +0 -4
- package/dist/pascal-BJzu1sgP.js +0 -4
- package/dist/perl--IrOzZ2Z.js +0 -4
- package/dist/pig-CiBKKNhC.js +0 -4
- package/dist/powershell-KY0j6Qop.js +0 -4
- package/dist/properties-BW8q3ziV.js +0 -4
- package/dist/protobuf-BGaeuTGV.js +0 -4
- package/dist/pug-DjOKK-4J.js +0 -4
- package/dist/puppet-DWm2o6zX.js +0 -4
- package/dist/python-Bp2gezZy.js +0 -4
- package/dist/q-DljPshos.js +0 -4
- package/dist/r-BajPMnEu.js +0 -4
- package/dist/rpm-BKx-ZZ62.js +0 -5
- package/dist/ruby-DJq_HNKc.js +0 -4
- package/dist/sas-WANvpcOU.js +0 -4
- package/dist/scheme-CliBbhGF.js +0 -4
- package/dist/shell-BwhrNUvM.js +0 -4
- package/dist/sieve-BIVePvMp.js +0 -4
- package/dist/smalltalk-D6G48JmY.js +0 -4
- package/dist/sparql-jjc3BmEP.js +0 -4
- package/dist/stateDiagram-v2-4FDKWEC3-Cv9Av10H.js +0 -29
- package/dist/stylus-WPBPQ4PE.js +0 -4
- package/dist/swift-O1Qy6iCm.js +0 -4
- package/dist/tcl-BAFdhvsi.js +0 -4
- package/dist/textile-DFuzhNLG.js +0 -4
- package/dist/toml-DRSTeely.js +0 -4
- package/dist/troff-B_ZjwBW0.js +0 -4
- package/dist/ttcn-CAyiB3ic.js +0 -4
- package/dist/ttcn-cfg-BS5_BGBJ.js +0 -4
- package/dist/turtle-CUBEDy3E.js +0 -4
- package/dist/vb-DY9S6-U2.js +0 -4
- package/dist/vbscript-gaHC39Jq.js +0 -4
- package/dist/velocity-TfCOtJZ_.js +0 -4
- package/dist/verilog-c2JOX8mv.js +0 -4
- package/dist/vhdl-dHBirRiO.js +0 -4
- package/dist/webidl-Bauj-i07.js +0 -4
- package/dist/xquery-CtaEAOt8.js +0 -4
- package/dist/yacas-BZ85agQP.js +0 -4
- package/dist/z80-hCgR-L4U.js +0 -4
- package/src/components/chat/tool-call-accordion.tsx +0 -247
- /package/dist/{ImageComparisonComponent-DaocPIse.js → ImageComparisonComponent-CNHIsPDj.js} +0 -0
- /package/dist/{Plot-PIeIvFnD.js → Plot-4wn-lMVn.js} +0 -0
- /package/dist/{apl-Dt8GMXYg.js → apl-BCgCq9iM.js} +0 -0
- /package/dist/{array-B-MVxRIF.js → array-tvvEqPy7.js} +0 -0
- /package/dist/{asciiarmor-CitDQ85h.js → asciiarmor-BtqU-KJQ.js} +0 -0
- /package/dist/{asn1-abrf9SMK.js → asn1-Dmb-dTMx.js} +0 -0
- /package/dist/{asterisk-BUZwqih-.js → asterisk-DaVJJDnV.js} +0 -0
- /package/dist/{brainfuck-BL-Boof0.js → brainfuck-C1HoZKlE.js} +0 -0
- /package/dist/{chunk-4F5CHEZ2-C6tO9vjs.js → chunk-4F5CHEZ2-BZq7Kom7.js} +0 -0
- /package/dist/{chunk-B2363JML-Ds8wZXyP.js → chunk-B2363JML-D9-XOau1.js} +0 -0
- /package/dist/{chunk-DR5Q36YT-CP69aZS_.js → chunk-DR5Q36YT-BflwErH1.js} +0 -0
- /package/dist/{chunk-FRFDVMJY-BgQv1HBE.js → chunk-FRFDVMJY-BSBUAX7r.js} +0 -0
- /package/dist/{chunk-PL6DKKU2-DHfTUHy8.js → chunk-PL6DKKU2-B0MTXvyc.js} +0 -0
- /package/dist/{chunk-SJTYNZTY-Diciw4sx.js → chunk-SJTYNZTY-CEG4F0pB.js} +0 -0
- /package/dist/{chunk-TQ3KTPDO-CQfP9npd.js → chunk-TQ3KTPDO-DiCtqVSi.js} +0 -0
- /package/dist/{chunk-UMXZTB3W-MSKeGL7W.js → chunk-UMXZTB3W-97iS1iEl.js} +0 -0
- /package/dist/{click-outside-container-BZgN7xS_.js → click-outside-container-BDd67_1U.js} +0 -0
- /package/dist/{clike-RWg7anhx.js → clike-CdT0yHjt.js} +0 -0
- /package/dist/{clojure-DaojKHow.js → clojure-CdyrCpUv.js} +0 -0
- /package/dist/{cmake-DN-_v0XE.js → cmake-BFlPxym7.js} +0 -0
- /package/dist/{cobol-C3VpMyux.js → cobol-CcJXewp8.js} +0 -0
- /package/dist/{coffeescript-DIkz3Tbt.js → coffeescript-DnKuIKRo.js} +0 -0
- /package/dist/{colors-Cn2p_FA3.js → colors-CQAOa8cK.js} +0 -0
- /package/dist/{common-keywords-hbLeU7VU.js → common-keywords-FBrXPTcz.js} +0 -0
- /package/dist/{commonlisp-CB1boOiP.js → commonlisp-B-kok83Z.js} +0 -0
- /package/dist/{crystal-DI2oCml6.js → crystal-FYRYjI1I.js} +0 -0
- /package/dist/{css-BdEVwQDV.js → css-B45lc2V3.js} +0 -0
- /package/dist/{cypher-BNHToqxU.js → cypher-DZMLyVY_.js} +0 -0
- /package/dist/{cytoscape.esm-WbbDoCfu.js → cytoscape.esm-ayF70frT.js} +0 -0
- /package/dist/{d-D7we7I1b.js → d-x-VVT4o9.js} +0 -0
- /package/dist/{diff-Cia6fzjN.js → diff-Dxe2mpXk.js} +0 -0
- /package/dist/{dist-BK-3fF4P.js → dist-B4LJpMEg.js} +0 -0
- /package/dist/{dist-CxdUraQr.js → dist-B507mf_I.js} +0 -0
- /package/dist/{dist-C89sHDXk.js → dist-BGdYVvOu.js} +0 -0
- /package/dist/{dist-DquyVv5H.js → dist-BNyrZfqT.js} +0 -0
- /package/dist/{dist-Zn0KNbo9.js → dist-Bc5pmZIw.js} +0 -0
- /package/dist/{dist-C-J0pt5p.js → dist-BvCfQQQE.js} +0 -0
- /package/dist/{dist-D9r7Cmw7.js → dist-C2ej4eOH.js} +0 -0
- /package/dist/{dist-HVuryI1a.js → dist-C34oIrQ9.js} +0 -0
- /package/dist/{dist-CGLzXdrt.js → dist-CDFZi-QD.js} +0 -0
- /package/dist/{dist-C9fmTOin.js → dist-CYEylvZA.js} +0 -0
- /package/dist/{dist-DadjmS-4.js → dist-DJ6zJQZ4.js} +0 -0
- /package/dist/{dist-CtCY55Jf.js → dist-Dh3wkoyH.js} +0 -0
- /package/dist/{dist-C474qFoq.js → dist-Dhk6FMb0.js} +0 -0
- /package/dist/{dist-DZjQ_MBo.js → dist-KnujRhFL.js} +0 -0
- /package/dist/{dist-CinA9Enb.js → dist-WdPUFc56.js} +0 -0
- /package/dist/{dist-DBLeRrPp.js → dist-t_qL7eB8.js} +0 -0
- /package/dist/{dist-CyFFzJTb.js → dist-usPCDYx8.js} +0 -0
- /package/dist/{dtd-H4Hubdwp.js → dtd-C9VM_Wfu.js} +0 -0
- /package/dist/{duckdb-keywords-CZ_ZTscu.js → duckdb-keywords-CvJhR_Yd.js} +0 -0
- /package/dist/{dylan-fVO6rnq3.js → dylan-DTSnEIFO.js} +0 -0
- /package/dist/{ebnf-WEXPLEWb.js → ebnf-2D4Ctp3y.js} +0 -0
- /package/dist/{ecl-B94VPjNR.js → ecl-N04ptnRK.js} +0 -0
- /package/dist/{eiffel-C_R6TusS.js → eiffel-Dd8rpqr_.js} +0 -0
- /package/dist/{elm-DzCHbO2g.js → elm-GT2E866W.js} +0 -0
- /package/dist/{erlang-BGNkx6JU.js → erlang-Cf0Bp5pY.js} +0 -0
- /package/dist/{esm-Bb_hbWan.js → esm-BaaaPNGl.js} +0 -0
- /package/dist/{fcl-B_Gv5Jfx.js → fcl-Ccj8Z5Xd.js} +0 -0
- /package/dist/{forth-Bybw0cJ7.js → forth-wd_XzGTg.js} +0 -0
- /package/dist/{fortran-C6PoCLkI.js → fortran-DcwUTZFe.js} +0 -0
- /package/dist/{gas-BBlhenj4.js → gas-DeALIER3.js} +0 -0
- /package/dist/{gherkin-NXtNG85X.js → gherkin-CKTqaJNX.js} +0 -0
- /package/dist/{groovy-BoFYK9xM.js → groovy-Bwdp_d8D.js} +0 -0
- /package/dist/{haskell-BtBdvQ1n.js → haskell-DCdCcPLK.js} +0 -0
- /package/dist/{haxe-D--o6dr0.js → haxe-DAyktQWJ.js} +0 -0
- /package/dist/{http-Dc2fv19V.js → http-_DVAYWoR.js} +0 -0
- /package/dist/{idl-AqTq5l7e.js → idl-CBuZiRYu.js} +0 -0
- /package/dist/{init-D-g0ONX1.js → init-uv0kkh4g.js} +0 -0
- /package/dist/{javascript-DvwNVye9.js → javascript-DzigE11c.js} +0 -0
- /package/dist/{julia-DoKiagZC.js → julia-PwfB-0Cm.js} +0 -0
- /package/dist/{katex-B7pMJpE0.js → katex-C_XRmjAP.js} +0 -0
- /package/dist/{livescript-DxBZMiWB.js → livescript-BJLz1EbT.js} +0 -0
- /package/dist/{lua-DmS_0NTu.js → lua-ZC-XC2jf.js} +0 -0
- /package/dist/{math-BYK36kWZ.js → math-DFcdCCU8.js} +0 -0
- /package/dist/{mathematica-ChlDFeIC.js → mathematica-DCYMx6qB.js} +0 -0
- /package/dist/{mbox-CguZuODr.js → mbox-OxMK_9XI.js} +0 -0
- /package/dist/{mirc-CFtY8dqz.js → mirc-nJVyhA0H.js} +0 -0
- /package/dist/{mllike-C0EJrEOk.js → mllike-DRO89bsU.js} +0 -0
- /package/dist/{modelica-C1kO1nfS.js → modelica-Don3E6ZD.js} +0 -0
- /package/dist/{mscgen-DEYdr7AY.js → mscgen-DJfqD3bN.js} +0 -0
- /package/dist/{mumps-B3NVJs2V.js → mumps-SjGTvDYL.js} +0 -0
- /package/dist/{nginx-ComVAAGN.js → nginx-DasThI7R.js} +0 -0
- /package/dist/{node-sql-parser-DNGGJ-Rw.js → node-sql-parser-B8nBD36q.js} +0 -0
- /package/dist/{ntriples-DHol9X9H.js → ntriples-CNBKRl3I.js} +0 -0
- /package/dist/{octave-CYGz0bfo.js → octave-DdeVHNlx.js} +0 -0
- /package/dist/{oz-kPxb2ni5.js → oz-CcKSoNvN.js} +0 -0
- /package/dist/{pascal-bZ0yrJKy.js → pascal-6leftwNj.js} +0 -0
- /package/dist/{path-Du6n3sOU.js → path-BGaWgPKg.js} +0 -0
- /package/dist/{perl-z4hvqyqz.js → perl-BhJIwWzN.js} +0 -0
- /package/dist/{pig-DZO8QDF9.js → pig-r-xDHqRf.js} +0 -0
- /package/dist/{powershell-BSuaDQEC.js → powershell-D-BELeNi.js} +0 -0
- /package/dist/{properties-BXhGLlIx.js → properties-CnuDhbll.js} +0 -0
- /package/dist/{protobuf-DM6iybWV.js → protobuf-CO8RBhvX.js} +0 -0
- /package/dist/{puppet-Bn05sQT8.js → puppet-NmXHjLy8.js} +0 -0
- /package/dist/{python-Cvnhm0g7.js → python-DAQXi720.js} +0 -0
- /package/dist/{q-B9V8hzex.js → q-DlikXfV0.js} +0 -0
- /package/dist/{r-Cf0gFqmq.js → r-CuohilwT.js} +0 -0
- /package/dist/{rpm-D-LMkTV1.js → rpm-0Pjwp0Pb.js} +0 -0
- /package/dist/{ruby-DeuPikpK.js → ruby-Dq8NJTDG.js} +0 -0
- /package/dist/{sas-C9tjgAo9.js → sas-CuwonyVP.js} +0 -0
- /package/dist/{scheme-D1_bUF0G.js → scheme-CYU-RRIf.js} +0 -0
- /package/dist/{shell-CJBmnks3.js → shell-COPmX2qE.js} +0 -0
- /package/dist/{sieve-1fSV75CF.js → sieve-B_3zyLne.js} +0 -0
- /package/dist/{simple-mode-B90Wdavj.js → simple-mode-DSBniks8.js} +0 -0
- /package/dist/{smalltalk-sZNPD0HO.js → smalltalk-DRft7iPv.js} +0 -0
- /package/dist/{solr-DTkyqJ-Z.js → solr-RZ9uTl59.js} +0 -0
- /package/dist/{sparql-oHc1nm77.js → sparql-CN6qj55H.js} +0 -0
- /package/dist/{spreadsheet-CER0raqY.js → spreadsheet-BNNUNXA2.js} +0 -0
- /package/dist/{sql-ByOoEONQ.js → sql-B4x8IkwU.js} +0 -0
- /package/dist/{stylus-KzkX6zRB.js → stylus-Bn_ZjOQ3.js} +0 -0
- /package/dist/{swift-DqVxZvKo.js → swift-BLUJhMbz.js} +0 -0
- /package/dist/{tcl-BtWSwXfA.js → tcl-C86fxecl.js} +0 -0
- /package/dist/{textile-CWDbn9Ql.js → textile-DmHh2rsK.js} +0 -0
- /package/dist/{tiddlywiki-Cr9xyOY1.js → tiddlywiki-DI0mF2WJ.js} +0 -0
- /package/dist/{tiki-D5JONyfZ.js → tiki-2HU6XLLn.js} +0 -0
- /package/dist/{timer-D7JVdX9U.js → timer-YZl28NYN.js} +0 -0
- /package/dist/{toml-BfehlgmL.js → toml-GWANRNAD.js} +0 -0
- /package/dist/{treemap-qFGzn7xk.js → treemap-D-ka1hvx.js} +0 -0
- /package/dist/{troff-BZBk6AAu.js → troff-BHTsomIy.js} +0 -0
- /package/dist/{ttcn-DVwvXg0_.js → ttcn-DQuhn5Mn.js} +0 -0
- /package/dist/{ttcn-cfg-gjbVLf1L.js → ttcn-cfg-HjFYtdB-.js} +0 -0
- /package/dist/{turtle-CgxKXorV.js → turtle-nCay33Nv.js} +0 -0
- /package/dist/{vb-B9kSwTdM.js → vb-BG-XlqqJ.js} +0 -0
- /package/dist/{vbscript-DrUKSCdb.js → vbscript-B6vyW0-D.js} +0 -0
- /package/dist/{velocity-AlMYTnMy.js → velocity-CWegueqO.js} +0 -0
- /package/dist/{verilog-DLUaM05j.js → verilog-CzSQm4cG.js} +0 -0
- /package/dist/{vhdl-DUJOtSmO.js → vhdl-DqnNVL7r.js} +0 -0
- /package/dist/{webidl-CQp4aHk_.js → webidl-DXEUpDWH.js} +0 -0
- /package/dist/{xquery-IxkjlwOD.js → xquery-Ba_NB5bD.js} +0 -0
- /package/dist/{yacas-Bnctn5w8.js → yacas-HKQU6hyk.js} +0 -0
- /package/dist/{z80-DrFwhx53.js → z80-CXkHXLdj.js} +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { MAX_RETRIES, WsTransport, TRANSPORT_EXHAUSTED_REASON } from "../ws";
|
|
5
|
+
|
|
6
|
+
let innerListeners: Record<string, ((e: unknown) => void)[]>;
|
|
7
|
+
|
|
8
|
+
vi.mock("partysocket/ws", () => {
|
|
9
|
+
class FakeReconnectingWebSocket {
|
|
10
|
+
retryCount = 0;
|
|
11
|
+
readyState = WebSocket.CONNECTING;
|
|
12
|
+
constructor() {
|
|
13
|
+
innerListeners = { open: [], close: [], message: [], error: [] };
|
|
14
|
+
}
|
|
15
|
+
addEventListener(event: string, cb: (e: unknown) => void) {
|
|
16
|
+
innerListeners[event].push(cb);
|
|
17
|
+
}
|
|
18
|
+
removeEventListener(event: string, cb: (e: unknown) => void) {
|
|
19
|
+
innerListeners[event] = innerListeners[event].filter((c) => c !== cb);
|
|
20
|
+
}
|
|
21
|
+
reconnect() {}
|
|
22
|
+
close() {}
|
|
23
|
+
send() {}
|
|
24
|
+
}
|
|
25
|
+
return { default: FakeReconnectingWebSocket };
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
interface FakeReconnectingWebSocket {
|
|
29
|
+
retryCount: number;
|
|
30
|
+
readyState: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function dispatchClose(reason = "") {
|
|
34
|
+
const evt = new CloseEvent("close", { reason, code: 1006 });
|
|
35
|
+
for (const cb of innerListeners.close) {
|
|
36
|
+
cb(evt);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("WsTransport", () => {
|
|
41
|
+
let transport: WsTransport;
|
|
42
|
+
let inner: FakeReconnectingWebSocket;
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
transport = new WsTransport(() => "ws://example.invalid/ws");
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
+
inner = (transport as any).inner;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("close event reason", () => {
|
|
51
|
+
it("forwards the original reason before retry budget is exhausted", () => {
|
|
52
|
+
const seen: CloseEvent[] = [];
|
|
53
|
+
transport.addEventListener("close", (e) => seen.push(e));
|
|
54
|
+
|
|
55
|
+
inner.retryCount = MAX_RETRIES - 1;
|
|
56
|
+
dispatchClose("");
|
|
57
|
+
|
|
58
|
+
expect(seen).toHaveLength(1);
|
|
59
|
+
expect(seen[0].reason).toBe("");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("rewrites reason to MARIMO_TRANSPORT_EXHAUSTED on exhaustion", () => {
|
|
63
|
+
const seen: CloseEvent[] = [];
|
|
64
|
+
transport.addEventListener("close", (e) => seen.push(e));
|
|
65
|
+
|
|
66
|
+
inner.retryCount = MAX_RETRIES;
|
|
67
|
+
dispatchClose("");
|
|
68
|
+
|
|
69
|
+
expect(seen).toHaveLength(1);
|
|
70
|
+
expect(seen[0].reason).toBe(TRANSPORT_EXHAUSTED_REASON);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("does not rewrite a server-sent reason on exhaustion", () => {
|
|
74
|
+
// If partysocket happens to deliver a real MARIMO_* reason at the same
|
|
75
|
+
// moment the retry budget exhausts, the exhausted-state rewrite still
|
|
76
|
+
// wins because the wrapper keys off retryCount, not the original reason.
|
|
77
|
+
// Document the behavior so a future change is deliberate.
|
|
78
|
+
const seen: CloseEvent[] = [];
|
|
79
|
+
transport.addEventListener("close", (e) => seen.push(e));
|
|
80
|
+
|
|
81
|
+
inner.retryCount = MAX_RETRIES;
|
|
82
|
+
dispatchClose("MARIMO_SHUTDOWN");
|
|
83
|
+
|
|
84
|
+
expect(seen[0].reason).toBe(TRANSPORT_EXHAUSTED_REASON);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("addEventListener dedupe", () => {
|
|
89
|
+
it("does not double-fire when the same close listener is added twice", () => {
|
|
90
|
+
const cb = vi.fn();
|
|
91
|
+
transport.addEventListener("close", cb);
|
|
92
|
+
transport.addEventListener("close", cb);
|
|
93
|
+
|
|
94
|
+
dispatchClose("");
|
|
95
|
+
|
|
96
|
+
expect(cb).toHaveBeenCalledTimes(1);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("a single removeEventListener fully unregisters a duplicated add", () => {
|
|
100
|
+
const cb = vi.fn();
|
|
101
|
+
transport.addEventListener("close", cb);
|
|
102
|
+
transport.addEventListener("close", cb);
|
|
103
|
+
transport.removeEventListener("close", cb);
|
|
104
|
+
|
|
105
|
+
dispatchClose("");
|
|
106
|
+
|
|
107
|
+
expect(cb).not.toHaveBeenCalled();
|
|
108
|
+
// Inner socket has no orphaned wrappers left.
|
|
109
|
+
expect(innerListeners.close).toHaveLength(0);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe("removeEventListener", () => {
|
|
114
|
+
it("unregisters the right wrapper for close listeners", () => {
|
|
115
|
+
const cb = vi.fn();
|
|
116
|
+
transport.addEventListener("close", cb);
|
|
117
|
+
transport.removeEventListener("close", cb);
|
|
118
|
+
|
|
119
|
+
inner.retryCount = MAX_RETRIES;
|
|
120
|
+
dispatchClose("");
|
|
121
|
+
|
|
122
|
+
expect(cb).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -43,7 +43,7 @@ export class BasicTransport implements IConnectionTransport {
|
|
|
43
43
|
return WebSocket.OPEN;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
reconnect(
|
|
46
|
+
reconnect(_code?: number | undefined, _reason?: string | undefined): void {
|
|
47
47
|
this.close();
|
|
48
48
|
this.connect();
|
|
49
49
|
return;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import ReconnectingWebSocket from "partysocket/ws";
|
|
4
|
+
import type {
|
|
5
|
+
ConnectionEvent,
|
|
6
|
+
ConnectionTransportCallback,
|
|
7
|
+
IConnectionTransport,
|
|
8
|
+
} from "./transport";
|
|
9
|
+
|
|
10
|
+
// Per-`reconnect()` retry budget. After exhaustion, partysocket stops silently;
|
|
11
|
+
// the wrapper rewrites the close-event reason to surface the give-up.
|
|
12
|
+
export const MAX_RETRIES = 10;
|
|
13
|
+
|
|
14
|
+
export const TRANSPORT_EXHAUSTED_REASON = "MARIMO_TRANSPORT_EXHAUSTED";
|
|
15
|
+
|
|
16
|
+
export class WsTransport implements IConnectionTransport {
|
|
17
|
+
private inner: ReconnectingWebSocket;
|
|
18
|
+
private closeWrappers = new WeakMap<
|
|
19
|
+
ConnectionTransportCallback<"close">,
|
|
20
|
+
ConnectionTransportCallback<"close">
|
|
21
|
+
>();
|
|
22
|
+
|
|
23
|
+
constructor(urlProvider: () => string) {
|
|
24
|
+
this.inner = new ReconnectingWebSocket(urlProvider, undefined, {
|
|
25
|
+
maxRetries: MAX_RETRIES,
|
|
26
|
+
debug: false,
|
|
27
|
+
startClosed: true,
|
|
28
|
+
// long timeout — the server can become slow when many notebooks are open.
|
|
29
|
+
connectionTimeout: 10_000,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get readyState(): WebSocket["readyState"] {
|
|
34
|
+
return this.inner.readyState as WebSocket["readyState"];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
reconnect(code?: number, reason?: string): void {
|
|
38
|
+
this.inner.reconnect(code, reason);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
close(): void {
|
|
42
|
+
this.inner.close();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
send(data: string | ArrayBuffer | Blob | ArrayBufferView): void {
|
|
46
|
+
this.inner.send(data);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
addEventListener<T extends ConnectionEvent>(
|
|
50
|
+
event: T,
|
|
51
|
+
callback: ConnectionTransportCallback<T>,
|
|
52
|
+
): void {
|
|
53
|
+
if (event === "close") {
|
|
54
|
+
const userCb = callback as ConnectionTransportCallback<"close">;
|
|
55
|
+
// Match native EventTarget dedupe: a second addEventListener with the
|
|
56
|
+
// same listener is a no-op. Without this, repeated adds leak wrappers
|
|
57
|
+
// on the inner socket and double-fire on close.
|
|
58
|
+
if (this.closeWrappers.has(userCb)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const wrapper: ConnectionTransportCallback<"close"> = (e) => {
|
|
62
|
+
if (this.inner.retryCount >= MAX_RETRIES) {
|
|
63
|
+
userCb(
|
|
64
|
+
new CloseEvent("close", {
|
|
65
|
+
code: e.code,
|
|
66
|
+
reason: TRANSPORT_EXHAUSTED_REASON,
|
|
67
|
+
wasClean: e.wasClean,
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
} else {
|
|
71
|
+
userCb(e);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
this.closeWrappers.set(userCb, wrapper);
|
|
75
|
+
this.inner.addEventListener("close", wrapper);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.inner.addEventListener(event, callback as never);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
removeEventListener<T extends ConnectionEvent>(
|
|
82
|
+
event: T,
|
|
83
|
+
callback: ConnectionTransportCallback<T>,
|
|
84
|
+
): void {
|
|
85
|
+
if (event === "close") {
|
|
86
|
+
const userCb = callback as ConnectionTransportCallback<"close">;
|
|
87
|
+
const wrapper = this.closeWrappers.get(userCb);
|
|
88
|
+
if (wrapper) {
|
|
89
|
+
this.closeWrappers.delete(userCb);
|
|
90
|
+
this.inner.removeEventListener("close", wrapper);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.inner.removeEventListener(event, callback as never);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
NotificationMessageData,
|
|
12
12
|
NotificationPayload,
|
|
13
13
|
} from "@/core/kernel/messages";
|
|
14
|
+
import { TRANSPORT_EXHAUSTED_REASON } from "@/core/websocket/transports/ws";
|
|
14
15
|
import { useConnectionTransport } from "@/core/websocket/useWebSocket";
|
|
15
16
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
16
17
|
import {
|
|
@@ -69,10 +70,105 @@ import { useStorageActions } from "../storage/state";
|
|
|
69
70
|
import { useVariablesActions } from "../variables/state";
|
|
70
71
|
import type { VariableName } from "../variables/types";
|
|
71
72
|
import { isWasm } from "../wasm/utils";
|
|
72
|
-
import {
|
|
73
|
+
import {
|
|
74
|
+
type ConnectionStatus,
|
|
75
|
+
WebSocketClosedReason,
|
|
76
|
+
WebSocketState,
|
|
77
|
+
} from "./types";
|
|
73
78
|
|
|
74
79
|
const SUPPORTS_LAZY_KERNELS = true;
|
|
75
80
|
|
|
81
|
+
// All MARIMO_* reasons except TRANSPORT_EXHAUSTED are emitted by the backend
|
|
82
|
+
// (marimo/_server/api/endpoints/ws_endpoint.py and ws/*.py). Keep in sync with
|
|
83
|
+
// the backend literals.
|
|
84
|
+
export type CloseReason =
|
|
85
|
+
| "MARIMO_ALREADY_CONNECTED"
|
|
86
|
+
| "MARIMO_WRONG_KERNEL_ID"
|
|
87
|
+
| "MARIMO_NO_FILE_KEY"
|
|
88
|
+
| "MARIMO_NO_SESSION_ID"
|
|
89
|
+
| "MARIMO_NO_SESSION"
|
|
90
|
+
| "MARIMO_SHUTDOWN"
|
|
91
|
+
| "MARIMO_MALFORMED_QUERY"
|
|
92
|
+
| "MARIMO_KERNEL_STARTUP_ERROR"
|
|
93
|
+
| typeof TRANSPORT_EXHAUSTED_REASON;
|
|
94
|
+
|
|
95
|
+
export type CloseDecision =
|
|
96
|
+
| { kind: "terminal"; status: ConnectionStatus; closeTransport: boolean }
|
|
97
|
+
| { kind: "gave-up"; status: ConnectionStatus }
|
|
98
|
+
| { kind: "retry"; status: ConnectionStatus };
|
|
99
|
+
|
|
100
|
+
export function classifyCloseEvent(event: { reason?: string }): CloseDecision {
|
|
101
|
+
switch (event.reason as CloseReason | undefined) {
|
|
102
|
+
case "MARIMO_ALREADY_CONNECTED":
|
|
103
|
+
return {
|
|
104
|
+
kind: "terminal",
|
|
105
|
+
status: {
|
|
106
|
+
state: WebSocketState.CLOSED,
|
|
107
|
+
code: WebSocketClosedReason.ALREADY_RUNNING,
|
|
108
|
+
reason: "another browser tab is already connected to the kernel",
|
|
109
|
+
canTakeover: true,
|
|
110
|
+
},
|
|
111
|
+
closeTransport: true,
|
|
112
|
+
};
|
|
113
|
+
case TRANSPORT_EXHAUSTED_REASON:
|
|
114
|
+
return {
|
|
115
|
+
kind: "gave-up",
|
|
116
|
+
status: {
|
|
117
|
+
state: WebSocketState.CLOSED,
|
|
118
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
119
|
+
reason: "kernel not found",
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
case "MARIMO_WRONG_KERNEL_ID":
|
|
123
|
+
case "MARIMO_NO_FILE_KEY":
|
|
124
|
+
case "MARIMO_NO_SESSION_ID":
|
|
125
|
+
case "MARIMO_NO_SESSION":
|
|
126
|
+
case "MARIMO_SHUTDOWN":
|
|
127
|
+
return {
|
|
128
|
+
kind: "terminal",
|
|
129
|
+
status: {
|
|
130
|
+
state: WebSocketState.CLOSED,
|
|
131
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
132
|
+
reason: "kernel not found",
|
|
133
|
+
},
|
|
134
|
+
closeTransport: true,
|
|
135
|
+
};
|
|
136
|
+
case "MARIMO_MALFORMED_QUERY":
|
|
137
|
+
return {
|
|
138
|
+
kind: "terminal",
|
|
139
|
+
status: {
|
|
140
|
+
state: WebSocketState.CLOSED,
|
|
141
|
+
code: WebSocketClosedReason.MALFORMED_QUERY,
|
|
142
|
+
reason:
|
|
143
|
+
"the kernel did not recognize a request; please file a bug with marimo",
|
|
144
|
+
},
|
|
145
|
+
closeTransport: false,
|
|
146
|
+
};
|
|
147
|
+
case "MARIMO_KERNEL_STARTUP_ERROR":
|
|
148
|
+
return {
|
|
149
|
+
kind: "terminal",
|
|
150
|
+
status: {
|
|
151
|
+
state: WebSocketState.CLOSED,
|
|
152
|
+
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
153
|
+
reason: "Failed to start kernel sandbox",
|
|
154
|
+
},
|
|
155
|
+
closeTransport: true,
|
|
156
|
+
};
|
|
157
|
+
default:
|
|
158
|
+
// Empty/undefined reasons are normal transient closes. Anything else is
|
|
159
|
+
// an unknown server reason; warn so a new MARIMO_* reason doesn't fall
|
|
160
|
+
// silently into the retry path.
|
|
161
|
+
if (event.reason) {
|
|
162
|
+
logNever(event.reason as never);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
kind: "retry",
|
|
168
|
+
status: { state: WebSocketState.CONNECTING },
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
76
172
|
function getExistingCells(): CellData[] | undefined {
|
|
77
173
|
if (!SUPPORTS_LAZY_KERNELS) {
|
|
78
174
|
return undefined;
|
|
@@ -340,6 +436,30 @@ export function useMarimoKernelConnection(opts: {
|
|
|
340
436
|
}
|
|
341
437
|
};
|
|
342
438
|
|
|
439
|
+
// Manual reconnect. Probes /health first to fail fast when the runtime
|
|
440
|
+
// is unreachable, instead of waiting on partysocket's retry budget.
|
|
441
|
+
const reconnect = async () => {
|
|
442
|
+
if (
|
|
443
|
+
ws.readyState === WebSocket.OPEN ||
|
|
444
|
+
ws.readyState === WebSocket.CONNECTING
|
|
445
|
+
) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
shouldTryReconnecting.current = true;
|
|
449
|
+
setConnection({ state: WebSocketState.CONNECTING });
|
|
450
|
+
const healthy = await runtimeManager.reconcileFromHealth();
|
|
451
|
+
if (!healthy) {
|
|
452
|
+
shouldTryReconnecting.current = false;
|
|
453
|
+
setConnection({
|
|
454
|
+
state: WebSocketState.CLOSED,
|
|
455
|
+
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
456
|
+
reason: "kernel not found",
|
|
457
|
+
});
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
ws.reconnect();
|
|
461
|
+
};
|
|
462
|
+
|
|
343
463
|
const ws = useConnectionTransport({
|
|
344
464
|
static: isStaticNotebook(),
|
|
345
465
|
/**
|
|
@@ -399,58 +519,17 @@ export function useMarimoKernelConnection(opts: {
|
|
|
399
519
|
*/
|
|
400
520
|
onClose: (e) => {
|
|
401
521
|
Logger.warn("WebSocket closed", e.code, e.reason);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
case "MARIMO_WRONG_KERNEL_ID":
|
|
414
|
-
case "MARIMO_NO_FILE_KEY":
|
|
415
|
-
case "MARIMO_NO_SESSION_ID":
|
|
416
|
-
case "MARIMO_NO_SESSION":
|
|
417
|
-
case "MARIMO_SHUTDOWN":
|
|
418
|
-
setConnection({
|
|
419
|
-
state: WebSocketState.CLOSED,
|
|
420
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
421
|
-
reason: "kernel not found",
|
|
422
|
-
});
|
|
423
|
-
ws.close(); // close to prevent reconnecting
|
|
424
|
-
return;
|
|
425
|
-
|
|
426
|
-
case "MARIMO_MALFORMED_QUERY":
|
|
427
|
-
setConnection({
|
|
428
|
-
state: WebSocketState.CLOSED,
|
|
429
|
-
code: WebSocketClosedReason.MALFORMED_QUERY,
|
|
430
|
-
reason:
|
|
431
|
-
"the kernel did not recognize a request; please file a bug with marimo",
|
|
432
|
-
});
|
|
433
|
-
return;
|
|
434
|
-
|
|
435
|
-
default:
|
|
436
|
-
// Check for kernel startup error (full error already received via message)
|
|
437
|
-
if (e.reason === "MARIMO_KERNEL_STARTUP_ERROR") {
|
|
438
|
-
setConnection({
|
|
439
|
-
state: WebSocketState.CLOSED,
|
|
440
|
-
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
441
|
-
reason: "Failed to start kernel sandbox",
|
|
442
|
-
});
|
|
443
|
-
ws.close(); // prevent reconnecting
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Session should be valid
|
|
448
|
-
// - browser tab might have been closed or re-opened
|
|
449
|
-
// - computer might have just woken from sleep
|
|
450
|
-
//
|
|
451
|
-
// so try reconnecting.
|
|
452
|
-
setConnection({ state: WebSocketState.CONNECTING });
|
|
453
|
-
tryReconnecting(e.code, e.reason);
|
|
522
|
+
const decision = classifyCloseEvent(e);
|
|
523
|
+
setConnection(decision.status);
|
|
524
|
+
if (decision.kind === "terminal" && decision.closeTransport) {
|
|
525
|
+
ws.close(); // close to prevent reconnecting
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (decision.kind === "retry") {
|
|
529
|
+
// Session should be valid
|
|
530
|
+
// - browser tab might have been closed or re-opened
|
|
531
|
+
// - computer might have just woken from sleep
|
|
532
|
+
tryReconnecting(e.code, e.reason);
|
|
454
533
|
}
|
|
455
534
|
},
|
|
456
535
|
|
|
@@ -468,5 +547,5 @@ export function useMarimoKernelConnection(opts: {
|
|
|
468
547
|
},
|
|
469
548
|
});
|
|
470
549
|
|
|
471
|
-
return { connection };
|
|
550
|
+
return { connection, reconnect };
|
|
472
551
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import ReconnectingWebSocket from "partysocket/ws";
|
|
4
3
|
import { useEffect, useState } from "react";
|
|
5
4
|
import { Logger } from "@/utils/Logger";
|
|
6
5
|
import { createPyodideConnection } from "../wasm/bridge";
|
|
7
6
|
import { isWasm } from "../wasm/utils";
|
|
8
7
|
import { BasicTransport } from "./transports/basic";
|
|
8
|
+
import { WsTransport } from "./transports/ws";
|
|
9
9
|
import type { IConnectionTransport } from "./transports/transport";
|
|
10
10
|
|
|
11
11
|
interface UseConnectionTransportOptions {
|
|
@@ -27,20 +27,8 @@ function createConnectionTransport(
|
|
|
27
27
|
if (isWasm()) {
|
|
28
28
|
return createPyodideConnection();
|
|
29
29
|
}
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
const urlProvider = options.url; // We don't call the URL provider now since it may change (i.e. if the runtime redirects)
|
|
33
|
-
// Cast needed: ReconnectingWebSocket types readyState as `number`
|
|
34
|
-
// but IConnectionTransport expects `0 | 1 | 2 | 3`
|
|
35
|
-
return new ReconnectingWebSocket(urlProvider, undefined, {
|
|
36
|
-
// We don't want Infinity retries
|
|
37
|
-
maxRetries: 10,
|
|
38
|
-
debug: false,
|
|
39
|
-
startClosed: true,
|
|
40
|
-
// long timeout -- the server can become slow when many notebooks
|
|
41
|
-
// are open.
|
|
42
|
-
connectionTimeout: 10_000,
|
|
43
|
-
}) as unknown as IConnectionTransport;
|
|
30
|
+
// urlProvider is passed lazily; it may change after a runtime redirect.
|
|
31
|
+
return new WsTransport(options.url);
|
|
44
32
|
}
|
|
45
33
|
|
|
46
34
|
/**
|
package/src/css/app/Cell.css
CHANGED
|
@@ -557,4 +557,34 @@ describe("sanitizeHtml", () => {
|
|
|
557
557
|
const html = "<some-custom-element>Content</some-custom-element>";
|
|
558
558
|
expect(sanitizeHtml(html)).toMatchInlineSnapshot(`"Content"`);
|
|
559
559
|
});
|
|
560
|
+
|
|
561
|
+
// DOMPurify SAFE_FOR_XML strips attribute values containing `]>`, `-->`,
|
|
562
|
+
// `--!>`, or `</(style|script|...)`. `_build_attr` JSON-escapes `<`/`>`
|
|
563
|
+
// (`<`/`>`) before HTML-escaping so the parsed attribute value
|
|
564
|
+
// never matches. These tests pin that contract.
|
|
565
|
+
test("preserves data-* attribute with JSON-escaped ]> payload", () => {
|
|
566
|
+
const html =
|
|
567
|
+
"<marimo-table data-data='[{"x":"]\u003e"}]'></marimo-table>";
|
|
568
|
+
expect(sanitizeHtml(html)).toMatchInlineSnapshot(
|
|
569
|
+
`"<marimo-table data-data="[{"x":"]\\u003e"}]"></marimo-table>"`,
|
|
570
|
+
);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
test("preserves data-* attribute with JSON-escaped </script> payload", () => {
|
|
574
|
+
const html =
|
|
575
|
+
"<marimo-table data-data='[{"x":"\u003c/script\u003e"}]'></marimo-table>";
|
|
576
|
+
expect(sanitizeHtml(html)).toMatchInlineSnapshot(
|
|
577
|
+
`"<marimo-table data-data="[{"x":"\\u003c/script\\u003e"}]"></marimo-table>"`,
|
|
578
|
+
);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// Regression sentinel: confirms DOMPurify still strips an UN-escaped `]>`,
|
|
582
|
+
// which is precisely the condition `_build_attr` exists to prevent.
|
|
583
|
+
test("strips data-* attribute when raw ]> leaks through", () => {
|
|
584
|
+
const html =
|
|
585
|
+
"<marimo-table data-data='[{"x":"]>"}]'></marimo-table>";
|
|
586
|
+
expect(sanitizeHtml(html)).toMatchInlineSnapshot(
|
|
587
|
+
`"<marimo-table></marimo-table>"`,
|
|
588
|
+
);
|
|
589
|
+
});
|
|
560
590
|
});
|
|
@@ -194,6 +194,7 @@ interface Data<T> {
|
|
|
194
194
|
wrappedColumns?: string[];
|
|
195
195
|
headerTooltip?: Record<string, string>;
|
|
196
196
|
totalColumns: number;
|
|
197
|
+
sizeBytes?: number | null;
|
|
197
198
|
maxColumns: number | "all";
|
|
198
199
|
hasStableRowId: boolean;
|
|
199
200
|
lazy: boolean;
|
|
@@ -220,6 +221,7 @@ type DataTableFunctions = {
|
|
|
220
221
|
cell_styles?: CellStyleState | null;
|
|
221
222
|
cell_hover_texts?: Record<string, Record<string, string | null>> | null;
|
|
222
223
|
raw_data?: TableData<T> | null;
|
|
224
|
+
size_bytes?: number | null;
|
|
223
225
|
}>;
|
|
224
226
|
get_data_url?: GetDataUrl;
|
|
225
227
|
get_row_ids?: GetRowIds;
|
|
@@ -270,6 +272,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
|
|
|
270
272
|
headerTooltip: z.record(z.string(), z.string()).optional(),
|
|
271
273
|
fieldTypes: columnToFieldTypesSchema.nullish(),
|
|
272
274
|
totalColumns: z.number(),
|
|
275
|
+
sizeBytes: z.number().nullish(),
|
|
273
276
|
maxColumns: z.union([z.number(), z.literal("all")]).default("all"),
|
|
274
277
|
hasStableRowId: z.boolean().default(false),
|
|
275
278
|
maxHeight: z.number().optional(),
|
|
@@ -327,6 +330,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
|
|
|
327
330
|
.nullable(),
|
|
328
331
|
cell_hover_texts: cellHoverTextSchema.nullable(),
|
|
329
332
|
raw_data: z.union([z.string(), z.array(z.looseObject({}))]).nullish(),
|
|
333
|
+
size_bytes: z.number().nullish(),
|
|
330
334
|
}),
|
|
331
335
|
),
|
|
332
336
|
get_row_ids: rpc.input(z.object({}).passthrough()).output(
|
|
@@ -532,6 +536,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
532
536
|
rows: T[];
|
|
533
537
|
rawRows?: T[];
|
|
534
538
|
totalRows: number | TooManyRows;
|
|
539
|
+
sizeBytes?: number | null;
|
|
535
540
|
cellStyles: CellStyleState | undefined | null;
|
|
536
541
|
cellHoverTexts?: Record<string, Record<string, string | null>> | null;
|
|
537
542
|
}>(async () => {
|
|
@@ -548,6 +553,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
548
553
|
let tableData = props.data;
|
|
549
554
|
let rawTableData: TableData<T> | undefined | null = props.rawData;
|
|
550
555
|
let totalRows = props.totalRows;
|
|
556
|
+
let sizeBytes = props.sizeBytes ?? null;
|
|
551
557
|
let cellStyles = props.cellStyles;
|
|
552
558
|
let cellHoverTexts = props.cellHoverTexts;
|
|
553
559
|
|
|
@@ -591,6 +597,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
591
597
|
tableData = searchResults.data;
|
|
592
598
|
rawTableData = searchResults.raw_data;
|
|
593
599
|
totalRows = searchResults.total_rows;
|
|
600
|
+
sizeBytes = searchResults.size_bytes ?? null;
|
|
594
601
|
cellStyles = searchResults.cell_styles || {};
|
|
595
602
|
cellHoverTexts = searchResults.cell_hover_texts || {};
|
|
596
603
|
}
|
|
@@ -603,6 +610,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
603
610
|
rows: tableData,
|
|
604
611
|
rawRows: rawData,
|
|
605
612
|
totalRows: totalRows,
|
|
613
|
+
sizeBytes,
|
|
606
614
|
cellStyles,
|
|
607
615
|
cellHoverTexts,
|
|
608
616
|
};
|
|
@@ -614,6 +622,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
614
622
|
useDeepCompareMemoize(props.fieldTypes),
|
|
615
623
|
props.data,
|
|
616
624
|
props.totalRows,
|
|
625
|
+
props.sizeBytes,
|
|
617
626
|
props.lazy,
|
|
618
627
|
props.cellHoverTexts,
|
|
619
628
|
props.cellStyles,
|
|
@@ -728,6 +737,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
728
737
|
setFilters={setFilters}
|
|
729
738
|
reloading={isFetching && !isPending}
|
|
730
739
|
totalRows={data?.totalRows ?? props.totalRows}
|
|
740
|
+
sizeBytes={data?.sizeBytes ?? props.sizeBytes ?? null}
|
|
731
741
|
paginationState={paginationState}
|
|
732
742
|
setPaginationState={setPaginationState}
|
|
733
743
|
cellStyles={data?.cellStyles ?? props.cellStyles}
|
|
@@ -774,6 +784,7 @@ const DataTableComponent = ({
|
|
|
774
784
|
data,
|
|
775
785
|
rawData,
|
|
776
786
|
totalRows,
|
|
787
|
+
sizeBytes,
|
|
777
788
|
maxColumns,
|
|
778
789
|
pagination,
|
|
779
790
|
selection,
|
|
@@ -1053,6 +1064,7 @@ const DataTableComponent = ({
|
|
|
1053
1064
|
maxHeight={maxHeight}
|
|
1054
1065
|
sorting={sorting}
|
|
1055
1066
|
totalRows={totalRows}
|
|
1067
|
+
sizeBytes={sizeBytes}
|
|
1056
1068
|
totalColumns={totalColumns}
|
|
1057
1069
|
manualSorting={true}
|
|
1058
1070
|
setSorting={setSorting}
|
|
@@ -13,6 +13,7 @@ interface Data {
|
|
|
13
13
|
allowSelectNone: boolean;
|
|
14
14
|
fullWidth: boolean;
|
|
15
15
|
searchable: boolean;
|
|
16
|
+
disabled: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export class DropdownPlugin implements IPlugin<string[], Data> {
|
|
@@ -25,6 +26,7 @@ export class DropdownPlugin implements IPlugin<string[], Data> {
|
|
|
25
26
|
allowSelectNone: z.boolean(),
|
|
26
27
|
fullWidth: z.boolean().default(false),
|
|
27
28
|
searchable: z.boolean().default(false),
|
|
29
|
+
disabled: z.boolean().default(false),
|
|
28
30
|
});
|
|
29
31
|
|
|
30
32
|
render(props: IPluginProps<string[], Data>): JSX.Element {
|
|
@@ -61,7 +63,15 @@ interface DropdownProps extends Data {
|
|
|
61
63
|
const EMPTY_VALUE = "--";
|
|
62
64
|
|
|
63
65
|
const Dropdown = (props: DropdownProps): JSX.Element => {
|
|
64
|
-
const {
|
|
66
|
+
const {
|
|
67
|
+
label,
|
|
68
|
+
options,
|
|
69
|
+
value,
|
|
70
|
+
setValue,
|
|
71
|
+
allowSelectNone,
|
|
72
|
+
fullWidth,
|
|
73
|
+
disabled,
|
|
74
|
+
} = props;
|
|
65
75
|
|
|
66
76
|
const id = useId();
|
|
67
77
|
|
|
@@ -85,6 +95,7 @@ const Dropdown = (props: DropdownProps): JSX.Element => {
|
|
|
85
95
|
})}
|
|
86
96
|
value={singleValue}
|
|
87
97
|
id={id}
|
|
98
|
+
disabled={disabled}
|
|
88
99
|
>
|
|
89
100
|
{allowSelectNone ? (
|
|
90
101
|
<option value={EMPTY_VALUE} selected={value.length === 0}>
|