collabmd 0.1.35 → 0.1.36
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/client/assets/{CodeMirrorEditor-UCMRAMCV-CvLFeHXu.js → CodeMirrorEditor-UCMRAMCV-DnBV8gCm.js} +1 -1
- package/dist/client/assets/{_baseFor-Bfo4esZ5.js → _baseFor-BSErPbF2.js} +1 -1
- package/dist/client/assets/{ar-SA-NXDWD63E-WivLHHDW.js → ar-SA-NXDWD63E-CTf_wpt3.js} +1 -1
- package/dist/client/assets/{arc-tRoMuWFi.js → arc-DD8jaAGl.js} +1 -1
- package/dist/client/assets/architecture-YZFGNWBL-DWWrde02.js +1 -0
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-CVdcOotN.js → architectureDiagram-Q4EWVU46-BftXiJA8.js} +1 -1
- package/dist/client/assets/{az-AZ-MXSORGZV-DOdq1TKC.js → az-AZ-MXSORGZV-C_C9i9u3.js} +1 -1
- package/dist/client/assets/{bg-BG-O6MV2KSF-CYucKuDS.js → bg-BG-O6MV2KSF-YmfvQf63.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-B_gNUKQ4.js → blockDiagram-DXYQGD6D-6UN-nR8-.js} +1 -1
- package/dist/client/assets/{bn-IN-MMW2ORAC-DYr8kqNL.js → bn-BD-T2VJNT7N-BD0ob0JE.js} +1 -1
- package/dist/client/assets/{bn-BD-T2VJNT7N-2OKWLCYa.js → bn-IN-MMW2ORAC-BTEFR4Ed.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-BSDwfduG.js → c4Diagram-AHTNJAMY-Gz7ZAK0d.js} +1 -1
- package/dist/client/assets/{ca-ES-MKBCGNOG-B9Aeb43I.js → ca-ES-MKBCGNOG-aLX_cjA0.js} +1 -1
- package/dist/client/assets/channel-XGCkuPi6.js +1 -0
- package/dist/client/assets/{chunk-2KRD3SAO-C6u8y11R.js → chunk-2KRD3SAO-CFcF2aNP.js} +1 -1
- package/dist/client/assets/{chunk-336JU56O-Ch9X5KoM.js → chunk-336JU56O-DvrrHsJT.js} +2 -2
- package/dist/client/assets/chunk-426QAEUC-CEbmCgux.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-2e7V-uuE.js → chunk-4BX2VUAB-D5YiFdu1.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-BEsauZP5.js → chunk-4TB4RGXK-CoouNThi.js} +2 -2
- package/dist/client/assets/{chunk-55IACEB6-DLqevMSj.js → chunk-55IACEB6-VHgZjidg.js} +1 -1
- package/dist/client/assets/{chunk-5FUZZQ4R-6x8SlhH9.js → chunk-5FUZZQ4R-CxIIxXPy.js} +1 -1
- package/dist/client/assets/{chunk-5PVQY5BW-R5SE6dhE.js → chunk-5PVQY5BW-ciE7eHID.js} +1 -1
- package/dist/client/assets/{chunk-67CJDMHE-CjXw5hFa.js → chunk-67CJDMHE-CW-fbgQB.js} +1 -1
- package/dist/client/assets/{chunk-7N4EOEYR-DNHyuswJ.js → chunk-7N4EOEYR-DbAW6XnF.js} +1 -1
- package/dist/client/assets/{chunk-AA7GKIK3-DayE4IF_.js → chunk-AA7GKIK3-ClDHDAza.js} +1 -1
- package/dist/client/assets/{chunk-BSJP7CBP-CexlYBxB.js → chunk-BSJP7CBP-D2KkrA_B.js} +1 -1
- package/dist/client/assets/{chunk-CIAEETIT-CkDJ4DYI.js → chunk-CIAEETIT-BnB8a6HR.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-BVR_nF3y.js → chunk-EDXVE4YY-M4QxyGNt.js} +1 -1
- package/dist/client/assets/{chunk-ENJZ2VHE-CFVWytAB.js → chunk-ENJZ2VHE-BQj_1YA_.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-CMahlBa_.js → chunk-FMBD7UC4-qQT7MtX2.js} +1 -1
- package/dist/client/assets/{chunk-FOC6F5B3-DzCiCLGs.js → chunk-FOC6F5B3-Bw6XfKDP.js} +1 -1
- package/dist/client/assets/{chunk-ICPOFSXX-B9LPHgU7.js → chunk-ICPOFSXX-DqJi89rc.js} +1 -1
- package/dist/client/assets/{chunk-K5T4RW27-kmGSebVE.js → chunk-K5T4RW27-CQtjKF2g.js} +7 -7
- package/dist/client/assets/{chunk-KGLVRYIC-DVjPRsaR.js → chunk-KGLVRYIC-BWSPiKjp.js} +1 -1
- package/dist/client/assets/{chunk-LIHQZDEY-DKFj13sC.js → chunk-LIHQZDEY-DtYrHuCi.js} +1 -1
- package/dist/client/assets/{chunk-AXZTUZBK-DuMiJYO9.js → chunk-LOOWOR4L-C5BUwXgZ.js} +2 -2
- package/dist/client/assets/{chunk-ORNJ4GCN-D0uTAC-5.js → chunk-ORNJ4GCN-Csga44e5.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-nWiNHNyD.js → chunk-OYMX7WX6-DvtmCasj.js} +1 -1
- package/dist/client/assets/chunk-QZHKN3VN-CHVH9_3S.js +1 -0
- package/dist/client/assets/{chunk-SRAX5OIU-CLVBQRWC.js → chunk-SRAX5OIU-yDw8XRsi.js} +1 -1
- package/dist/client/assets/{chunk-U2HBQHQK-Bue4Ufzn.js → chunk-U2HBQHQK-BBXgsocS.js} +1 -1
- package/dist/client/assets/{chunk-X2U36JSP-CRE6lp7n.js → chunk-X2U36JSP-D3OEPG7k.js} +1 -1
- package/dist/client/assets/{chunk-XPW4576I-BL5M-tF8.js → chunk-XPW4576I-BUfyrOtN.js} +1 -1
- package/dist/client/assets/chunk-YHkbxXgt.js +1 -0
- package/dist/client/assets/chunk-YKPWT25G-GISHuloq.js +35 -0
- package/dist/client/assets/{chunk-YZCP3GAM-D7Z5wUWA.js → chunk-YZCP3GAM-D1jf1WUI.js} +1 -1
- package/dist/client/assets/{chunk-Z5NKEFVG-HOkYqaKa.js → chunk-Z5NKEFVG-Vu8zBV4H.js} +1 -1
- package/dist/client/assets/{chunk-ZZ45TVLE-CBbl1Qec.js → chunk-ZZ45TVLE-DGIhE_ST.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-D1KhAUL3.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-BSyyJpnR.js +1 -0
- package/dist/client/assets/clone-DI0bYZ1L.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-xxgR5OJ-.js → cose-bilkent-S5V4N54A-A8ssRFyt.js} +1 -1
- package/dist/client/assets/{cs-CZ-V77HGUP7-BDg-F0CJ.js → cs-CZ-V77HGUP7-Du3y53BB.js} +1 -1
- package/dist/client/assets/{cytoscape.esm-B3PRdePO.js → cytoscape.esm-BurByw8X.js} +2 -2
- package/dist/client/assets/{da-DK-I5RFNTM4-wtSQ0Jxa.js → da-DK-I5RFNTM4-CDJtjf5s.js} +1 -1
- package/dist/client/assets/{dagre-VaFYRFbD.js → dagre-Dn6rkrte.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-C2K9mFg1.js → dagre-KV5264BT-COzej2en.js} +1 -1
- package/dist/client/assets/{de-CH-WLRDEVBV-C1swvmZy.js → de-CH-WLRDEVBV-CLV2tVw6.js} +1 -1
- package/dist/client/assets/{de-DE-DTI4WUSC-C0L6Nz8X.js → de-DE-DTI4WUSC-B53J0BQ8.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-DE0M0jaM.js → diagram-5BDNPKRD-BuK-UBuN.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-BfaRuSTT.js → diagram-G4DWMVQ6-CbswIU9X.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-91Bly_hN.js → diagram-MMDJMWI5-BE-yOVGX.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-fBkLwZGN.js → diagram-TYMM5635-CT8BdT4s.js} +1 -1
- package/dist/client/assets/{dist-FC9LftvP.js → dist-B98fHn5m.js} +1 -1
- package/dist/client/assets/{dist-VPEWg0Ob.js → dist-BE8C_ouo.js} +1 -1
- package/dist/client/assets/{dist-r5I9Jgww.js → dist-BEKQo64E.js} +1 -1
- package/dist/client/assets/{dist-BMlUxhOz.js → dist-BOP-dC-R.js} +1 -1
- package/dist/client/assets/{dist-DidT3Jay.js → dist-BPEi1dEF.js} +1 -1
- package/dist/client/assets/{dist-DAKGEzm0.js → dist-BScEL4VP.js} +1 -1
- package/dist/client/assets/dist-BfVljg0L2.js +1 -0
- package/dist/client/assets/{dist-PPAeaw4t.js → dist-BiCgLddE.js} +1 -1
- package/dist/client/assets/{dist-CSNMpi-w.js → dist-Bn8WRPs1.js} +1 -1
- package/dist/client/assets/{dist-CSAH9iuE.js → dist-Brrlevif.js} +1 -1
- package/dist/client/assets/{dist-Dwy75xI6.js → dist-CBEw2W2P.js} +1 -1
- package/dist/client/assets/{dist-Bkn7JaJv.js → dist-CJWCCWEW.js} +1 -1
- package/dist/client/assets/{dist-D1-dK0Dk.js → dist-CQVTTk81.js} +1 -1
- package/dist/client/assets/{dist-BSED50tI.js → dist-CaMl1R6P.js} +3 -3
- package/dist/client/assets/dist-CcG3Y7Wp.js +1 -0
- package/dist/client/assets/dist-CghBwrO3.js +1 -0
- package/dist/client/assets/dist-Csbx9lQ-.js +1 -0
- package/dist/client/assets/dist-D34Xzrah.js +1 -0
- package/dist/client/assets/dist-DLyohOXi.js +1 -0
- package/dist/client/assets/{dist-CqU98NzX.js → dist-DPCUH5MO.js} +1 -1
- package/dist/client/assets/{dist-74GtnE06.js → dist-DQiph4qx.js} +1 -1
- package/dist/client/assets/{dist-C0e9kfNh.js → dist-DWRyOl2w.js} +1 -1
- package/dist/client/assets/{dist-cQSK4Xor.js → dist-DZ2t5lUX.js} +1 -1
- package/dist/client/assets/{dist-D0dQAc9b.js → dist-Dbg8P4C5.js} +1 -1
- package/dist/client/assets/{dist-Co8HE14w.js → dist-DdAqzGFU.js} +1 -1
- package/dist/client/assets/{dist-CDUQ5ELn.js → dist-DwvSvkOE.js} +1 -1
- package/dist/client/assets/{dist-Doo91MTa.js → dist-WXLmfDGg.js} +1 -1
- package/dist/client/assets/{dist-DdR2aYqj.js → dist-aE0_04fl.js} +1 -1
- package/dist/client/assets/{dist-Bzb9nPam.js → dist-mPPUaHhq.js} +1 -1
- package/dist/client/assets/{dist-DSRCADL9.js → dist-v3i1ifes.js} +1 -1
- package/dist/client/assets/{dist-DBzteOlY.js → dist-wkd-N1L5.js} +1 -1
- package/dist/client/assets/{drawio-editor-CWLEpwps.js → drawio-editor-D4Qoluwz.js} +1 -1
- package/dist/client/assets/{drawioEditor-5rJhxjA4.js → drawioEditor-B65FWq-b.js} +2 -2
- package/dist/client/assets/{editor-session-CLOuvy37.js → editor-session-DV80PhYL.js} +3 -3
- package/dist/client/assets/{el-GR-ZXDJ2OS4-BH0saXds.js → el-GR-ZXDJ2OS4-DFmRQv0o.js} +1 -1
- package/dist/client/assets/{en-IQZW2TQM-CzlcEpq3.js → en-CMP6EMR6-D9x8hVSu.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-DUQcqEQ1.js → erDiagram-SMLLAGMA-6VFZA3Qb.js} +1 -1
- package/dist/client/assets/{es-ES-DYQHAD43-CyzL9Mni.js → es-ES-DYQHAD43-BiGWIrBG.js} +1 -1
- package/dist/client/assets/{eu-ES-QDSYU5Y3-D2-x316S.js → eu-ES-QDSYU5Y3-BjwS0kZi.js} +1 -1
- package/dist/client/assets/excalidraw-editor-BZCE9ydu.css +1 -0
- package/dist/client/assets/excalidraw-editor-hiJQt1cX.js +9 -0
- package/dist/client/assets/excalidraw-scene-MyNAJi2A.js +176 -0
- package/dist/client/assets/excalidrawEditor-BnbblxK4.js +2 -0
- package/dist/client/assets/{export-page-D2rCmrUH.js → export-page-BKDarp9x.js} +3 -3
- package/dist/client/assets/exportDocument-CULEGKmb.js +2 -0
- package/dist/client/assets/{fa-IR-26LZG4PM-D8-trU2x.js → fa-IR-26LZG4PM-BgANg2TD.js} +1 -1
- package/dist/client/assets/{fi-FI-6YS4KDE4-CCdRVFDQ.js → fi-FI-6YS4KDE4-CBL5f3oN.js} +1 -1
- package/dist/client/assets/{flatten-CX_XvnUf.js → flatten-DjXjUsvv.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-B_A5JyId.js → flowDiagram-DWJPFMVM-DO9RH8YQ.js} +1 -1
- package/dist/client/assets/{fr-FR-BRLLPTZC-Dqq-O5T_.js → fr-FR-BRLLPTZC-CRibNSLG.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-HM3CD7bk.js → ganttDiagram-T4ZO3ILL-B-NMvHWN.js} +1 -1
- package/dist/client/assets/gitGraph-7Q5UKJZL-DWNinXu4.js +1 -0
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-Dw7twZDm.js → gitGraphDiagram-UUTBAWPF-B95qkCUx.js} +1 -1
- package/dist/client/assets/{gl-ES-OKUZTLYG-BK7pbLbm.js → gl-ES-OKUZTLYG-DEDwa_xt.js} +1 -1
- package/dist/client/assets/{graphlib-DDD4Vdye.js → graphlib-CAwOVCJc.js} +1 -1
- package/dist/client/assets/{he-IL-26MGYIU7-C3BuYKyY.js → he-IL-26MGYIU7-47wxy70N.js} +1 -1
- package/dist/client/assets/{hi-IN-Q4ZOGTP2-BEvXWXnH.js → hi-IN-Q4ZOGTP2-bhV7c3dK.js} +1 -1
- package/dist/client/assets/{hu-HU-P2OXPSN5-BWWZeJNp.js → hu-HU-P2OXPSN5-xG-gBMzE.js} +1 -1
- package/dist/client/assets/{id-ID-2EIKXYN6-DxSKi_aJ.js → id-ID-2EIKXYN6-MQuYaNHo.js} +1 -1
- package/dist/client/assets/image-J2CAS7OM-DD4DaQTs.js +1 -0
- package/dist/client/assets/{image-blob-reduce.esm-DiuPkovC.js → image-blob-reduce.esm-D8JQdTFk.js} +1 -1
- package/dist/client/assets/{index-BbziNMqE.js → index-BjdYZiBM.js} +2 -2
- package/dist/client/assets/{index-BIt5EZXz.css → index-BryqP9QY.css} +1 -1
- package/dist/client/assets/info-OMHHGYJF-DtYG_rX0.js +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-DX-d3DMp.js → infoDiagram-42DDH7IO-C77Pt7T1.js} +1 -1
- package/dist/client/assets/{isEmpty-BKDbo1FH.js → isEmpty-CpfhGGBo.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-BHmsxpMs.js → ishikawaDiagram-UXIWVN3A-Cy1fwvvg.js} +1 -1
- package/dist/client/assets/{it-IT-4CFKVXI2-BmA8wW6q.js → it-IT-4CFKVXI2-v2kj-y7j.js} +1 -1
- package/dist/client/assets/{ja-JP-MAND2Z4V-CLS1jI9o.js → ja-JP-MAND2Z4V-BahXSQz-.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-jxDSjgE1.js → journeyDiagram-VCZTEJTY-CYWaI6re.js} +1 -1
- package/dist/client/assets/{jsx-runtime-B_8UNt-W.js → jsx-runtime-1KUJVfx8.js} +1 -1
- package/dist/client/assets/{kaa-HQRTCXTJ-W15DEDPz.js → kaa-HQRTCXTJ-BF26ydFa.js} +1 -1
- package/dist/client/assets/{kab-KAB-JKIKKTGH-MLh1inqS.js → kab-KAB-JKIKKTGH-CEIH0F80.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-od3qY1mE.js → kanban-definition-6JOO6SKY-DY1xE7tm.js} +1 -1
- package/dist/client/assets/{kk-KZ-HXQ63ZFC-BtFrPeLs.js → kk-KZ-HXQ63ZFC-CxWjc9Sf.js} +1 -1
- package/dist/client/assets/{km-KH-PKL3LSGX-xO5FyM9T.js → km-KH-PKL3LSGX-DJlCteEp.js} +1 -1
- package/dist/client/assets/{ko-KR-KXLREZX3-NZFoRybS.js → ko-KR-KXLREZX3-B1gtI_ci.js} +1 -1
- package/dist/client/assets/{ku-TR-MJ4IER3X-B5eVPIpK.js → ku-TR-MJ4IER3X-Bf41y2v2.js} +1 -1
- package/dist/client/assets/{line-CZsGUM4H.js → line-BCItEgq3.js} +1 -1
- package/dist/client/assets/{linear-B2dOdA24.js → linear-dsIQT_iU.js} +1 -1
- package/dist/client/assets/{lt-LT-H6WFQ6FJ-D_7_OeJD.js → lt-LT-H6WFQ6FJ-DA1or-Eo.js} +1 -1
- package/dist/client/assets/{lv-LV-GOCK6SJW-CnpKr0oQ.js → lv-LV-GOCK6SJW-qa0BoYMm.js} +1 -1
- package/dist/client/assets/main-QJcxyvDa.js +1404 -0
- package/dist/client/assets/{mermaid-parser.core-DtIbxv6L.js → mermaid-parser.core-CsTVsPcD.js} +2 -2
- package/dist/client/assets/{mermaid-runtime-vVJfjscE.js → mermaid-runtime-BGlnoUXY.js} +3 -3
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-C9qrdAqo.js → mindmap-definition-QFDTVHPH-DB_M5r-j.js} +1 -1
- package/dist/client/assets/{mr-IN-IXVLDMEQ-Pht2X_GK.js → mr-IN-IXVLDMEQ-DXFRgvgb.js} +1 -1
- package/dist/client/assets/{my-MM-YG6MYTTD-Cgq4HhPO.js → my-MM-YG6MYTTD-BKDIfalJ.js} +1 -1
- package/dist/client/assets/{nb-NO-XGWJISD2-Bn_Bk2un.js → nb-NO-XGWJISD2-DbwbopH8.js} +1 -1
- package/dist/client/assets/{nl-NL-XVDVCPNC-YkWSJS94.js → nl-NL-XVDVCPNC-ChSneTSU.js} +1 -1
- package/dist/client/assets/{nn-NO-EMX5MJX5-DhP5eZJ7.js → nn-NO-EMX5MJX5-Cf7ZWKWZ.js} +1 -1
- package/dist/client/assets/{oc-FR-ROEINTVO-D3udMPnr.js → oc-FR-ROEINTVO-lM7Nl7hD.js} +1 -1
- package/dist/client/assets/{pa-IN-ZYN6SUDY-CR5YzFig.js → pa-IN-ZYN6SUDY-C9WNUTeR.js} +1 -1
- package/dist/client/assets/packet-4T2RLAQJ-CUVefhAv.js +1 -0
- package/dist/client/assets/percentages-5DKR754L-DuhOjTM2.js +1 -0
- package/dist/client/assets/{pica-BEurQXMu.js → pica-CgGaIJly.js} +1 -1
- package/dist/client/assets/pie-ZZUOXDRM-BHBJ1dLX.js +1 -0
- package/dist/client/assets/{pieDiagram-DEJITSTG-BHXxj7wl.js → pieDiagram-DEJITSTG-BOo-WzjZ.js} +1 -1
- package/dist/client/assets/{pl-PL-6VTG7PHC-_wZuoIDM.js → pl-PL-6VTG7PHC-DqRVepnC.js} +1 -1
- package/dist/client/assets/{preview-diagram-utils-D8VypUft.js → preview-diagram-utils-Nqpp4FNV.js} +1 -1
- package/dist/client/assets/preview-render-compiler-BCB8u6iM.js +1 -0
- package/dist/client/assets/{preview-render-compiler-BHeDhYho.js → preview-render-compiler-Tkc6JX1O.js} +1 -1
- package/dist/client/assets/{preview-render-profile-BF6os3x9.js → preview-render-profile-Bf6R7v4w.js} +2 -2
- package/dist/client/assets/{preview-render-worker-C4AFtMIr.js → preview-render-worker-1LBLqgKu.js} +2 -2
- package/dist/client/assets/{pt-BR-5YFKRR5G-M7gIm2Hi.js → pt-BR-5YFKRR5G-CopLYEA6.js} +1 -1
- package/dist/client/assets/{pt-PT-GEIXXZ67-CcxWpkGj.js → pt-PT-GEIXXZ67-BjZ_Lphg.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-CWW7LORF.js → quadrantDiagram-34T5L4WZ-2vfo0l5S.js} +1 -1
- package/dist/client/assets/radar-PYXPWWZC-2jR4qZNU.js +1 -0
- package/dist/client/assets/{reduce-C6FuFJbE.js → reduce-ChpYjEUB.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-CTljNdQH.js → requirementDiagram-MS252O5E-CtUIQnWa.js} +1 -1
- package/dist/client/assets/{ro-RO-E2P6TFZI-qR9noVzP.js → ro-RO-E2P6TFZI-DakDz5Xu.js} +1 -1
- package/dist/client/assets/{room-DI7DXGeS.js → room-z2w9b96b.js} +1 -1
- package/dist/client/assets/{ru-RU-YBIIY43T-CE4S_RX8.js → ru-RU-YBIIY43T-BMvCT-XT.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-CCfFkC74.js → sankeyDiagram-XADWPNL6-tcSeuifE.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-BD9vj6WG.js → sequenceDiagram-FGHM5R23-DtF-1Kt2.js} +1 -1
- package/dist/client/assets/{si-LK-673C2CI2-Bv6Avh3z.js → si-LK-673C2CI2-hGdH1S9E.js} +1 -1
- package/dist/client/assets/{sk-SK-CKZHQ4AP-Cnlpp55z.js → sk-SK-CKZHQ4AP-DiRA-fj8.js} +1 -1
- package/dist/client/assets/{sl-SI-557H2GWM-BfGq7AQF.js → sl-SI-557H2GWM-DN94n_1-.js} +1 -1
- package/dist/client/assets/src-BuiVcSz-.js +1 -0
- package/dist/client/assets/{stateDiagram-FHFEXIEX-CpiX3KPd.js → stateDiagram-FHFEXIEX-DKk7Sb0f.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-DJUaiADr.js +1 -0
- package/dist/client/assets/subset-shared.chunk-CWNYNLru.js +1 -0
- package/dist/client/assets/{subset-worker.chunk-BSCP6IiC.js → subset-worker.chunk-kj1e3wjW.js} +1 -1
- package/dist/client/assets/{sv-SE-XOPKKDWS-B2_Vk-sp.js → sv-SE-XOPKKDWS-CkHUNABj.js} +1 -1
- package/dist/client/assets/{ta-IN-XBH7DQI3-BXQMZZIx.js → ta-IN-XBH7DQI3-W-157oVK.js} +1 -1
- package/dist/client/assets/{th-TH-TOCWH3R4-C-ZIYMfH.js → th-TH-TOCWH3R4-BsU-Pydr.js} +1 -1
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-BafRAkSF.js → timeline-definition-GMOUNBTQ-Bs6U53Mo.js} +1 -1
- package/dist/client/assets/{tr-TR-GXW6CYY5-dl702PMA.js → tr-TR-GXW6CYY5-CTddyq89.js} +1 -1
- package/dist/client/assets/treeView-SZITEDCU-DN5dP2ol.js +1 -0
- package/dist/client/assets/treemap-W4RFUUIX-Dva7DBJR.js +1 -0
- package/dist/client/assets/{uk-UA-IJKTNUDG-CUYQvSSF.js → uk-UA-IJKTNUDG-1LzXkII3.js} +1 -1
- package/dist/client/assets/{uz-UZ-TBZZEA4V-B9qw0PXX.js → uz-UZ-TBZZEA4V-kqm-qcUj.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-DSngq_Zj.js → vennDiagram-DHZGUBPP-DNnIjRae.js} +1 -1
- package/dist/client/assets/{vi-VN-MULSGNVB-DqxZ_sVc.js → vi-VN-MULSGNVB-C3H2AUhm.js} +1 -1
- package/dist/client/assets/wardley-RL74JXVD-CDZW5uzY.js +1 -0
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-CAEd2kJG.js → wardleyDiagram-NUSXRM2D-C-scJfPY.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-BScQpnru.js → xychartDiagram-5P7HB3ND-D3nQoxhz.js} +1 -1
- package/dist/client/assets/{yjs-provider-reset-guard-_Q3mj6tP.js → yjs-provider-reset-guard-DSPzcvAO.js} +2 -2
- package/dist/client/assets/{zh-CN-MVX3E32U-BM0aLuGc.js → zh-CN-MVX3E32U-BULPbsyl.js} +1 -1
- package/dist/client/assets/{zh-HK-JNU5RLIE-dmG_YD0d.js → zh-HK-JNU5RLIE-bNGmeSaW.js} +1 -1
- package/dist/client/assets/{zh-TW-LENVCA6T-LFgbiOi3.js → zh-TW-LENVCA6T-CQDp064P.js} +1 -1
- package/dist/client/drawio-editor.html +1 -1
- package/dist/client/excalidraw-editor.html +1 -1
- package/dist/client/export-document.html +1 -1
- package/dist/client/index.html +2 -2
- package/package.json +11 -11
- package/src/client/application/app-shell/presence-feature.js +265 -34
- package/src/client/application/app-shell/ui-feature-shell.js +26 -3
- package/src/client/application/app-shell/ui-feature-tab-activity.js +1 -0
- package/src/client/application/app-shell/workspace-feature.js +5 -2
- package/src/client/application/app-shell-elements.js +3 -0
- package/src/client/application/diagram-preview-export.js +304 -0
- package/src/client/application/mermaid-preview-hydrator.js +153 -23
- package/src/client/application/plantuml-preview-hydrator.js +155 -20
- package/src/client/application/preview-diagram-utils.js +48 -8
- package/src/client/application/preview-renderer.js +2 -0
- package/src/client/application/quick-switcher-loader.js +4 -1
- package/src/client/application/workspace-route-controller.js +35 -2
- package/src/client/application/workspace-state-store.js +1 -0
- package/src/client/bootstrap/collabmd-app-shell.js +9 -0
- package/src/client/domain/diagram-action-icons.js +21 -0
- package/src/client/domain/excalidraw-api-scene-sync.js +70 -0
- package/src/client/excalidraw-editor.js +106 -18
- package/src/client/infrastructure/excalidraw-room-client.js +41 -4
- package/src/client/presentation/app-shell-template.js +18 -1
- package/src/client/presentation/file-explorer-controller.js +10 -0
- package/src/client/presentation/file-explorer-view.js +6 -0
- package/src/client/presentation/image-lightbox-controller.js +290 -29
- package/src/client/styles/features/collaboration-presence.css +212 -0
- package/src/client/styles/features/diagram-preview.css +71 -4
- package/src/client/styles/features/embedded-preview.css +4 -6
- package/src/client/styles/features/media-lightbox.css +2 -0
- package/src/server/config/env.js +4 -0
- package/src/server/create-app-server.js +2 -0
- package/src/server/domain/bases/base-query-service.js +89 -7
- package/src/server/domain/collaboration/collaboration-room.js +10 -1
- package/src/server/infrastructure/http/create-request-handler.js +1 -0
- package/src/server/infrastructure/http/create-vault-api-handler.js +2 -0
- package/src/server/infrastructure/http/create-vault-api-query-handler.js +100 -26
- package/src/server/infrastructure/persistence/vault-file-store.js +136 -0
- package/src/server/infrastructure/workspace/file-system-sync-service.js +9 -11
- package/dist/client/assets/architecture-YZFGNWBL-CtU43_5T.js +0 -1
- package/dist/client/assets/channel-BDb1g_mJ.js +0 -1
- package/dist/client/assets/chunk-426QAEUC-CwJ7loGf.js +0 -1
- package/dist/client/assets/chunk-DpHwWhuW.js +0 -1
- package/dist/client/assets/chunk-NU2UP6EN-UVL-wkIc.js +0 -35
- package/dist/client/assets/chunk-QZHKN3VN-BnOS2iQW.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-MIbgV5UL.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-Bb70vg2O.js +0 -1
- package/dist/client/assets/clone-D6JWrlxJ.js +0 -1
- package/dist/client/assets/dist-B3lARV_e.js +0 -1
- package/dist/client/assets/dist-BCvzlTeb.js +0 -1
- package/dist/client/assets/dist-Bq8Z0WUT.js +0 -1
- package/dist/client/assets/dist-C8wdW7W4.js +0 -1
- package/dist/client/assets/dist-CHSg_nUM.js +0 -1
- package/dist/client/assets/dist-CZPTvk_g2.js +0 -1
- package/dist/client/assets/excalidraw-editor-Dj3i59LW.css +0 -1
- package/dist/client/assets/excalidraw-editor-ukEKPqGJ.js +0 -9
- package/dist/client/assets/excalidraw-scene-CDK3oDnm.js +0 -176
- package/dist/client/assets/excalidrawEditor-BJ8QLmWc.js +0 -2
- package/dist/client/assets/exportDocument-Dunnjgii.js +0 -2
- package/dist/client/assets/gitGraph-7Q5UKJZL-BrBlB49D.js +0 -1
- package/dist/client/assets/image-XLNPCCAD-BFNybKza.js +0 -1
- package/dist/client/assets/info-OMHHGYJF-BcmgcSx1.js +0 -1
- package/dist/client/assets/main-CN0kbtGk.js +0 -1369
- package/dist/client/assets/packet-4T2RLAQJ-DYYSvRuJ.js +0 -1
- package/dist/client/assets/percentages-5DKR754L-D7n4T776.js +0 -1
- package/dist/client/assets/pie-ZZUOXDRM-cG65Mc64.js +0 -1
- package/dist/client/assets/preview-render-compiler-D3QM1Ryz.js +0 -1
- package/dist/client/assets/radar-PYXPWWZC-Bmpup_xw.js +0 -1
- package/dist/client/assets/src-Pgt9Gp65.js +0 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-D_5ufPqT.js +0 -1
- package/dist/client/assets/subset-shared.chunk-C9HjwTXy.js +0 -1
- package/dist/client/assets/treeView-SZITEDCU-NbjhK5cw.js +0 -1
- package/dist/client/assets/treemap-W4RFUUIX-DJzRbb-x.js +0 -1
- package/dist/client/assets/wardley-RL74JXVD-DTNoH_BY.js +0 -1
|
@@ -75,13 +75,12 @@
|
|
|
75
75
|
|
|
76
76
|
.preview-content .mermaid-toolbar,
|
|
77
77
|
.mermaid-maximized-root .mermaid-toolbar {
|
|
78
|
-
|
|
78
|
+
width: 100%;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
.preview-content .mermaid-zoom-btn,
|
|
82
82
|
.mermaid-maximized-root .mermaid-zoom-btn {
|
|
83
|
-
|
|
84
|
-
line-height: 1.5;
|
|
83
|
+
flex-shrink: 0;
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
.preview-content .mermaid-zoom-btn:disabled,
|
|
@@ -174,13 +173,12 @@ body.mermaid-maximized-open::before {
|
|
|
174
173
|
|
|
175
174
|
.preview-content .plantuml-toolbar,
|
|
176
175
|
.plantuml-maximized-root .plantuml-toolbar {
|
|
177
|
-
|
|
176
|
+
width: 100%;
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
.preview-content .plantuml-tool-btn,
|
|
181
180
|
.plantuml-maximized-root .plantuml-tool-btn {
|
|
182
|
-
|
|
183
|
-
line-height: 1.5;
|
|
181
|
+
flex-shrink: 0;
|
|
184
182
|
}
|
|
185
183
|
|
|
186
184
|
.preview-content .plantuml-frame,
|
package/src/server/config/env.js
CHANGED
|
@@ -322,6 +322,10 @@ export function loadConfig(overrides = {}) {
|
|
|
322
322
|
httpRequestTimeoutMs: parsePositiveInt(process.env.HTTP_REQUEST_TIMEOUT_MS, 30_000),
|
|
323
323
|
git,
|
|
324
324
|
gitEnabled: git.enabled,
|
|
325
|
+
maxArchiveEntries: parsePositiveInt(process.env.COLLABMD_MAX_ARCHIVE_ENTRIES, 10_000),
|
|
326
|
+
maxBaseQueryRows: parsePositiveInt(process.env.COLLABMD_MAX_BASE_QUERY_ROWS, 5_000),
|
|
327
|
+
maxDownloadFileBytes: parsePositiveInt(process.env.COLLABMD_MAX_DOWNLOAD_FILE_BYTES, 268_435_456),
|
|
328
|
+
maxInitialSyncBytes: parsePositiveInt(process.env.COLLABMD_MAX_INITIAL_SYNC_BYTES, 16_777_216),
|
|
325
329
|
perfLoggingEnabled: overrides.perfLoggingEnabled ?? isPerfLoggingEnabled(process.env.COLLABMD_PERF_LOGGING),
|
|
326
330
|
port: parsePort(process.env.PORT, 1234),
|
|
327
331
|
nodeEnv,
|
|
@@ -77,6 +77,7 @@ export function createAppServer(config = loadConfig()) {
|
|
|
77
77
|
let fileSystemSyncService = null;
|
|
78
78
|
let workspaceMutationCoordinator = null;
|
|
79
79
|
const baseQueryService = new BaseQueryService({
|
|
80
|
+
maxResultRows: config.maxBaseQueryRows,
|
|
80
81
|
vaultFileStore,
|
|
81
82
|
workspaceStateProvider: () => workspaceMutationCoordinator?.workspaceState ?? null,
|
|
82
83
|
workspaceStateSynchronizer: () => fileSystemSyncService?.flushPendingChanges?.(),
|
|
@@ -104,6 +105,7 @@ export function createAppServer(config = loadConfig()) {
|
|
|
104
105
|
}),
|
|
105
106
|
getHydrateDelayMs: () => testControls.wsRoomHydrateDelayMs,
|
|
106
107
|
idleGraceMs: config.wsRoomIdleGraceMs,
|
|
108
|
+
maxInitialSyncBytes: config.maxInitialSyncBytes,
|
|
107
109
|
maxBufferedAmountBytes: config.wsMaxBufferedAmountBytes,
|
|
108
110
|
name,
|
|
109
111
|
onEmpty,
|
|
@@ -53,6 +53,32 @@ function sortRows(rows, sortChain = []) {
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function compareRowsBySortChain(left, right, sortChain = []) {
|
|
57
|
+
for (const sortConfig of sortChain) {
|
|
58
|
+
const delta = compareValues(left.rawCells[sortConfig.property], right.rawCells[sortConfig.property]);
|
|
59
|
+
if (delta !== 0) {
|
|
60
|
+
return sortConfig.direction === 'desc' ? -delta : delta;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return String(left.file.path ?? '').localeCompare(String(right.file.path ?? ''));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function insertSortedBounded(rows, row, {
|
|
68
|
+
limit,
|
|
69
|
+
sortChain = [],
|
|
70
|
+
}) {
|
|
71
|
+
let insertIndex = rows.findIndex((existingRow) => compareRowsBySortChain(row, existingRow, sortChain) < 0);
|
|
72
|
+
if (insertIndex === -1) {
|
|
73
|
+
insertIndex = rows.length;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
rows.splice(insertIndex, 0, row);
|
|
77
|
+
if (rows.length > limit) {
|
|
78
|
+
rows.pop();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
56
82
|
function escapeRegExp(value = '') {
|
|
57
83
|
return String(value ?? '').replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
58
84
|
}
|
|
@@ -102,16 +128,19 @@ function pruneFilterNodeForProperty(filterNode, propertyId = '') {
|
|
|
102
128
|
|
|
103
129
|
export class BaseQueryService {
|
|
104
130
|
constructor({
|
|
131
|
+
maxResultRows = 5_000,
|
|
105
132
|
vaultFileStore,
|
|
106
133
|
workspaceStateProvider = null,
|
|
107
134
|
workspaceStateSynchronizer = null,
|
|
108
135
|
}) {
|
|
136
|
+
this.maxResultRows = maxResultRows;
|
|
109
137
|
this.vaultFileStore = vaultFileStore;
|
|
110
138
|
this.snapshotStore = new BaseIndexSnapshotStore({
|
|
111
139
|
vaultFileStore,
|
|
112
140
|
workspaceStateProvider,
|
|
113
141
|
workspaceStateSynchronizer,
|
|
114
142
|
});
|
|
143
|
+
this.definitionCache = new Map();
|
|
115
144
|
this.propertyCatalogCache = new Map();
|
|
116
145
|
}
|
|
117
146
|
|
|
@@ -202,6 +231,25 @@ export class BaseQueryService {
|
|
|
202
231
|
return result;
|
|
203
232
|
}
|
|
204
233
|
|
|
234
|
+
getCachedDefinition(cacheKey, baseSource) {
|
|
235
|
+
const sourceText = String(baseSource ?? '');
|
|
236
|
+
const existing = this.definitionCache.get(cacheKey);
|
|
237
|
+
if (existing?.source === sourceText) {
|
|
238
|
+
return existing.definition;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const definition = normalizeBaseDefinition(sourceText);
|
|
242
|
+
this.definitionCache.set(cacheKey, {
|
|
243
|
+
definition,
|
|
244
|
+
source: sourceText,
|
|
245
|
+
});
|
|
246
|
+
if (this.definitionCache.size > 50) {
|
|
247
|
+
const firstKey = this.definitionCache.keys().next().value;
|
|
248
|
+
this.definitionCache.delete(firstKey);
|
|
249
|
+
}
|
|
250
|
+
return definition;
|
|
251
|
+
}
|
|
252
|
+
|
|
205
253
|
invalidatePropertyCatalogsExcept(scannedAt = '') {
|
|
206
254
|
Array.from(this.propertyCatalogCache.keys()).forEach((cacheKey) => {
|
|
207
255
|
if (cacheKey !== scannedAt) {
|
|
@@ -222,7 +270,7 @@ export class BaseQueryService {
|
|
|
222
270
|
throw new Error('Base source not found');
|
|
223
271
|
}
|
|
224
272
|
|
|
225
|
-
const definition =
|
|
273
|
+
const definition = this.getCachedDefinition(source === null ? `file:${basePath}` : `source:${sourcePath}:${basePath}`, baseSource);
|
|
226
274
|
const snapshot = await this.ensureIndexSnapshot({
|
|
227
275
|
basePath,
|
|
228
276
|
sourcePath,
|
|
@@ -251,12 +299,24 @@ export class BaseQueryService {
|
|
|
251
299
|
collectCandidateRows({
|
|
252
300
|
activeView,
|
|
253
301
|
astCache = new Map(),
|
|
302
|
+
columns = [],
|
|
254
303
|
definition,
|
|
255
304
|
evaluatedPropertyIds,
|
|
305
|
+
limit = null,
|
|
306
|
+
maxRows = this.maxResultRows,
|
|
256
307
|
snapshot,
|
|
308
|
+
sortChain = [],
|
|
309
|
+
search = '',
|
|
257
310
|
thisFile,
|
|
258
311
|
}) {
|
|
259
312
|
const rows = [];
|
|
313
|
+
const effectiveMaxRows = Number.isInteger(maxRows) && maxRows > 0 ? maxRows : Infinity;
|
|
314
|
+
const effectiveLimit = Number.isInteger(limit) && limit > 0 ? limit : Infinity;
|
|
315
|
+
const canBoundDuringCollection = Number.isFinite(Math.min(effectiveLimit, effectiveMaxRows))
|
|
316
|
+
&& sortChain.length > 0
|
|
317
|
+
&& !activeView.groupBy?.property
|
|
318
|
+
&& (activeView.summaries?.length ?? 0) === 0;
|
|
319
|
+
const hardLimit = Math.min(effectiveLimit, effectiveMaxRows);
|
|
260
320
|
|
|
261
321
|
snapshot.filePaths.forEach((filePath) => {
|
|
262
322
|
const row = snapshot.rowsByPath.get(filePath);
|
|
@@ -280,10 +340,23 @@ export class BaseQueryService {
|
|
|
280
340
|
rawCells[propertyId] = getPropertyValue(propertyId, row, definition, snapshot, thisFile, rowContext);
|
|
281
341
|
});
|
|
282
342
|
|
|
283
|
-
|
|
343
|
+
const candidateRow = {
|
|
284
344
|
file: row.file,
|
|
285
345
|
rawCells,
|
|
286
|
-
}
|
|
346
|
+
};
|
|
347
|
+
if (!rowMatchesSearch(candidateRow, columns, search)) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (canBoundDuringCollection) {
|
|
352
|
+
insertSortedBounded(rows, candidateRow, {
|
|
353
|
+
limit: hardLimit,
|
|
354
|
+
sortChain,
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
rows.push(candidateRow);
|
|
287
360
|
});
|
|
288
361
|
|
|
289
362
|
return rows;
|
|
@@ -378,15 +451,24 @@ export class BaseQueryService {
|
|
|
378
451
|
});
|
|
379
452
|
|
|
380
453
|
const astCache = new Map();
|
|
454
|
+
const sortChain = buildSortChain(context.activeView);
|
|
455
|
+
const requestedLimit = Number.isInteger(context.activeView.limit) && context.activeView.limit > 0
|
|
456
|
+
? context.activeView.limit
|
|
457
|
+
: null;
|
|
381
458
|
let rows = this.collectCandidateRows({
|
|
382
459
|
...context,
|
|
383
460
|
astCache,
|
|
461
|
+
limit: requestedLimit,
|
|
462
|
+
maxRows: this.maxResultRows,
|
|
463
|
+
search,
|
|
464
|
+
sortChain,
|
|
384
465
|
});
|
|
385
|
-
rows = rows
|
|
386
|
-
rows = sortRows(rows, buildSortChain(context.activeView));
|
|
466
|
+
rows = sortRows(rows, sortChain);
|
|
387
467
|
|
|
388
|
-
if (
|
|
389
|
-
rows = rows.slice(0,
|
|
468
|
+
if (requestedLimit != null) {
|
|
469
|
+
rows = rows.slice(0, Math.min(requestedLimit, this.maxResultRows));
|
|
470
|
+
} else if (Number.isInteger(this.maxResultRows) && this.maxResultRows > 0) {
|
|
471
|
+
rows = rows.slice(0, this.maxResultRows);
|
|
390
472
|
}
|
|
391
473
|
|
|
392
474
|
const payload = buildQueryResultPayload({
|
|
@@ -165,6 +165,7 @@ export class CollaborationRoom {
|
|
|
165
165
|
getHydrateDelayMs = null,
|
|
166
166
|
name,
|
|
167
167
|
idleGraceMs = 0,
|
|
168
|
+
maxInitialSyncBytes = 16_777_216,
|
|
168
169
|
maxBufferedAmountBytes,
|
|
169
170
|
perfLoggingEnabled = false,
|
|
170
171
|
vaultFileStore,
|
|
@@ -173,6 +174,7 @@ export class CollaborationRoom {
|
|
|
173
174
|
}) {
|
|
174
175
|
this.name = name;
|
|
175
176
|
this.idleGraceMs = idleGraceMs;
|
|
177
|
+
this.maxInitialSyncBytes = maxInitialSyncBytes;
|
|
176
178
|
this.maxBufferedAmountBytes = maxBufferedAmountBytes;
|
|
177
179
|
this.perfLoggingEnabled = perfLoggingEnabled;
|
|
178
180
|
this.documentStore = documentStore ?? new CollaborationDocumentStore({
|
|
@@ -576,10 +578,17 @@ export class CollaborationRoom {
|
|
|
576
578
|
this.debugMetrics.initialSyncCount += 1;
|
|
577
579
|
this.debugMetrics.lastInitialSyncAt = Date.now();
|
|
578
580
|
const initialSyncMessage = this.getInitialSyncMessage();
|
|
581
|
+
const initialSyncBytes = initialSyncMessage.byteLength;
|
|
582
|
+
if (initialSyncBytes > this.maxInitialSyncBytes) {
|
|
583
|
+
console.warn(
|
|
584
|
+
`[room:${this.name}] Initial sync payload is ${initialSyncBytes} bytes, exceeding ${this.maxInitialSyncBytes} bytes`,
|
|
585
|
+
);
|
|
586
|
+
}
|
|
579
587
|
logPerfEvent(this.perfLoggingEnabled, `room:${this.name}`, {
|
|
580
|
-
bytes:
|
|
588
|
+
bytes: initialSyncBytes,
|
|
581
589
|
count: this.debugMetrics.initialSyncCount,
|
|
582
590
|
event: 'initial-sync',
|
|
591
|
+
exceedsLimit: initialSyncBytes > this.maxInitialSyncBytes,
|
|
583
592
|
});
|
|
584
593
|
return sendMessage.call(this, ws, initialSyncMessage, this);
|
|
585
594
|
}
|
|
@@ -5,6 +5,7 @@ import { createVaultApiQueryHandler } from './create-vault-api-query-handler.js'
|
|
|
5
5
|
export function createVaultApiHandler({
|
|
6
6
|
baseQueryService = null,
|
|
7
7
|
backlinkIndex,
|
|
8
|
+
config = {},
|
|
8
9
|
docxExporter = null,
|
|
9
10
|
plantUmlRenderer = null,
|
|
10
11
|
roomRegistry = null,
|
|
@@ -14,6 +15,7 @@ export function createVaultApiHandler({
|
|
|
14
15
|
const handleVaultApiQuery = createVaultApiQueryHandler({
|
|
15
16
|
baseQueryService,
|
|
16
17
|
backlinkIndex,
|
|
18
|
+
config,
|
|
17
19
|
vaultFileStore,
|
|
18
20
|
workspaceMutationCoordinator,
|
|
19
21
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import archiver from 'archiver';
|
|
2
|
+
import { readdir } from 'node:fs/promises';
|
|
2
3
|
import { basename } from 'node:path';
|
|
4
|
+
import { join } from 'node:path';
|
|
3
5
|
|
|
4
6
|
import {
|
|
5
7
|
isBaseFilePath,
|
|
@@ -9,11 +11,14 @@ import {
|
|
|
9
11
|
isMermaidFilePath,
|
|
10
12
|
isPlantUmlFilePath,
|
|
11
13
|
} from '../../../domain/file-kind.js';
|
|
14
|
+
import { isIgnoredVaultEntry } from '../persistence/path-utils.js';
|
|
12
15
|
import { parseJsonBody } from './request-body.js';
|
|
13
16
|
import { jsonResponse, sendResponse, sendStreamResponse } from './http-response.js';
|
|
14
17
|
|
|
15
18
|
const SVG_MIME_TYPE = 'image/svg+xml';
|
|
16
19
|
const SVG_ATTACHMENT_CSP = "default-src 'none'; img-src 'self' data: blob:; style-src 'unsafe-inline'; sandbox";
|
|
20
|
+
const DEFAULT_MAX_ARCHIVE_ENTRIES = 10_000;
|
|
21
|
+
const DEFAULT_MAX_DOWNLOAD_FILE_BYTES = 268_435_456;
|
|
17
22
|
|
|
18
23
|
function encodeContentDispositionFilename(fileName) {
|
|
19
24
|
return encodeURIComponent(String(fileName ?? ''))
|
|
@@ -78,7 +83,8 @@ function selectReadOperation(vaultFileStore, filePath) {
|
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
async function streamDirectoryArchive(req, res, {
|
|
81
|
-
|
|
86
|
+
maxEntries = 10_000,
|
|
87
|
+
rootAbsolutePath = '',
|
|
82
88
|
rootName = 'archive',
|
|
83
89
|
} = {}) {
|
|
84
90
|
const archive = archiver('zip', {
|
|
@@ -99,22 +105,62 @@ async function streamDirectoryArchive(req, res, {
|
|
|
99
105
|
stream: archive,
|
|
100
106
|
});
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
archive.append('', { name: directoryName });
|
|
108
|
-
continue;
|
|
108
|
+
let entryCount = 0;
|
|
109
|
+
const appendEntry = () => {
|
|
110
|
+
entryCount += 1;
|
|
111
|
+
if (entryCount > maxEntries) {
|
|
112
|
+
throw new Error(`Directory archive exceeds ${maxEntries} entries`);
|
|
109
113
|
}
|
|
114
|
+
};
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
try {
|
|
117
|
+
const visitDirectory = async (directoryAbsolutePath, relativeDirectoryPath = '') => {
|
|
118
|
+
const dirEntries = (await readdir(directoryAbsolutePath, { withFileTypes: true }))
|
|
119
|
+
.filter((entry) => !isIgnoredVaultEntry(entry.name))
|
|
120
|
+
.sort((left, right) => {
|
|
121
|
+
if (left.isDirectory() && !right.isDirectory()) return -1;
|
|
122
|
+
if (!left.isDirectory() && right.isDirectory()) return 1;
|
|
123
|
+
return left.name.localeCompare(right.name, undefined, { sensitivity: 'base' });
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (dirEntries.length === 0) {
|
|
127
|
+
appendEntry();
|
|
128
|
+
archive.append('', {
|
|
129
|
+
name: relativeDirectoryPath ? `${rootName}/${relativeDirectoryPath}/` : `${rootName}/`,
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
115
133
|
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
for (const entry of dirEntries) {
|
|
135
|
+
const childAbsolutePath = join(directoryAbsolutePath, entry.name);
|
|
136
|
+
const childRelativePath = relativeDirectoryPath
|
|
137
|
+
? `${relativeDirectoryPath}/${entry.name}`
|
|
138
|
+
: entry.name;
|
|
139
|
+
|
|
140
|
+
if (entry.isDirectory()) {
|
|
141
|
+
await visitDirectory(childAbsolutePath, childRelativePath);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!entry.isFile()) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
appendEntry();
|
|
150
|
+
archive.file(childAbsolutePath, {
|
|
151
|
+
name: `${rootName}/${childRelativePath}`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
await visitDirectory(rootAbsolutePath);
|
|
157
|
+
await archive.finalize();
|
|
158
|
+
await responsePromise;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
archive.destroy(error);
|
|
161
|
+
await responsePromise.catch(() => {});
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
118
164
|
}
|
|
119
165
|
|
|
120
166
|
// --- Route handlers ---
|
|
@@ -257,7 +303,7 @@ async function handleFileRead(req, res, requestUrl, { vaultFileStore }) {
|
|
|
257
303
|
}
|
|
258
304
|
}
|
|
259
305
|
|
|
260
|
-
async function handleFileDownload(req, res, requestUrl, { vaultFileStore }) {
|
|
306
|
+
async function handleFileDownload(req, res, requestUrl, { config, vaultFileStore }) {
|
|
261
307
|
const filePath = requestUrl.searchParams.get('path');
|
|
262
308
|
if (!filePath) {
|
|
263
309
|
jsonResponse(req, res, 400, { error: 'Missing path parameter' });
|
|
@@ -265,19 +311,25 @@ async function handleFileDownload(req, res, requestUrl, { vaultFileStore }) {
|
|
|
265
311
|
}
|
|
266
312
|
|
|
267
313
|
try {
|
|
268
|
-
const download = await vaultFileStore.
|
|
314
|
+
const download = await vaultFileStore.openDownloadFileStream(filePath, {
|
|
315
|
+
maxBytes: config.maxDownloadFileBytes ?? DEFAULT_MAX_DOWNLOAD_FILE_BYTES,
|
|
316
|
+
});
|
|
269
317
|
if (!download) {
|
|
270
318
|
jsonResponse(req, res, 404, { error: 'File not found' });
|
|
271
319
|
return;
|
|
272
320
|
}
|
|
321
|
+
if (download.error) {
|
|
322
|
+
jsonResponse(req, res, download.statusCode || 400, { error: download.error });
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
273
325
|
|
|
274
|
-
|
|
275
|
-
body: download.content,
|
|
326
|
+
await sendStreamResponse(req, res, {
|
|
276
327
|
headers: createDownloadHeaders(
|
|
277
328
|
basename(String(download.path ?? 'download')),
|
|
278
329
|
download.mimeType || 'application/octet-stream',
|
|
279
330
|
),
|
|
280
331
|
statusCode: 200,
|
|
332
|
+
stream: download.stream,
|
|
281
333
|
});
|
|
282
334
|
} catch (error) {
|
|
283
335
|
console.error('[api] Failed to download file:', error.message);
|
|
@@ -285,7 +337,7 @@ async function handleFileDownload(req, res, requestUrl, { vaultFileStore }) {
|
|
|
285
337
|
}
|
|
286
338
|
}
|
|
287
339
|
|
|
288
|
-
async function handleDirectoryDownload(req, res, requestUrl, { vaultFileStore }) {
|
|
340
|
+
async function handleDirectoryDownload(req, res, requestUrl, { config, vaultFileStore }) {
|
|
289
341
|
const directoryPath = requestUrl.searchParams.get('path');
|
|
290
342
|
if (!directoryPath) {
|
|
291
343
|
jsonResponse(req, res, 400, { error: 'Missing path parameter' });
|
|
@@ -293,14 +345,23 @@ async function handleDirectoryDownload(req, res, requestUrl, { vaultFileStore })
|
|
|
293
345
|
}
|
|
294
346
|
|
|
295
347
|
try {
|
|
296
|
-
const result = await vaultFileStore.
|
|
348
|
+
const result = await vaultFileStore.resolveDirectoryDownloadRoot(directoryPath);
|
|
297
349
|
if (!result.ok) {
|
|
298
350
|
jsonResponse(req, res, result.error === 'Directory not found' ? 404 : 400, { error: result.error });
|
|
299
351
|
return;
|
|
300
352
|
}
|
|
353
|
+
const maxArchiveEntries = config.maxArchiveEntries ?? DEFAULT_MAX_ARCHIVE_ENTRIES;
|
|
354
|
+
const entryCount = await vaultFileStore.countDirectoryDownloadEntries(result.absolute, {
|
|
355
|
+
maxEntries: maxArchiveEntries,
|
|
356
|
+
});
|
|
357
|
+
if (!entryCount.withinLimit) {
|
|
358
|
+
jsonResponse(req, res, 413, { error: `Directory archive exceeds ${maxArchiveEntries} entries` });
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
301
361
|
|
|
302
362
|
await streamDirectoryArchive(req, res, {
|
|
303
|
-
|
|
363
|
+
maxEntries: maxArchiveEntries,
|
|
364
|
+
rootAbsolutePath: result.absolute,
|
|
304
365
|
rootName: result.rootName || 'archive',
|
|
305
366
|
});
|
|
306
367
|
} catch (error) {
|
|
@@ -313,7 +374,7 @@ async function handleDirectoryDownload(req, res, requestUrl, { vaultFileStore })
|
|
|
313
374
|
}
|
|
314
375
|
}
|
|
315
376
|
|
|
316
|
-
async function handleAttachmentRead(req, res, requestUrl, { vaultFileStore }) {
|
|
377
|
+
async function handleAttachmentRead(req, res, requestUrl, { config, vaultFileStore }) {
|
|
317
378
|
const filePath = requestUrl.searchParams.get('path');
|
|
318
379
|
if (!filePath) {
|
|
319
380
|
jsonResponse(req, res, 400, { error: 'Missing path parameter' });
|
|
@@ -326,16 +387,22 @@ async function handleAttachmentRead(req, res, requestUrl, { vaultFileStore }) {
|
|
|
326
387
|
}
|
|
327
388
|
|
|
328
389
|
try {
|
|
329
|
-
const attachment = await vaultFileStore.
|
|
390
|
+
const attachment = await vaultFileStore.openImageAttachmentReadStream(filePath, {
|
|
391
|
+
maxBytes: config.maxDownloadFileBytes ?? DEFAULT_MAX_DOWNLOAD_FILE_BYTES,
|
|
392
|
+
});
|
|
330
393
|
if (!attachment) {
|
|
331
394
|
jsonResponse(req, res, 404, { error: 'Attachment not found' });
|
|
332
395
|
return;
|
|
333
396
|
}
|
|
397
|
+
if (attachment.error) {
|
|
398
|
+
jsonResponse(req, res, attachment.statusCode || 400, { error: attachment.error });
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
334
401
|
|
|
335
|
-
|
|
336
|
-
body: attachment.content,
|
|
402
|
+
await sendStreamResponse(req, res, {
|
|
337
403
|
headers: createAttachmentHeaders(attachment),
|
|
338
404
|
statusCode: 200,
|
|
405
|
+
stream: attachment.stream,
|
|
339
406
|
});
|
|
340
407
|
} catch (error) {
|
|
341
408
|
console.error('[api] Failed to read attachment:', error.message);
|
|
@@ -384,10 +451,17 @@ function createRouteTable(context) {
|
|
|
384
451
|
export function createVaultApiQueryHandler({
|
|
385
452
|
baseQueryService = null,
|
|
386
453
|
backlinkIndex,
|
|
454
|
+
config = {},
|
|
387
455
|
vaultFileStore,
|
|
388
456
|
workspaceMutationCoordinator = null,
|
|
389
457
|
}) {
|
|
390
|
-
const context = {
|
|
458
|
+
const context = {
|
|
459
|
+
baseQueryService,
|
|
460
|
+
backlinkIndex,
|
|
461
|
+
config,
|
|
462
|
+
vaultFileStore,
|
|
463
|
+
workspaceMutationCoordinator,
|
|
464
|
+
};
|
|
391
465
|
const routes = createRouteTable(context);
|
|
392
466
|
|
|
393
467
|
return async function handleVaultApiQuery(req, res, requestUrl) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createReadStream } from 'fs';
|
|
1
2
|
import { mkdir, readFile, readdir, rename, rm, rmdir, stat, writeFile } from 'fs/promises';
|
|
2
3
|
import { basename, dirname, extname, join, relative, resolve } from 'path';
|
|
3
4
|
import sharp from 'sharp';
|
|
@@ -483,6 +484,36 @@ export class VaultFileStore {
|
|
|
483
484
|
}
|
|
484
485
|
}
|
|
485
486
|
|
|
487
|
+
async openImageAttachmentReadStream(filePath, { maxBytes = Infinity } = {}) {
|
|
488
|
+
const absolute = this.resolveContentPath(filePath, { requireVaultFile: false });
|
|
489
|
+
if (!absolute || !isImageAttachmentFilePath(filePath)) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
try {
|
|
494
|
+
const info = await stat(absolute);
|
|
495
|
+
if (!info.isFile()) {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
if (Number(info.size || 0) > maxBytes) {
|
|
499
|
+
return { error: 'Attachment is too large', statusCode: 413 };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
mimeType: IMAGE_EXTENSION_TO_MIME_TYPE[extname(filePath).toLowerCase()] || 'application/octet-stream',
|
|
504
|
+
path: filePath,
|
|
505
|
+
size: Number(info.size || 0),
|
|
506
|
+
stream: createReadStream(absolute),
|
|
507
|
+
};
|
|
508
|
+
} catch (error) {
|
|
509
|
+
if (error.code === 'ENOENT') {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
throw error;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
486
517
|
async writeMarkdownFile(filePath, content, options = {}) {
|
|
487
518
|
return this.writeContentFile(filePath, content, 'markdown', options);
|
|
488
519
|
}
|
|
@@ -602,6 +633,45 @@ export class VaultFileStore {
|
|
|
602
633
|
}
|
|
603
634
|
}
|
|
604
635
|
|
|
636
|
+
async openDownloadFileStream(filePath, { maxBytes = Infinity } = {}) {
|
|
637
|
+
const normalizedPath = String(filePath ?? '').replace(/\\/g, '/').trim();
|
|
638
|
+
if (!normalizedPath || !isVaultFilePath(normalizedPath)) {
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (isImageAttachmentFilePath(normalizedPath)) {
|
|
643
|
+
return this.openImageAttachmentReadStream(normalizedPath, { maxBytes });
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const absolute = this.resolveContentPath(normalizedPath, { requireVaultFile: false });
|
|
647
|
+
if (!absolute) {
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
try {
|
|
652
|
+
const info = await stat(absolute);
|
|
653
|
+
if (!info.isFile()) {
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
if (Number(info.size || 0) > maxBytes) {
|
|
657
|
+
return { error: 'File is too large to download', statusCode: 413 };
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
return {
|
|
661
|
+
mimeType: getDownloadMimeType(normalizedPath),
|
|
662
|
+
path: normalizedPath,
|
|
663
|
+
size: Number(info.size || 0),
|
|
664
|
+
stream: createReadStream(absolute),
|
|
665
|
+
};
|
|
666
|
+
} catch (error) {
|
|
667
|
+
if (error.code === 'ENOENT') {
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
throw error;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
605
675
|
async persistCollaborationState(filePath, {
|
|
606
676
|
commentThreads = [],
|
|
607
677
|
content = '',
|
|
@@ -861,6 +931,72 @@ export class VaultFileStore {
|
|
|
861
931
|
};
|
|
862
932
|
}
|
|
863
933
|
|
|
934
|
+
async resolveDirectoryDownloadRoot(dirPath) {
|
|
935
|
+
const normalizedPath = String(dirPath ?? '').replace(/\\/g, '/').trim();
|
|
936
|
+
const { absolute, error } = resolveVaultDirectoryPath(this.vaultDir, normalizedPath);
|
|
937
|
+
if (!absolute) {
|
|
938
|
+
return { ok: false, error };
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
try {
|
|
942
|
+
const info = await stat(absolute);
|
|
943
|
+
if (!info.isDirectory()) {
|
|
944
|
+
return { ok: false, error: 'Directory not found' };
|
|
945
|
+
}
|
|
946
|
+
} catch (statError) {
|
|
947
|
+
if (statError.code === 'ENOENT') {
|
|
948
|
+
return { ok: false, error: 'Directory not found' };
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
throw statError;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
return {
|
|
955
|
+
absolute,
|
|
956
|
+
ok: true,
|
|
957
|
+
rootName: basename(normalizedPath),
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
async countDirectoryDownloadEntries(directoryAbsolutePath, { maxEntries = Infinity } = {}) {
|
|
962
|
+
let count = 0;
|
|
963
|
+
const visitDirectory = async (currentDirectoryPath) => {
|
|
964
|
+
const dirEntries = sortDirectoryEntries(await readdir(currentDirectoryPath, { withFileTypes: true }))
|
|
965
|
+
.filter((entry) => !isIgnoredVaultEntry(entry.name));
|
|
966
|
+
|
|
967
|
+
if (dirEntries.length === 0) {
|
|
968
|
+
count += 1;
|
|
969
|
+
return count <= maxEntries;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
for (const entry of dirEntries) {
|
|
973
|
+
const childAbsolutePath = join(currentDirectoryPath, entry.name);
|
|
974
|
+
if (entry.isDirectory()) {
|
|
975
|
+
const withinLimit = await visitDirectory(childAbsolutePath);
|
|
976
|
+
if (!withinLimit) {
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
if (entry.isFile()) {
|
|
983
|
+
count += 1;
|
|
984
|
+
if (count > maxEntries) {
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
return true;
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
const withinLimit = await visitDirectory(directoryAbsolutePath);
|
|
994
|
+
return {
|
|
995
|
+
count,
|
|
996
|
+
withinLimit,
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
|
|
864
1000
|
async deleteFile(filePath) {
|
|
865
1001
|
const { absolute, error } = resolveVaultFilePath(this.vaultDir, filePath);
|
|
866
1002
|
if (!absolute) {
|