collabmd 0.1.54 → 0.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/bin/collabmd.js +19 -38
  2. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-cMeDxAEL.js +1 -0
  3. package/dist/client/assets/{abnfDiagram-VCTEODGH-DxNxad6-.js → abnfDiagram-VCTEODGH-D2UdmYvj.js} +1 -1
  4. package/dist/client/assets/{abnfDiagram-O67JEVCF-Dwt6a0Ds.js → abnfDiagram-YUKMZFIV-DbmU4Q-X.js} +1 -1
  5. package/dist/client/assets/api-client-utils-C5ESDKMG.js +1 -0
  6. package/dist/client/assets/architecture-7GRP2DOG-BBwRXFv3.js +1 -1
  7. package/dist/client/assets/architecture-WOLXFQ4H-C0NxYiG7.js +1 -0
  8. package/dist/client/assets/{architectureDiagram-NJMV4G6O-D5CGiX3G.js → architectureDiagram-47P4ROYG-C7OjXK9S.js} +3 -3
  9. package/dist/client/assets/{architectureDiagram-5GKGNRK7-C1uvg5id.js → architectureDiagram-5GKGNRK7-CSiUzzeN.js} +1 -1
  10. package/dist/client/assets/base-CaIEJUF9.css +1 -0
  11. package/dist/client/assets/{blockDiagram-BEXU5L5S-BgTM0var.js → blockDiagram-E7TT5TSB-DMG-YlZw.js} +3 -3
  12. package/dist/client/assets/{blockDiagram-I7D4REHJ-B2YonsoG.js → blockDiagram-I7D4REHJ-sXfAgK2w.js} +1 -1
  13. package/dist/client/assets/{browser-BKLM0ThC-BCLQGPD6-K2seJgRL.js → browser-BKLM0ThC-BCLQGPD6-CcMAHZXi.js} +1 -1
  14. package/dist/client/assets/{c4Diagram-7LVT6UL2-r4IwomZm.js → c4Diagram-7LVT6UL2-C88V_K-8.js} +1 -1
  15. package/dist/client/assets/{c4Diagram-YGBWAQC7-_xZPrNkB.js → c4Diagram-CRA5TL53-D3F9ElJv.js} +2 -2
  16. package/dist/client/assets/canvasEditor-BJkwGzO1.css +1 -0
  17. package/dist/client/assets/canvasEditor-sBK7KfrD.js +1 -0
  18. package/dist/client/assets/{chunk-6AZGARVD--pTGpDnx.js → chunk-24IY7LWP-flnn6SWX.js} +1 -1
  19. package/dist/client/assets/chunk-2BW5OAIV-CNFO1U_e.js +10 -0
  20. package/dist/client/assets/{chunk-2E4U76K2-CIQUuV9n.js → chunk-2E4U76K2-DEnS5IbF.js} +1 -1
  21. package/dist/client/assets/{chunk-5V3GS4D5-B5uC2oxu.js → chunk-3M4EKCLJ-D-sZGCtO.js} +1 -1
  22. package/dist/client/assets/chunk-3YJQHVM4-Ctp__8EK.js +2 -0
  23. package/dist/client/assets/{chunk-7PRAP22T-9uTvtc_-.js → chunk-4EA7E6EY-bU4wRJot.js} +1 -1
  24. package/dist/client/assets/{chunk-4HAMMTFA-q0ldNVvr.js → chunk-4HAMMTFA-CQy6Skzw.js} +1 -1
  25. package/dist/client/assets/{chunk-6K3QC6MW-JnuvEGV4.js → chunk-4S7OKTRW-BpUW13a3.js} +1 -1
  26. package/dist/client/assets/{chunk-ICYGCRZG-odvlDZyA.js → chunk-53FOQ5SW-5lPdGYP4.js} +1 -1
  27. package/dist/client/assets/{chunk-75Z2AOVW-DitkSoSG.js → chunk-75Z2AOVW-BRdhvVTZ.js} +1 -1
  28. package/dist/client/assets/{chunk-GWA4HPMP-CGmv2yIq.js → chunk-7TKQ45FW-rA2u-WUl.js} +1 -1
  29. package/dist/client/assets/{chunk-GTNCS2PH-ChgkzEIi.js → chunk-AW2ZBBNX-DL0KGAdi.js} +3 -3
  30. package/dist/client/assets/{chunk-747NJXEK-BjqqAsS9.js → chunk-BP2KR52E-DAQ1pzDV.js} +1 -1
  31. package/dist/client/assets/{chunk-CLGD4ZFX-BfYJtJm1.js → chunk-CLGD4ZFX-DJiSE0gD.js} +1 -1
  32. package/dist/client/assets/{chunk-5DYCD2WN-BKWCKnK-.js → chunk-DBDB3WZW-CXleNlok.js} +1 -1
  33. package/dist/client/assets/{chunk-DU6HZSFF-CWlP1Dk_.js → chunk-DU6HZSFF-C-18UZkS.js} +1 -1
  34. package/dist/client/assets/{chunk-MBY4JIJT-DTJ4UcAm.js → chunk-E2ZNV5FY-D_07zfWd.js} +3 -3
  35. package/dist/client/assets/chunk-EU5HNXII-CETVNUXF.js +213 -0
  36. package/dist/client/assets/{chunk-F27PBJKO-DPcsPcEs.js → chunk-F27PBJKO-_beIJos4.js} +1 -1
  37. package/dist/client/assets/{chunk-2ZTRR5NV-DcPRfelM.js → chunk-F6S3BTY2-DVWKCAHp.js} +1 -1
  38. package/dist/client/assets/{chunk-ISPTBLVO-BMsDq9Ha.js → chunk-FLFP27SU-CydzbSsY.js} +2 -2
  39. package/dist/client/assets/chunk-FVRAUYC3-C7b9SJ81.js +1 -0
  40. package/dist/client/assets/{chunk-GMAD6QVW-Bgk8qnty.js → chunk-GMAD6QVW-DnZH7DxV.js} +1 -1
  41. package/dist/client/assets/{chunk-GVQU2GXP-CQ8cl-Uu.js → chunk-GVQU2GXP-B0Vm415C.js} +1 -1
  42. package/dist/client/assets/chunk-H5A3YXKD-ChP7mNJq.js +41 -0
  43. package/dist/client/assets/{chunk-742MDFTN-D1nh6vNv.js → chunk-HJ2JQQFS-DQX7RePR.js} +1 -1
  44. package/dist/client/assets/{chunk-NETBCI7D-CmUwDWUZ.js → chunk-HTAEGDNF-C0PA_N-c.js} +1 -1
  45. package/dist/client/assets/{chunk-IMKFNOWR-CBqxfpcP.js → chunk-IMKFNOWR-DoO8IHzF.js} +1 -1
  46. package/dist/client/assets/{chunk-IH6LHLGP-BNevEHZK.js → chunk-KPI5JJXK-B2ld5-w4.js} +1 -1
  47. package/dist/client/assets/{chunk-WEXAMYUT-DDlVNp8J.js → chunk-KQW6MTUR-OQ4MyMr_.js} +1 -1
  48. package/dist/client/assets/{chunk-L3NEJ4N5-BflzkdTI.js → chunk-L3NEJ4N5-CvHossEU.js} +1 -1
  49. package/dist/client/assets/chunk-NGNAAXSQ-DqoPQk1a.js +136 -0
  50. package/dist/client/assets/{chunk-UA2S7LBM-DicYDjDM.js → chunk-NTY3LDVX-CVWLK_fh.js} +1 -1
  51. package/dist/client/assets/{chunk-UY3FDG6J-QT-rkt0y.js → chunk-OD3NTWWA-Dz9nCUGX.js} +1 -1
  52. package/dist/client/assets/{chunk-OSK3NFVY-DqeKV_pg.js → chunk-OSK3NFVY-C3JOcBao.js} +1 -1
  53. package/dist/client/assets/{chunk-P2QGCYS3-BA--DhpW.js → chunk-P2QGCYS3-Bfo8qS8r.js} +1 -1
  54. package/dist/client/assets/{chunk-POPQ4Y6H-V_NEc45n.js → chunk-POPQ4Y6H-sv6rCftH.js} +1 -1
  55. package/dist/client/assets/{chunk-PWAF6VOD-D_kLse-N.js → chunk-PWAF6VOD-B-AT-L2H.js} +1 -1
  56. package/dist/client/assets/{chunk-3Z5EZCMW-BAnA6eQ7.js → chunk-QNH66VMT-Cb9xxTwQ.js} +1 -1
  57. package/dist/client/assets/{chunk-SHT3W25Y-YM3S-A_M.js → chunk-SHT3W25Y-C1lu518T.js} +1 -1
  58. package/dist/client/assets/{chunk-GNY47TPC-CTrH5O5R.js → chunk-SVEVUXB4-BnM-LXop.js} +1 -1
  59. package/dist/client/assets/{chunk-SVP7TREG-DdNhDOmW.js → chunk-SVP7TREG-CKqt0syj.js} +1 -1
  60. package/dist/client/assets/{chunk-TICWLB2K-BGGgCr4x.js → chunk-TICWLB2K-D2ZnWAfF.js} +1 -1
  61. package/dist/client/assets/{chunk-TLUHSLCS-DCZhIDYA.js → chunk-TLUHSLCS-BMIhqv1X.js} +1 -1
  62. package/dist/client/assets/{chunk-6EIED4P4-DBVWq7Tz.js → chunk-TPMEZKFX-DIPHIqGb.js} +1 -1
  63. package/dist/client/assets/{chunk-6TQVIW2G-BSj0l_pu.js → chunk-VPELOWWC-DXayM28-.js} +1 -1
  64. package/dist/client/assets/chunk-VPRB5NB3-BqaJfj_v.js +127 -0
  65. package/dist/client/assets/{chunk-I5DQTOEV-aBZooNp1.js → chunk-VTWWFHGB-SZnJiyWY.js} +1 -1
  66. package/dist/client/assets/{chunk-KI3K4JFJ-FTtDwx3-.js → chunk-VZTHESGH-eHyXmK8W.js} +1 -1
  67. package/dist/client/assets/{chunk-7INBJB4K-CDmiHbaX.js → chunk-XC4XBNZT-D9oehSn8.js} +20 -20
  68. package/dist/client/assets/{chunk-XHIXRSVI-DN_fEwws.js → chunk-YK26KJH5-DVy3MGMd.js} +1 -1
  69. package/dist/client/assets/{chunk-6AEJRKK7-DTVZj5bY.js → chunk-Z6ETV63D-DOcrnz-P.js} +1 -1
  70. package/dist/client/assets/{chunk-OUJLGHUK-75UXlPjl.js → chunk-ZO67DCNQ-BAOMIkLF.js} +1 -1
  71. package/dist/client/assets/classDiagram-ZZMXUADV-BmETdFmC.js +1 -0
  72. package/dist/client/assets/{classDiagram-v2-NBCMYWYE-3TQORq33.js → classDiagram-v2-K4WV4PDN-eaadfJDB.js} +3 -3
  73. package/dist/client/assets/classDiagram-v2-VYDZK3BY-BmETdFmC.js +1 -0
  74. package/dist/client/assets/{comment-markdown-renderer-Bxi_JRSR.js → comment-markdown-renderer-CpBKaj7H.js} +1 -1
  75. package/dist/client/assets/comment-thread-store-DUQsWtnu.js +1 -0
  76. package/dist/client/assets/comment-threads-DnfkLVJA.js +4 -0
  77. package/dist/client/assets/comment-ui-shared-D_pgPUti.js +7 -0
  78. package/dist/client/assets/cynefin-EF2NZ3EQ-DVkJeZ8i.js +1 -0
  79. package/dist/client/assets/cynefin-OW5HDTMX-CF3N9j1_.js +1 -1
  80. package/dist/client/assets/{cynefinDiagram-VND7K2PF-DwfMZ3vk.js → cynefinDiagram-3GCD6N5R-DjpAsBHC.js} +1 -1
  81. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-DTnLZaO7.js → cynefinDiagram-5FMLGOSQ-D2rFQG67.js} +1 -1
  82. package/dist/client/assets/dagre-C-rnJpZF.js +1 -0
  83. package/dist/client/assets/{dagre-GXQ25YYZ-Vtyx08Qh.js → dagre-GXQ25YYZ-Cku9eia9.js} +2 -2
  84. package/dist/client/assets/{dagre-6A5THRUB-DewyAGK6.js → dagre-W4DXFKR2-DOMOIsPd.js} +2 -2
  85. package/dist/client/assets/deferred-collab-C9aa9cvT.css +1 -0
  86. package/dist/client/assets/deferred-git-BPQ-UgrN.css +1 -0
  87. package/dist/client/assets/deferred-preview-B-RebLry.css +1 -0
  88. package/dist/client/assets/{diagram-22UHCM2B-DbZirFfl.js → diagram-2UJZ2QOL-D8WvnEyx.js} +6 -6
  89. package/dist/client/assets/{diagram-3UASUU5V-DmhdYv6_.js → diagram-OVF4WLC6-D8_escYE.js} +2 -2
  90. package/dist/client/assets/{diagram-CDSNMT55-D_qyS11R.js → diagram-PFPMY2P6-B1izZfrN.js} +3 -3
  91. package/dist/client/assets/{diagram-S7CK7UJ4-CGTzfo2f.js → diagram-S7CK7UJ4-BzicH2t-.js} +1 -1
  92. package/dist/client/assets/{diagram-MLGK6HIB-DIBG6Ivu.js → diagram-UMYRVEAY-Djf7WDjZ.js} +1 -1
  93. package/dist/client/assets/{diagram-UQ7AKVKN-CWZS8QtB.js → diagram-UQ7AKVKN-DqX4zTtr.js} +1 -1
  94. package/dist/client/assets/{diagram-VSXAHHWV-DaO1nOZF.js → diagram-VSXAHHWV-DnVbfI4Y.js} +1 -1
  95. package/dist/client/assets/{diagram-VX7I27RA-B54P6Cyf.js → diagram-VX7I27RA-D-Dj0TQC.js} +1 -1
  96. package/dist/client/assets/{diagram-MPIPVDR6-D9XsALDV.js → diagram-YEKJPTXX-B40bP3Yr.js} +2 -2
  97. package/dist/client/assets/{diagram-Z3DM3KII-Cl2EXiXp.js → diagram-Z3DM3KII-_iT7Uz5p.js} +1 -1
  98. package/dist/client/assets/diagram-ZIFT7M5P-BUUK0oNw.js +3 -0
  99. package/dist/client/assets/{direct-engine-DVLMOJWp-C-YL5NFb.js → direct-engine-DVLMOJWp-DWtWIifK.js} +1 -1
  100. package/dist/client/assets/dist-26Ce-5t4.js +1 -0
  101. package/dist/client/assets/dist-8MLNn-I6.js +1 -0
  102. package/dist/client/assets/dist-Amm5Pr1C.js +1 -0
  103. package/dist/client/assets/dist-BXXPaoUV.js +1 -0
  104. package/dist/client/assets/{dist-CoXN2D3R.js → dist-Bkb-_VdB.js} +1 -1
  105. package/dist/client/assets/dist-Bl4yuUS9.js +1 -0
  106. package/dist/client/assets/{dist-lw5TGjI6.js → dist-C2CGvCPd.js} +1 -1
  107. package/dist/client/assets/dist-C2niyEh0.js +1 -0
  108. package/dist/client/assets/{dist-DOHWxIty.js → dist-CFCSUmJk.js} +1 -1
  109. package/dist/client/assets/dist-CHUI56fT.js +6 -0
  110. package/dist/client/assets/dist-CJh3Qrid.js +13 -0
  111. package/dist/client/assets/{dist-Ch6Sr9KF.js → dist-CKxETpSC.js} +3 -3
  112. package/dist/client/assets/dist-CSHJthAI.js +2 -0
  113. package/dist/client/assets/dist-CbKnZGN4.js +1 -0
  114. package/dist/client/assets/{dist-KrdpB_GB.js → dist-Cik4RJXj.js} +1 -1
  115. package/dist/client/assets/{dist-uk11ih8u.js → dist-CqkAY6Ot.js} +2 -2
  116. package/dist/client/assets/dist-D2ql2LCd.js +1 -0
  117. package/dist/client/assets/{dist-BpAUe9sL.js → dist-D47MOYFN.js} +1 -1
  118. package/dist/client/assets/dist-DBhUaexM.js +1 -0
  119. package/dist/client/assets/dist-DJux6Vc5.js +1 -0
  120. package/dist/client/assets/{dist-9Eodxf4G.js → dist-DLNdMWPH.js} +1 -1
  121. package/dist/client/assets/dist-DPJj-Y3l.js +1 -0
  122. package/dist/client/assets/{dist-BSAZ-Hek.js → dist-DRYFMufe.js} +6 -6
  123. package/dist/client/assets/{dist-BrKhPlc9.js → dist-DTGcVSU8.js} +1 -1
  124. package/dist/client/assets/dist-DlOxjzWi.js +9 -0
  125. package/dist/client/assets/{dist-BT9gJXCb.js → dist-DogjjM_B.js} +1 -1
  126. package/dist/client/assets/dist-Dyv_RvyB.js +23 -0
  127. package/dist/client/assets/dist-FUFeH5Cx.js +1 -0
  128. package/dist/client/assets/dist-It70ktCU.js +1 -0
  129. package/dist/client/assets/dist-QMvcnJHf.js +1 -0
  130. package/dist/client/assets/dist-QN1K2czv.js +11 -0
  131. package/dist/client/assets/dist-W8ilOKl3.js +1 -0
  132. package/dist/client/assets/dist-_17-t9qP.js +1 -0
  133. package/dist/client/assets/{dist-DeCV9FU4.js → dist-uE774WWs.js} +1 -1
  134. package/dist/client/assets/document-formatter-DtXmKZcy.js +1 -0
  135. package/dist/client/assets/drawioEditor-DO6IOaJ1.js +9 -0
  136. package/dist/client/assets/{ebnfDiagram-PWID7BFC-PfC84FyI.js → ebnfDiagram-PWID7BFC-IemGPf9X.js} +1 -1
  137. package/dist/client/assets/{ebnfDiagram-ZINNZB2B-DYvm_QtE.js → ebnfDiagram-VR2GEFS7-9fXqy1DI.js} +1 -1
  138. package/dist/client/assets/editor-session-CPsqXY_A.js +13 -0
  139. package/dist/client/assets/elk-IJKZMXRS-DsbrbBYg.js +27 -0
  140. package/dist/client/assets/embedded-editor-base-C44ZcCZv.css +1 -0
  141. package/dist/client/assets/{embedpdf-TkbBYowM.js → embedpdf-BfUI-3pv.js} +1 -1
  142. package/dist/client/assets/{embedpdf-cl9qiF45-itpgqvGY.js → embedpdf-cl9qiF45-CLMxJTMP.js} +2 -2
  143. package/dist/client/assets/en-7ZVUCEYH-C_VXKxxb.js +1 -0
  144. package/dist/client/assets/{erDiagram-OPXOYQCR-o8GRv8A_.js → erDiagram-O2IAPWRE-Cdadm-HN.js} +2 -2
  145. package/dist/client/assets/{erDiagram-RLTQ6QDP-C9cJl5NB.js → erDiagram-RLTQ6QDP-CGGmjm8t.js} +1 -1
  146. package/dist/client/assets/eventmodeling-K75KTNOO-BWBlZ5cR.js +1 -0
  147. package/dist/client/assets/eventmodeling-NTZA5JFV-CDy1bN6j.js +1 -1
  148. package/dist/client/assets/excalidraw-element-link-NQnskRkm.js +1 -0
  149. package/dist/client/assets/excalidraw-scene-DLlw4jyc.js +1 -0
  150. package/dist/client/assets/excalidrawEditor-DiKOIudt.css +1 -0
  151. package/dist/client/assets/excalidrawEditor-W2lZ5Mej.js +9 -0
  152. package/dist/client/assets/export-page-Bomh9oEr.js +46 -0
  153. package/dist/client/assets/exportDocument-BFIOECJ3.js +2 -0
  154. package/dist/client/assets/exportDocument-D0mONgQ4.css +1 -0
  155. package/dist/client/assets/file-kind-BGxTVHan.js +1 -0
  156. package/dist/client/assets/{file-search-BA8o_gs0.js → file-search-Dk2O14Vw.js} +1 -1
  157. package/dist/client/assets/flowDiagram-HODETNUW-DcVVYJUZ.js +1 -0
  158. package/dist/client/assets/flowDiagram-OXPTDLAJ-Dy6y46oF.js +1 -0
  159. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-x40PW0Ah.js → ganttDiagram-EL5Y4UJY-Duu4KnsU.js} +1 -1
  160. package/dist/client/assets/ganttDiagram-R7TSEDQI-BWy52pjn.js +292 -0
  161. package/dist/client/assets/gitGraph-4MIJSDKK-B-rpDYbz.js +1 -1
  162. package/dist/client/assets/gitGraph-VSP46ZUC-1499lQAI.js +1 -0
  163. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-ahsNaZsp.js → gitGraphDiagram-WWUBYQGX-CaJ0vC1a.js} +1 -1
  164. package/dist/client/assets/gitGraphDiagram-XJZIOB7I-DJwp9ilx.js +106 -0
  165. package/dist/client/assets/graphlib-DS17s2tU.js +1 -0
  166. package/dist/client/assets/image-6XY3GD3F-DCWbu6d4.js +1 -0
  167. package/dist/client/assets/image-lightbox-controller-DAcXEXxT.js +184 -0
  168. package/dist/client/assets/index-CglpXOg7.css +1 -0
  169. package/dist/client/assets/index-D3WGkxfI.js +960 -0
  170. package/dist/client/assets/info-A6RAGUB7-BlutK7BT.js +1 -1
  171. package/dist/client/assets/info-OHQRW6UA-BDFQOo4H.js +1 -0
  172. package/dist/client/assets/{infoDiagram-27XIBGKW-MrZyptIy.js → infoDiagram-27XIBGKW-DBJh7QOu.js} +1 -1
  173. package/dist/client/assets/{infoDiagram-VRGFBTTK-KkUjDRAQ.js → infoDiagram-5W2HQ5XZ-DmWsqJ0w.js} +1 -1
  174. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-Bnt9yM0O.js → ishikawaDiagram-5VMMS53U-CeEbSJem.js} +1 -1
  175. package/dist/client/assets/{ishikawaDiagram-OU5B5YK6-Di9BcpOY.js → ishikawaDiagram-K3B6WC7H-DH1NI35G.js} +2 -2
  176. package/dist/client/assets/{journeyDiagram-3NMN7TZE-Bl0abK1r.js → journeyDiagram-3NMN7TZE-BoIEEr6U.js} +1 -1
  177. package/dist/client/assets/{journeyDiagram-ZHPQQLJL-J-sGrs9e.js → journeyDiagram-COXZFDF6-CnHV2f9V.js} +3 -3
  178. package/dist/client/assets/{kanban-definition-PNTS6WVX-5ZDV_yIa.js → kanban-definition-P3RFRI5V-Cxvn5ZAG.js} +4 -4
  179. package/dist/client/assets/{kanban-definition-UXKFOSKX-DMgUfNt0.js → kanban-definition-UXKFOSKX-BY16Tgbr.js} +1 -1
  180. package/dist/client/assets/keyboard-shortcuts-BWNCBJqw.js +1 -0
  181. package/dist/client/assets/lobby-presence-DNNXcuwR.js +1 -0
  182. package/dist/client/assets/{markdown-CZ1tYEW8.js → markdown-DU84620G.js} +1 -1
  183. package/dist/client/assets/markdown-headings-zYEUahfW.js +41 -0
  184. package/dist/client/assets/{markdown-math-CyyBVuDO.js → markdown-math-B96cnrz1.js} +11 -11
  185. package/dist/client/assets/{mermaid-parser.core-Bpogunsh.js → mermaid-parser.core-R-uwU5kf.js} +3 -3
  186. package/dist/client/assets/{mermaid-parser.core-DBy--Jc0.js → mermaid-parser.core-mE6t1qEO.js} +1 -1
  187. package/dist/client/assets/mermaid.core-D8Z6LN7O.js +10 -0
  188. package/dist/client/assets/{mindmap-definition-NLK3R4M7-ByVb-0vj.js → mindmap-definition-LZFPQGKD-DVfFenfJ.js} +3 -3
  189. package/dist/client/assets/{mindmap-definition-YA3MSWOX-DBZN5_GH.js → mindmap-definition-YA3MSWOX-DtiE80UJ.js} +1 -1
  190. package/dist/client/assets/packet-AYTQ26CC-DvbY8dI6.js +1 -1
  191. package/dist/client/assets/packet-JDAUHWVQ-DJ9K2MA4.js +1 -0
  192. package/dist/client/assets/{pegDiagram-GJSIUBJH-aost1sSO.js → pegDiagram-BGZESJAR-DxfvEcwv.js} +1 -1
  193. package/dist/client/assets/{pegDiagram-XKGWAZYB-DRo8CZu3.js → pegDiagram-XKGWAZYB-CyozY-Kt.js} +1 -1
  194. package/dist/client/assets/pie-WAS4IAKB-DWSm9SSD.js +1 -1
  195. package/dist/client/assets/pie-XZMESJXO-CQIQasY-.js +1 -0
  196. package/dist/client/assets/{pieDiagram-5QR66LMP-BICdpEuz.js → pieDiagram-CAPJLFHJ-CRlMcrv3.js} +2 -2
  197. package/dist/client/assets/{pieDiagram-E7YTZNPT-CZThaHsc.js → pieDiagram-E7YTZNPT-BRdmTkDq.js} +1 -1
  198. package/dist/client/assets/preload-helper-CYtfOYgs.js +1 -0
  199. package/dist/client/assets/preview-render-compiler-D_aJv7Ew.js +3 -0
  200. package/dist/client/assets/{preview-render-worker-BA4VK_GY.js → preview-render-worker-dFNyrVyB.js} +46 -42
  201. package/dist/client/assets/prod-ItolaHmf.js +145 -0
  202. package/dist/client/assets/prod-rdly4JJQ.js +1 -0
  203. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-C5iowkl_.js → quadrantDiagram-AXDQQJYC-7QyPIXkF.js} +1 -1
  204. package/dist/client/assets/{quadrantDiagram-O4NWA36T-Bgx5bF97.js → quadrantDiagram-GDMTTRAM-DE30uqTl.js} +3 -3
  205. package/dist/client/assets/quick-switcher-controller-DsK70I7K.js +1 -0
  206. package/dist/client/assets/radar-ABXABTNO-ByfpCXh9.js +1 -0
  207. package/dist/client/assets/radar-RG4KPBEZ-BfNQUEQy.js +1 -1
  208. package/dist/client/assets/railroad-74A4TZTK-BaQ6U6eJ.js +1 -1
  209. package/dist/client/assets/railroad-I3PHUGI6-CTUn9HhI.js +1 -0
  210. package/dist/client/assets/railroad-abnf-HS5TGJTU-BJ3KZw7J.js +1 -1
  211. package/dist/client/assets/railroad-abnf-LNEFI6M7-Ct-b-y0F.js +1 -0
  212. package/dist/client/assets/railroad-ebnf-DWYD2UWJ-BZMYMWOe.js +1 -0
  213. package/dist/client/assets/railroad-ebnf-LZEXJU2U-DA0sEq7w.js +1 -1
  214. package/dist/client/assets/railroad-peg-JR7BVNR7-Dj23PxYc.js +1 -0
  215. package/dist/client/assets/railroad-peg-WCYAUIDC-DCmlICzO.js +1 -1
  216. package/dist/client/assets/{railroadDiagram-O6MQD6OU-BTt_rKjT.js → railroadDiagram-O6MQD6OU-BPk3RS2D.js} +1 -1
  217. package/dist/client/assets/{railroadDiagram-XR7U4H2S-DbVoNgSz.js → railroadDiagram-SM67HX2B-CZRXJ647.js} +1 -1
  218. package/dist/client/assets/{requirementDiagram-BXWQKSXE-BkvazG7r.js → requirementDiagram-BXWQKSXE-BRwfym6z.js} +1 -1
  219. package/dist/client/assets/{requirementDiagram-PLB6GJNP-BT0j9C40.js → requirementDiagram-X7JNWC4A-BofCuLJA.js} +4 -4
  220. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-C_IemB9h.js → sankeyDiagram-P5KCCOFB-D4LcrKpW.js} +1 -1
  221. package/dist/client/assets/{sankeyDiagram-IPEJSGJF-X1BCUIrf.js → sankeyDiagram-UM26HJRW-CLKMDbej.js} +3 -3
  222. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-CxFBgLGd.js → sequenceDiagram-WJ2MYXX4-DQjtv-Bs.js} +1 -1
  223. package/dist/client/assets/sequenceDiagram-ZO4K6R2Y-CDP_m6ma.js +169 -0
  224. package/dist/client/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  225. package/dist/client/assets/sizeCapture-INFHLROL-BMR1ovSU.js +1 -0
  226. package/dist/client/assets/src-D5mvpivG.js +2 -0
  227. package/dist/client/assets/{standalone-DbyFjvTU.js → standalone-D_lg5NC9.js} +1 -1
  228. package/dist/client/assets/{stateDiagram-D77RDMKH-BaSQ6Owj.js → stateDiagram-D77RDMKH-DSMvV-kF.js} +1 -1
  229. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-ClmOOUsT.js +1 -0
  230. package/dist/client/assets/{stateDiagram-v2-GCMORJYK-CsVcfwVp.js → stateDiagram-v2-TBUQTH76-Dc5-FKzd.js} +2 -2
  231. package/dist/client/assets/{swimlanes-42K2YHIH-CALFEmiS.js → swimlanes-42K2YHIH-BUz31lO3.js} +1 -1
  232. package/dist/client/assets/{swimlanes-2SLR337P-CnYTVqRX.js → swimlanes-N4OXWK64-Dd3dFdPD.js} +1 -1
  233. package/dist/client/assets/swimlanesDiagram-K3J5GTZL-Bz9gFdls.js +8 -0
  234. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DoDs3zod.js +8 -0
  235. package/dist/client/assets/{timeline-definition-24CTP7MA-zse-5Dbm.js → timeline-definition-24CTP7MA-BvqCvSjy.js} +1 -1
  236. package/dist/client/assets/{timeline-definition-EJHVYXUP-BhqPlKkN.js → timeline-definition-YOQAKGHF-D2XWPSLs.js} +3 -3
  237. package/dist/client/assets/treeView-D4JQ5SDB-DcX7Bx0H.js +1 -0
  238. package/dist/client/assets/treeView-Q6P3EWNA-BvHOzbu9.js +1 -1
  239. package/dist/client/assets/treemap-SAJKECNS-BcCHmcAX.js +1 -0
  240. package/dist/client/assets/treemap-WGGIJYW6-oety7paS.js +1 -1
  241. package/dist/client/assets/usecaseDiagram-VIAY4XPW-CDe-IMjS.js +328 -0
  242. package/dist/client/assets/vault-api-client-DrRW0QwO.js +7 -0
  243. package/dist/client/assets/{vennDiagram-4TSXK5OY-DgHr6cJD.js → vennDiagram-4TSXK5OY-BW6Qp12d.js} +1 -1
  244. package/dist/client/assets/{vennDiagram-UO4OBE2U-BRwLn2Q1.js → vennDiagram-BLWOH2XV-KxIPKpHi.js} +3 -3
  245. package/dist/client/assets/wardley-7MLQ67FV-DOahSwbZ.js +1 -0
  246. package/dist/client/assets/wardley-WFR3VGLG-BdwDpX_I.js +1 -1
  247. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-9A60XZis.js → wardleyDiagram-VM6X3IG4-BoCETVsK.js} +1 -1
  248. package/dist/client/assets/{wardleyDiagram-VNRHLVJA-B_tMcVFG.js → wardleyDiagram-YMQ3BMBF-BNYqEy7M.js} +4 -4
  249. package/dist/client/assets/{wiki-link-resolver-Dch88erO.js → wiki-link-resolver-BCdGUpdu.js} +1 -1
  250. package/dist/client/assets/{worker-engine-BCCrxWYm-CX0qJ_cG.js → worker-engine-BCCrxWYm-1fphds7O.js} +1 -1
  251. package/dist/client/assets/workspace-sync-client-C_P9wtjf.js +1 -0
  252. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-D00iy-wB.js → xychartDiagram-S5SC5T6Z-eB5Fu9P7.js} +1 -1
  253. package/dist/client/assets/xychartDiagram-TAQBALBS-Sv6aaptV.js +7 -0
  254. package/dist/client/assets/yjs-Jd9fna_Y.js +4 -0
  255. package/dist/client/assets/yjs-provider-reset-guard-Cqu0Z6xH.js +1 -0
  256. package/dist/client/canvas-editor.html +16 -0
  257. package/dist/client/drawio-editor.html +7 -6
  258. package/dist/client/excalidraw-editor.html +31 -30
  259. package/dist/client/export-document.html +4 -3
  260. package/dist/client/index.html +2 -2
  261. package/package.json +27 -29
  262. package/scripts/local-compose.mjs +101 -0
  263. package/src/client/app/canvas-editor.html +13 -0
  264. package/src/client/application/app-shell/git-feature.js +3 -2
  265. package/src/client/application/app-shell/ui-feature-identity.js +1 -0
  266. package/src/client/application/app-shell/ui-feature-shell.js +2 -0
  267. package/src/client/application/app-shell/ui-feature-tab-activity.js +4 -0
  268. package/src/client/application/app-shell/workspace-feature.js +8 -34
  269. package/src/client/application/diagram-chrome.js +8 -11
  270. package/src/client/application/diagram-preview-hydrator.js +5 -5
  271. package/src/client/application/mermaid-preview-hydrator.js +3 -2
  272. package/src/client/application/plantuml-preview-hydrator.js +6 -0
  273. package/src/client/application/preview-render-compiler.js +34 -98
  274. package/src/client/application/preview-render-executor.js +3 -0
  275. package/src/client/application/preview-render-worker.js +2 -0
  276. package/src/client/application/preview-renderer.js +9 -5
  277. package/src/client/application/workspace-coordinator.js +18 -10
  278. package/src/client/application/workspace-preview-controller.js +105 -158
  279. package/src/client/application/workspace-route-controller.js +29 -54
  280. package/src/client/bootstrap/canvas-markdown-preview.js +87 -0
  281. package/src/client/bootstrap/collabmd-app-shell.js +28 -13
  282. package/src/client/canvas-editor.js +143 -0
  283. package/src/client/domain/canvas-view.js +50 -0
  284. package/src/client/domain/excalidraw-scene.js +4 -49
  285. package/src/client/domain/highlight-runtime.js +0 -4
  286. package/src/client/domain/markdown-formatting.js +12 -94
  287. package/src/client/domain/markdown-headings.js +98 -0
  288. package/src/client/domain/wiki-link-completions.js +42 -10
  289. package/src/client/infrastructure/browser-preferences-port.js +27 -33
  290. package/src/client/infrastructure/canvas-room-client.js +210 -0
  291. package/src/client/infrastructure/canvas-text-editor.js +36 -0
  292. package/src/client/infrastructure/comment-thread-store.js +19 -77
  293. package/src/client/infrastructure/editor-view-adapter.js +0 -30
  294. package/src/client/infrastructure/excalidraw-room-client.js +22 -10
  295. package/src/client/infrastructure/hosted-api-client.js +4 -2
  296. package/src/client/infrastructure/vault-api-client.js +4 -4
  297. package/src/client/presentation/canvas-editor-view.js +1028 -0
  298. package/src/client/presentation/canvas-embed-controller.js +116 -0
  299. package/src/client/presentation/canvas-picker.js +111 -0
  300. package/src/client/presentation/drawio-embed-controller.js +1 -3
  301. package/src/client/presentation/excalidraw-embed-controller.js +10 -3
  302. package/src/client/presentation/file-action-controller.js +37 -0
  303. package/src/client/presentation/file-explorer-controller.js +1 -2
  304. package/src/client/presentation/file-explorer-view.js +7 -1
  305. package/src/client/presentation/file-icon-svg.js +1 -1
  306. package/src/client/presentation/file-tree-state.js +4 -1
  307. package/src/client/presentation/image-lightbox-controller.js +1 -5
  308. package/src/client/presentation/team-settings-controller.js +44 -10
  309. package/src/client/styles/components/actions.css +4 -16
  310. package/src/client/styles/components/surfaces.css +0 -7
  311. package/src/client/styles/features/comment-card.css +1 -2
  312. package/src/client/styles/features/comment-markdown.css +0 -18
  313. package/src/client/styles/features/diagram-preview.css +0 -18
  314. package/src/client/styles/features/git-branch.css +0 -4
  315. package/src/client/styles/foundation/themes.css +6 -0
  316. package/src/client/styles/foundation/utilities.css +1 -2
  317. package/src/client/styles/layout/editor-page.css +0 -13
  318. package/src/client/styles/layout/responsive.css +2 -7
  319. package/src/client/styles/layout/shell.css +13 -1
  320. package/src/client/styles/layout/view-modes.css +1 -0
  321. package/src/client/styles/surfaces/canvas-editor.css +239 -0
  322. package/src/domain/canvas-room-codec.js +359 -0
  323. package/src/domain/collabmd-content-capabilities.js +10 -1
  324. package/src/domain/comment-threads.js +49 -5
  325. package/src/domain/excalidraw-room-codec.js +23 -73
  326. package/src/domain/excalidraw-scene.js +48 -0
  327. package/src/domain/file-kind.js +13 -1
  328. package/src/server/application/workspace-reconciliation.js +0 -14
  329. package/src/server/domain/backlink-index.js +1 -36
  330. package/src/server/domain/bases/base-index-snapshot-store.js +41 -24
  331. package/src/server/domain/bases/base-query-service.js +1 -47
  332. package/src/server/domain/collaboration/collaboration-room.js +149 -15
  333. package/src/server/domain/collaboration/room-registry.js +7 -7
  334. package/src/server/domain/hosted-workspace.js +29 -2
  335. package/src/server/domain/plantuml-encoder.js +7 -43
  336. package/src/server/infrastructure/git/diff-service.js +1 -5
  337. package/src/server/infrastructure/git/history-service.js +18 -2
  338. package/src/server/infrastructure/git/untracked-files.js +1 -1
  339. package/src/server/infrastructure/http/create-git-api-command-handler.js +60 -149
  340. package/src/server/infrastructure/http/create-hosted-api-handler.js +5 -2
  341. package/src/server/infrastructure/http/create-vault-api-query-handler.js +2 -2
  342. package/src/server/infrastructure/http/http-response.js +2 -36
  343. package/src/server/infrastructure/http/request-body.js +14 -49
  344. package/src/server/infrastructure/persistence/hosted-metadata-store.js +12 -3
  345. package/src/server/infrastructure/persistence/path-utils.js +8 -2
  346. package/src/server/infrastructure/persistence/vault-file-store.js +26 -60
  347. package/src/server/{infrastructure/git → shared}/image-mime.js +2 -2
  348. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-kJfwukbn.js +0 -1
  349. package/dist/client/assets/_basePickBy-QJXUw_pr.js +0 -1
  350. package/dist/client/assets/_baseUniq-DR4vVjyC.js +0 -1
  351. package/dist/client/assets/architecture-7GRP2DOG-DJVtYNt-.js +0 -1
  352. package/dist/client/assets/browser-utils-S4QYY31r.js +0 -1
  353. package/dist/client/assets/chunk-3FUC2YCW-8tZlhTGX.js +0 -1
  354. package/dist/client/assets/chunk-7M6MHVWA-BDakkknV.js +0 -213
  355. package/dist/client/assets/chunk-FOHPRMQF-Dmmo5Kak.js +0 -161
  356. package/dist/client/assets/chunk-O7XYJQB3-D0_ZY2za.js +0 -126
  357. package/dist/client/assets/chunk-T5WUORNS-DD7KlyY6.js +0 -40
  358. package/dist/client/assets/chunk-Z7XXMR3K-P4Vaq8hD.js +0 -10
  359. package/dist/client/assets/chunk-ZIGJFQKS-b8OUHKK5.js +0 -2
  360. package/dist/client/assets/classDiagram-ZZMXUADV-QLbh_Nkf.js +0 -1
  361. package/dist/client/assets/classDiagram-v2-VYDZK3BY-QLbh_Nkf.js +0 -1
  362. package/dist/client/assets/comment-thread-store-CHvy8GF8.js +0 -1
  363. package/dist/client/assets/comment-threads-nJhK1yfc.js +0 -4
  364. package/dist/client/assets/cynefin-OW5HDTMX-e-Quc9Yl.js +0 -1
  365. package/dist/client/assets/dagre-D7FiCLLP.js +0 -1
  366. package/dist/client/assets/deferred-collab-D4cxEdad.css +0 -1
  367. package/dist/client/assets/deferred-git-BHKtkFYi.css +0 -1
  368. package/dist/client/assets/deferred-preview-BAXYgf4T.css +0 -1
  369. package/dist/client/assets/diagram-ATOU4E4O-B5uX-jVO.js +0 -3
  370. package/dist/client/assets/dist-B2ZNQifU.js +0 -1
  371. package/dist/client/assets/dist-B6QCMNze.js +0 -1
  372. package/dist/client/assets/dist-BIAv19LO.js +0 -1
  373. package/dist/client/assets/dist-BKYp1-dl.js +0 -13
  374. package/dist/client/assets/dist-BSTbcioM.js +0 -11
  375. package/dist/client/assets/dist-BTVg1m-V.js +0 -1
  376. package/dist/client/assets/dist-Bi9ZIYXq.js +0 -9
  377. package/dist/client/assets/dist-Bqo-XRVG.js +0 -1
  378. package/dist/client/assets/dist-CBsvKPcT.js +0 -1
  379. package/dist/client/assets/dist-CJBYh9Wy.js +0 -23
  380. package/dist/client/assets/dist-CRwfjtwz.js +0 -2
  381. package/dist/client/assets/dist-CX7Kc61C.js +0 -1
  382. package/dist/client/assets/dist-CYfPeupF.js +0 -1
  383. package/dist/client/assets/dist-CucpLxUY.js +0 -1
  384. package/dist/client/assets/dist-DHBMeCxC.js +0 -6
  385. package/dist/client/assets/dist-DLEg9d4u.js +0 -1
  386. package/dist/client/assets/dist-DYFBD-wW.js +0 -1
  387. package/dist/client/assets/dist-DugWGOjQ.js +0 -1
  388. package/dist/client/assets/dist-NNrRnB-f.js +0 -1
  389. package/dist/client/assets/dist-PUxZqhFe.js +0 -1
  390. package/dist/client/assets/dist-cYiJMWHJ.js +0 -1
  391. package/dist/client/assets/dist-iKC7go4m.js +0 -1
  392. package/dist/client/assets/document-formatter-6I63vstk.js +0 -1
  393. package/dist/client/assets/drawioEditor-DNTjsjzJ.js +0 -9
  394. package/dist/client/assets/editor-session-D8GGkJak.js +0 -14
  395. package/dist/client/assets/elk-276RUBZZ-B8LB3Pac.js +0 -27
  396. package/dist/client/assets/embedded-editor-base-elU0Avik.css +0 -1
  397. package/dist/client/assets/en-JTHJ2SIP-DBz9bRq4.js +0 -1
  398. package/dist/client/assets/eventmodeling-NTZA5JFV-Dxtv5D-P.js +0 -1
  399. package/dist/client/assets/excalidraw-element-link-BRZOTIeI.js +0 -7
  400. package/dist/client/assets/excalidraw-scene-6uROebca.js +0 -1
  401. package/dist/client/assets/excalidrawEditor-BCTFp_CV.css +0 -1
  402. package/dist/client/assets/excalidrawEditor-D0orhhku.js +0 -9
  403. package/dist/client/assets/export-page-CVJNMERq.js +0 -46
  404. package/dist/client/assets/exportDocument-Ba-n1X4U.css +0 -1
  405. package/dist/client/assets/exportDocument-DSshnmnZ.js +0 -2
  406. package/dist/client/assets/file-kind-BwMIcZbi.js +0 -1
  407. package/dist/client/assets/flowDiagram-HODETNUW-Bq4470NR.js +0 -1
  408. package/dist/client/assets/flowDiagram-KWPJA3E3-DQG9qGiU.js +0 -1
  409. package/dist/client/assets/ganttDiagram-FUAMR5RP-BQpsI7gQ.js +0 -292
  410. package/dist/client/assets/gitGraph-4MIJSDKK-ZaBIE4Lb.js +0 -1
  411. package/dist/client/assets/gitGraphDiagram-X574FWY7-wbs_2m9f.js +0 -106
  412. package/dist/client/assets/graphlib-C9Tl7QrK.js +0 -1
  413. package/dist/client/assets/image-I42VHMUI-B2-c_ifV.js +0 -1
  414. package/dist/client/assets/index-BCgNcVNs.css +0 -1
  415. package/dist/client/assets/index-BpmR5Qqk.js +0 -1140
  416. package/dist/client/assets/info-A6RAGUB7-BcGxhjED.js +0 -1
  417. package/dist/client/assets/lobby-presence-KJrYhMdN.js +0 -1
  418. package/dist/client/assets/mermaid.core-BeOUPE3Q.js +0 -10
  419. package/dist/client/assets/packet-AYTQ26CC-CqpSjTWl.js +0 -1
  420. package/dist/client/assets/pie-WAS4IAKB-Bg2eCNl5.js +0 -1
  421. package/dist/client/assets/preload-helper-BAlEavIC.js +0 -1
  422. package/dist/client/assets/preview-render-compiler-BmWQStaL.js +0 -43
  423. package/dist/client/assets/prod-CA0ie9yD.js +0 -145
  424. package/dist/client/assets/prod-yKJZ3E4s.js +0 -1
  425. package/dist/client/assets/quick-switcher-controller-B5vT9Vj5.js +0 -1
  426. package/dist/client/assets/radar-RG4KPBEZ-DxExotg6.js +0 -1
  427. package/dist/client/assets/railroad-74A4TZTK-FfHmeIQk.js +0 -1
  428. package/dist/client/assets/railroad-abnf-HS5TGJTU-CLkdDRsJ.js +0 -1
  429. package/dist/client/assets/railroad-ebnf-LZEXJU2U-B162zvcG.js +0 -1
  430. package/dist/client/assets/railroad-peg-WCYAUIDC-CGs5GeJ5.js +0 -1
  431. package/dist/client/assets/sequenceDiagram-PO4LG4MO-B-2QfXhV.js +0 -169
  432. package/dist/client/assets/sizeCapture-INFHLROL-B0uUizjq.js +0 -1
  433. package/dist/client/assets/sizeCapture-INFHLROL-DrzwYt5z.js +0 -1
  434. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CLlwrdvU.js +0 -1
  435. package/dist/client/assets/swimlanesDiagram-TC7HE7FX-Bh4tmz27.js +0 -8
  436. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-xhehUG9e.js +0 -8
  437. package/dist/client/assets/treeView-Q6P3EWNA-Cccy0ngL.js +0 -1
  438. package/dist/client/assets/treemap-WGGIJYW6-sMRCjCtX.js +0 -1
  439. package/dist/client/assets/usecaseDiagram-POWQR4AR-DR2LHQYs.js +0 -328
  440. package/dist/client/assets/vault-api-client-NS_EVHJ3.js +0 -7
  441. package/dist/client/assets/wardley-WFR3VGLG-Y7xty_3m.js +0 -1
  442. package/dist/client/assets/workspace-sync-client-BrMtf6zN.js +0 -1
  443. package/dist/client/assets/xychartDiagram-PMCCYNJV-fRpZ1MA5.js +0 -7
  444. package/dist/client/assets/yjs-B41tM6Sz.js +0 -4
  445. package/dist/client/assets/yjs-provider-reset-guard-DpntzUDR.js +0 -1
  446. package/scripts/local-plantuml-compose.mjs +0 -92
  447. package/scripts/local-structurizr-compose.mjs +0 -101
@@ -0,0 +1,359 @@
1
+ import * as Y from 'yjs';
2
+ import { generateNKeysBetween } from '@excalidraw/fractional-indexing';
3
+ import { simpleDiffString } from 'lib0/diff';
4
+
5
+ export const CANVAS_NODES_KEY = 'canvas-nodes';
6
+ export const CANVAS_EDGES_KEY = 'canvas-edges';
7
+ export const CANVAS_META_KEY = 'canvas-meta';
8
+ export const CANVAS_NODE_ORDER_KEY = 'canvas-node-order';
9
+ export const CANVAS_EDGE_ORDER_KEY = 'canvas-edge-order';
10
+
11
+ function invalid() {
12
+ const error = new Error('Invalid JSON Canvas 1.0 document');
13
+ error.code = 'CANVAS_INVALID';
14
+ return error;
15
+ }
16
+
17
+ function requireObject(value) {
18
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw invalid();
19
+ }
20
+
21
+ function requireString(value) {
22
+ if (typeof value !== 'string') throw invalid();
23
+ }
24
+
25
+ function optionalString(value, key, choices = null) {
26
+ if (!Object.hasOwn(value, key)) return;
27
+ requireString(value[key]);
28
+ if (choices && !choices.includes(value[key])) throw invalid();
29
+ }
30
+
31
+ function validateColor(value) {
32
+ if (Object.hasOwn(value, 'color') && !/^(?:[1-6]|#[\da-f]{6})$/i.test(value.color)) throw invalid();
33
+ optionalString(value, 'color');
34
+ }
35
+
36
+ function validateNode(node) {
37
+ requireObject(node);
38
+ requireString(node.id);
39
+ if (!['text', 'file', 'link', 'group'].includes(node.type)) throw invalid();
40
+ for (const key of ['x', 'y', 'width', 'height']) {
41
+ if (!Number.isInteger(node[key])) throw invalid();
42
+ }
43
+ validateColor(node);
44
+ if (node.type === 'text') requireString(node.text);
45
+ if (node.type === 'file') {
46
+ requireString(node.file);
47
+ optionalString(node, 'subpath');
48
+ if (Object.hasOwn(node, 'subpath') && !node.subpath.startsWith('#')) throw invalid();
49
+ }
50
+ if (node.type === 'link') requireString(node.url);
51
+ if (node.type === 'group') {
52
+ optionalString(node, 'label');
53
+ optionalString(node, 'background');
54
+ optionalString(node, 'backgroundStyle', ['cover', 'ratio', 'repeat']);
55
+ }
56
+ }
57
+
58
+ function validateEdge(edge) {
59
+ requireObject(edge);
60
+ for (const key of ['id', 'fromNode', 'toNode']) requireString(edge[key]);
61
+ for (const key of ['fromSide', 'toSide']) optionalString(edge, key, ['top', 'right', 'bottom', 'left']);
62
+ for (const key of ['fromEnd', 'toEnd']) optionalString(edge, key, ['none', 'arrow']);
63
+ optionalString(edge, 'label');
64
+ validateColor(edge);
65
+ }
66
+
67
+ export function validateCanvasDocument(value) {
68
+ requireObject(value);
69
+ for (const key of ['nodes', 'edges']) {
70
+ if (Object.hasOwn(value, key) && !Array.isArray(value[key])) throw invalid();
71
+ const ids = new Set();
72
+ for (const item of value[key] ?? []) {
73
+ (key === 'nodes' ? validateNode : validateEdge)(item);
74
+ if (ids.has(item.id)) throw invalid();
75
+ ids.add(item.id);
76
+ }
77
+ }
78
+ const nodeIds = new Set((value.nodes ?? []).map((node) => node.id));
79
+ if ((value.edges ?? []).some((edge) => !nodeIds.has(edge.fromNode) || !nodeIds.has(edge.toNode))) throw invalid();
80
+ return value;
81
+ }
82
+
83
+ export function parseCanvasJson(text) {
84
+ try {
85
+ if (typeof text !== 'string') throw invalid();
86
+ return validateCanvasDocument(JSON.parse(text, (_key, value) => {
87
+ if (typeof value === 'number' && !Number.isFinite(value)) throw invalid();
88
+ return value;
89
+ }));
90
+ } catch {
91
+ throw invalid();
92
+ }
93
+ }
94
+
95
+ function equal(left, right) {
96
+ return JSON.stringify(left) === JSON.stringify(right);
97
+ }
98
+
99
+ function readItem(item) {
100
+ if (!(item instanceof Y.Map)) throw invalid();
101
+ return Object.fromEntries(Array.from(item, ([key, value]) => [
102
+ key, value instanceof Y.Text ? value.toString() : structuredClone(value),
103
+ ]));
104
+ }
105
+
106
+ function updateText(text, value) {
107
+ const { index, remove, insert } = simpleDiffString(text.toString(), value);
108
+ if (remove) text.delete(index, remove);
109
+ if (insert) text.insert(index, insert);
110
+ }
111
+
112
+ function writeProperties(map, value, { textNode = false, replace = false } = {}) {
113
+ if (replace) {
114
+ for (const key of map.keys()) if (!Object.hasOwn(value, key)) map.delete(key);
115
+ }
116
+ for (const [key, next] of Object.entries(value)) {
117
+ const previous = map.get(key);
118
+ if (next === undefined) {
119
+ map.delete(key);
120
+ } else if (textNode && key === 'text') {
121
+ if (previous instanceof Y.Text) updateText(previous, next);
122
+ else map.set(key, new Y.Text(next));
123
+ } else if (!equal(previous, next)) {
124
+ map.set(key, structuredClone(next));
125
+ }
126
+ }
127
+ }
128
+
129
+ function sortedItems(doc, mapKey, orderKey) {
130
+ const order = doc.getMap(orderKey);
131
+ return Array.from(doc.getMap(mapKey), ([id, value]) => {
132
+ const item = readItem(value);
133
+ if (item.id !== id) throw invalid();
134
+ return item;
135
+ }).sort((left, right) => {
136
+ const leftOrder = String(order.get(left.id) ?? '');
137
+ const rightOrder = String(order.get(right.id) ?? '');
138
+ if (leftOrder !== rightOrder) return leftOrder < rightOrder ? -1 : 1;
139
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
140
+ });
141
+ }
142
+
143
+ export function isCanvasRoomDocStructured(doc) {
144
+ return doc?.getMap(CANVAS_META_KEY).get('schemaVersion') === 1;
145
+ }
146
+
147
+ export function buildCanvasRoomDocument(doc) {
148
+ if (!isCanvasRoomDocStructured(doc)) throw invalid();
149
+ const meta = doc.getMap(CANVAS_META_KEY);
150
+ const properties = meta.get('properties');
151
+ const result = properties instanceof Y.Map ? readItem(properties) : {};
152
+ const nodes = sortedItems(doc, CANVAS_NODES_KEY, CANVAS_NODE_ORDER_KEY);
153
+ const nodeIds = new Set(nodes.map((node) => node.id));
154
+ const edges = sortedItems(doc, CANVAS_EDGES_KEY, CANVAS_EDGE_ORDER_KEY).filter((edge) => {
155
+ validateEdge(edge);
156
+ // A concurrent node deletion wins over an edge connected while offline.
157
+ return nodeIds.has(edge.fromNode) && nodeIds.has(edge.toNode);
158
+ });
159
+ if (meta.get('nodesPresent') || nodes.length) result.nodes = nodes;
160
+ if (meta.get('edgesPresent') || edges.length) result.edges = edges;
161
+ return validateCanvasDocument(result);
162
+ }
163
+
164
+ export function serializeCanvasRoomDocument(doc) {
165
+ return serializeCanvasDocument(buildCanvasRoomDocument(doc));
166
+ }
167
+
168
+ export function serializeCanvasDocument(document) {
169
+ validateCanvasDocument(document);
170
+ return JSON.stringify(document, (_key, value) => {
171
+ if (typeof value === 'number' && !Number.isFinite(value)) throw invalid();
172
+ return value && typeof value === 'object' && !Array.isArray(value)
173
+ ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, value[key]]))
174
+ : value;
175
+ }, 2) + '\n';
176
+ }
177
+
178
+ export function replaceCanvasRoomDocument(doc, document) {
179
+ validateCanvasDocument(document);
180
+ const meta = doc.getMap(CANVAS_META_KEY);
181
+ if (meta.get('schemaVersion') !== 1) meta.set('schemaVersion', 1);
182
+ let properties = meta.get('properties');
183
+ if (!(properties instanceof Y.Map)) {
184
+ properties = new Y.Map();
185
+ meta.set('properties', properties);
186
+ }
187
+ writeProperties(properties, Object.fromEntries(Object.entries(document).filter(([key]) => !['nodes', 'edges'].includes(key))), { replace: true });
188
+ for (const [key, mapKey, orderKey] of [
189
+ ['nodes', CANVAS_NODES_KEY, CANVAS_NODE_ORDER_KEY],
190
+ ['edges', CANVAS_EDGES_KEY, CANVAS_EDGE_ORDER_KEY],
191
+ ]) {
192
+ const items = document[key] ?? [];
193
+ const map = doc.getMap(mapKey);
194
+ const order = doc.getMap(orderKey);
195
+ const ids = new Set(items.map((item) => item.id));
196
+ for (const id of map.keys()) if (!ids.has(id)) map.delete(id);
197
+ for (const id of order.keys()) if (!ids.has(id)) order.delete(id);
198
+ const indices = generateNKeysBetween(null, null, items.length);
199
+ items.forEach((item, index) => {
200
+ let entry = map.get(item.id);
201
+ if (!(entry instanceof Y.Map)) {
202
+ entry = new Y.Map();
203
+ map.set(item.id, entry);
204
+ }
205
+ writeProperties(entry, item, { replace: true, textNode: key === 'nodes' && item.type === 'text' });
206
+ if (order.get(item.id) !== indices[index]) order.set(item.id, indices[index]);
207
+ });
208
+ const present = Object.hasOwn(document, key);
209
+ if (meta.get(`${key}Present`) !== present) meta.set(`${key}Present`, present);
210
+ }
211
+ return document;
212
+ }
213
+
214
+ function addItem(doc, item, mapKey, orderKey) {
215
+ const map = doc.getMap(mapKey);
216
+ if (map.has(item.id)) throw invalid();
217
+ const order = doc.getMap(orderKey);
218
+ const entries = sortedItems(doc, mapKey, orderKey);
219
+ const lastKey = entries.length ? order.get(entries.at(-1).id) : null;
220
+ const nextKey = generateNKeysBetween(lastKey ?? null, null, 1)[0];
221
+ const value = new Y.Map();
222
+ map.set(item.id, value);
223
+ writeProperties(value, item, { textNode: mapKey === CANVAS_NODES_KEY && item.type === 'text' });
224
+ order.set(item.id, nextKey);
225
+ return true;
226
+ }
227
+
228
+ export function addCanvasNode(doc, node) {
229
+ validateNode(node);
230
+ return addItem(doc, node, CANVAS_NODES_KEY, CANVAS_NODE_ORDER_KEY);
231
+ }
232
+
233
+ export function addCanvasEdge(doc, edge) {
234
+ validateEdge(edge);
235
+ const nodes = doc.getMap(CANVAS_NODES_KEY);
236
+ if (!nodes.has(edge.fromNode) || !nodes.has(edge.toNode)) throw invalid();
237
+ return addItem(doc, edge, CANVAS_EDGES_KEY, CANVAS_EDGE_ORDER_KEY);
238
+ }
239
+
240
+ function updateItem(doc, id, patch, key, validate) {
241
+ const entry = doc.getMap(key).get(id);
242
+ if (!(entry instanceof Y.Map)) return false;
243
+ requireObject(patch);
244
+ const previous = readItem(entry);
245
+ const next = Object.fromEntries(Object.entries({ ...previous, ...patch }).filter(([, value]) => value !== undefined));
246
+ if (next.id !== id) throw invalid();
247
+ validate(next);
248
+ if (equal(previous, next)) return false;
249
+ writeProperties(entry, patch, { textNode: key === CANVAS_NODES_KEY && next.type === 'text' });
250
+ return true;
251
+ }
252
+
253
+ export function updateCanvasNode(doc, id, patch) {
254
+ return updateItem(doc, id, patch, CANVAS_NODES_KEY, validateNode);
255
+ }
256
+
257
+ export function updateCanvasEdge(doc, id, patch) {
258
+ return updateItem(doc, id, patch, CANVAS_EDGES_KEY, (edge) => {
259
+ validateEdge(edge);
260
+ const nodes = doc.getMap(CANVAS_NODES_KEY);
261
+ if (!nodes.has(edge.fromNode) || !nodes.has(edge.toNode)) throw invalid();
262
+ });
263
+ }
264
+
265
+ export function deleteCanvasEdges(doc, ids) {
266
+ let changed = false;
267
+ for (const id of ids) {
268
+ if (!doc.getMap(CANVAS_EDGES_KEY).has(id)) continue;
269
+ doc.getMap(CANVAS_EDGES_KEY).delete(id);
270
+ doc.getMap(CANVAS_EDGE_ORDER_KEY).delete(id);
271
+ changed = true;
272
+ }
273
+ return changed;
274
+ }
275
+
276
+ export function deleteCanvasNodes(doc, ids) {
277
+ let changed = false;
278
+ const removed = new Set(ids);
279
+ for (const id of removed) {
280
+ if (!doc.getMap(CANVAS_NODES_KEY).has(id)) continue;
281
+ doc.getMap(CANVAS_NODES_KEY).delete(id);
282
+ doc.getMap(CANVAS_NODE_ORDER_KEY).delete(id);
283
+ changed = true;
284
+ }
285
+ const edgeIds = Array.from(doc.getMap(CANVAS_EDGES_KEY), ([id, edge]) => (
286
+ removed.has(edge.get('fromNode')) || removed.has(edge.get('toNode')) ? id : null
287
+ )).filter((id) => id !== null);
288
+ return deleteCanvasEdges(doc, edgeIds) || changed;
289
+ }
290
+
291
+ export function reorderCanvasNode(doc, id, direction) {
292
+ if (!['front', 'back'].includes(direction)) throw invalid();
293
+ const nodes = sortedItems(doc, CANVAS_NODES_KEY, CANVAS_NODE_ORDER_KEY);
294
+ if (!nodes.some((node) => node.id === id) || nodes.length < 2) return false;
295
+ const last = direction === 'front' ? nodes.at(-1) : nodes[0];
296
+ if (last.id === id) return false;
297
+ const order = doc.getMap(CANVAS_NODE_ORDER_KEY);
298
+ const bound = order.get(last.id);
299
+ const nextKey = direction === 'front'
300
+ ? generateNKeysBetween(bound, null, 1)[0]
301
+ : generateNKeysBetween(null, bound, 1)[0];
302
+ order.set(id, nextKey);
303
+ return true;
304
+ }
305
+
306
+ export function resolveCanvasExternalConflict(doc, choice) {
307
+ const meta = doc.getMap(CANVAS_META_KEY);
308
+ const conflict = meta.get('externalConflict');
309
+ if (!conflict) return false;
310
+ if (!['local', 'external'].includes(choice)) throw invalid();
311
+ if (choice === 'external') replaceCanvasRoomDocument(doc, parseCanvasJson(conflict.content));
312
+ meta.delete('externalConflict');
313
+ return true;
314
+ }
315
+
316
+ // Merge independent fields; overlapping changes stay preserved for explicit resolution.
317
+ export function mergeCanvasDocuments(baseline, local, external) {
318
+ let conflict = false;
319
+ function mergeValue(before, current, next) {
320
+ if (equal(current, before)) return next;
321
+ if (equal(next, before) || equal(current, next)) return current;
322
+ if (before && current && next && ![before, current, next].some((value) => typeof value !== 'object' || Array.isArray(value))) {
323
+ return Object.fromEntries(Array.from(new Set([...Object.keys(before), ...Object.keys(current), ...Object.keys(next)]), (key) => [
324
+ key, mergeValue(before[key], current[key], next[key]),
325
+ ]).filter(([, value]) => value !== undefined));
326
+ }
327
+ conflict = true;
328
+ return current;
329
+ }
330
+ const result = mergeValue(
331
+ Object.fromEntries(Object.entries(baseline).filter(([key]) => !['nodes', 'edges'].includes(key))),
332
+ Object.fromEntries(Object.entries(local).filter(([key]) => !['nodes', 'edges'].includes(key))),
333
+ Object.fromEntries(Object.entries(external).filter(([key]) => !['nodes', 'edges'].includes(key))),
334
+ );
335
+ for (const key of ['nodes', 'edges']) {
336
+ const before = baseline[key] ?? [];
337
+ const current = local[key] ?? [];
338
+ const next = external[key] ?? [];
339
+ const currentById = new Map(current.map((item) => [item.id, item]));
340
+ const nextById = new Map(next.map((item) => [item.id, item]));
341
+ const beforeById = new Map(before.map((item) => [item.id, item]));
342
+ const beforeIds = before.map((item) => item.id);
343
+ const currentIds = current.map((item) => item.id);
344
+ const nextIds = next.map((item) => item.id);
345
+ const localReordered = !equal(currentIds.filter((id) => beforeById.has(id)), beforeIds.filter((id) => currentById.has(id)));
346
+ const externalReordered = !equal(nextIds.filter((id) => beforeById.has(id)), beforeIds.filter((id) => nextById.has(id)));
347
+ if (localReordered && externalReordered && !equal(currentIds, nextIds)) conflict = true;
348
+ const ids = Array.from(new Set(localReordered ? [...currentIds, ...nextIds] : [...nextIds, ...currentIds]));
349
+ const merged = ids.map((id) => mergeValue(beforeById.get(id), currentById.get(id), nextById.get(id))).filter((item) => item !== undefined);
350
+ const present = mergeValue(Object.hasOwn(baseline, key), Object.hasOwn(local, key), Object.hasOwn(external, key));
351
+ if (present || merged.length) result[key] = merged;
352
+ }
353
+ try {
354
+ validateCanvasDocument(result);
355
+ } catch {
356
+ conflict = true;
357
+ }
358
+ return { conflict, document: conflict ? local : result };
359
+ }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  BASE_FILE_EXTENSION,
3
+ CANVAS_FILE_EXTENSION,
3
4
  DRAWIO_FILE_EXTENSION,
4
5
  EXCALIDRAW_FILE_EXTENSION,
5
6
  HTML_FILE_EXTENSIONS,
@@ -64,6 +65,14 @@ const EXCALIDRAW_CREATION_EXAMPLES = [
64
65
  ].map((example) => JSON.stringify(example));
65
66
 
66
67
  const CAPABILITIES = Object.freeze({
68
+ canvas: {
69
+ agentCreatable: false,
70
+ agentEditable: false,
71
+ editable: true,
72
+ extensions: [CANVAS_FILE_EXTENSION],
73
+ guide: 'Standard JSON Canvas 1.0 document edited collaboratively in CollabMD. Collaboration metadata is stored separately. Agent writes are disabled.',
74
+ examples: ['{"nodes": [], "edges": []}'],
75
+ },
67
76
  base: {
68
77
  agentCreatable: true,
69
78
  agentEditable: true,
@@ -167,7 +176,7 @@ export function getCollabMdContentCapability(kindOrPath) {
167
176
  commentsSupported: commentPath ? supportsCommentsForFilePath(commentPath) : false,
168
177
  kind,
169
178
  readable: capability.editable,
170
- searchable: kind !== 'image' && kind !== 'pdf',
179
+ searchable: kind !== 'image' && kind !== 'pdf' && kind !== 'canvas',
171
180
  };
172
181
  }
173
182
 
@@ -6,6 +6,7 @@ export const COMMENT_ANCHOR_QUOTE_MAX_LENGTH = 280;
6
6
  export const COMMENT_REACTION_EMOJI_MAX_LENGTH = 16;
7
7
 
8
8
  const COMMENT_ANCHOR_KINDS = new Set(['diagram-element', 'line', 'text']);
9
+ const REACTION_KEY_PREFIX = 'reaction:';
9
10
 
10
11
  function asFiniteNumber(value) {
11
12
  return Number.isFinite(value) ? value : null;
@@ -125,12 +126,16 @@ export function summarizeCommentExcerpt(value, maxLength = COMMENT_EXCERPT_MAX_L
125
126
  return `${normalized.slice(0, Math.max(maxLength - 1, 1)).trimEnd()}…`;
126
127
  }
127
128
 
128
- function normalizeReactionEmoji(value) {
129
+ export function normalizeCommentReactionEmoji(value) {
129
130
  return Array.from(String(value ?? '').trim())
130
131
  .slice(0, COMMENT_REACTION_EMOJI_MAX_LENGTH)
131
132
  .join('');
132
133
  }
133
134
 
135
+ export function createCommentReactionKey(messageId, emoji, userId) {
136
+ return `${REACTION_KEY_PREFIX}${JSON.stringify([messageId, emoji, userId])}`;
137
+ }
138
+
134
139
  function createReactionUserRecord(user) {
135
140
  const userId = asString(readRecordValue(user, 'userId')).trim();
136
141
  if (!userId) {
@@ -146,7 +151,7 @@ function createReactionUserRecord(user) {
146
151
  }
147
152
 
148
153
  function createReactionGroupRecord(group) {
149
- const emoji = normalizeReactionEmoji(readRecordValue(group, 'emoji'));
154
+ const emoji = normalizeCommentReactionEmoji(readRecordValue(group, 'emoji'));
150
155
  if (!emoji) {
151
156
  return null;
152
157
  }
@@ -212,10 +217,49 @@ function createMessageRecord(message) {
212
217
  };
213
218
  }
214
219
 
215
- function serializeMessages(messages) {
216
- return asArray(messages)
220
+ function serializeMessages(messages, thread) {
221
+ const records = asArray(messages)
217
222
  .map((message) => createMessageRecord(message))
218
223
  .filter(Boolean);
224
+ if (!(thread instanceof Y.Map)) {
225
+ return records;
226
+ }
227
+
228
+ const byId = new Map(records.map((message) => [message.id, message]));
229
+ const overrides = [...thread.entries()]
230
+ .filter(([key]) => key.startsWith(REACTION_KEY_PREFIX))
231
+ .sort(([left], [right]) => left.localeCompare(right));
232
+ for (const [key, value] of overrides) {
233
+ let identity;
234
+ try {
235
+ identity = JSON.parse(key.slice(REACTION_KEY_PREFIX.length));
236
+ } catch {
237
+ continue;
238
+ }
239
+ if (!Array.isArray(identity) || identity.length !== 3 || !identity.every((part) => typeof part === 'string')) {
240
+ continue;
241
+ }
242
+ const [messageId, rawEmoji, userId] = identity;
243
+ const emoji = normalizeCommentReactionEmoji(rawEmoji);
244
+ const message = byId.get(messageId);
245
+ const user = value === null ? null : createReactionUserRecord(value);
246
+ if (!message || !emoji || !userId || (value !== null && user?.userId !== userId)) {
247
+ continue;
248
+ }
249
+
250
+ const groupIndex = message.reactions.findIndex((group) => group.emoji === emoji);
251
+ const users = new Map((message.reactions[groupIndex]?.users ?? []).map((entry) => [entry.userId, entry]));
252
+ if (user) users.set(userId, user);
253
+ else users.delete(userId);
254
+ if (users.size > 0) {
255
+ const group = { emoji, users: [...users.values()] };
256
+ if (groupIndex < 0) message.reactions.push(group);
257
+ else message.reactions[groupIndex] = group;
258
+ } else if (groupIndex >= 0) {
259
+ message.reactions.splice(groupIndex, 1);
260
+ }
261
+ }
262
+ return records;
219
263
  }
220
264
 
221
265
  export function createCommentId(prefix = 'comment') {
@@ -323,7 +367,7 @@ export function serializeCommentThread(thread) {
323
367
  anchorSnapshot: readThreadValue(thread, 'anchorSnapshot'),
324
368
  elementId: readThreadValue(thread, 'elementId'),
325
369
  });
326
- const messages = serializeMessages(readThreadValue(thread, 'messages'));
370
+ const messages = serializeMessages(readThreadValue(thread, 'messages'), thread);
327
371
 
328
372
  if (!anchor || messages.length === 0) {
329
373
  return null;
@@ -1,8 +1,8 @@
1
1
  import * as Y from 'yjs';
2
2
 
3
- const EXCALIDRAW_TYPE = 'excalidraw';
4
- const EXCALIDRAW_VERSION = 2;
5
- const EXCALIDRAW_SOURCE = 'collabmd';
3
+ import { createEmptyScene, normalizeScene, tryParseSceneJson } from './excalidraw-scene.js';
4
+
5
+ export { tryParseSceneJson as tryParseExcalidrawSceneJson } from './excalidraw-scene.js';
6
6
 
7
7
  export const EXCALIDRAW_APP_STATE_KEY = 'excalidraw-app-state';
8
8
  export const EXCALIDRAW_ELEMENTS_KEY = 'excalidraw-elements';
@@ -13,65 +13,10 @@ export const EXCALIDRAW_ROOM_TEXT_KEY = 'codemirror';
13
13
  export const EXCALIDRAW_SCHEMA_VERSION_KEY = 'schemaVersion';
14
14
  export const EXCALIDRAW_REPLACE_GENERATION_KEY = 'replaceGeneration';
15
15
 
16
- function createEmptyScene() {
17
- return {
18
- type: EXCALIDRAW_TYPE,
19
- version: EXCALIDRAW_VERSION,
20
- source: EXCALIDRAW_SOURCE,
21
- elements: [],
22
- appState: {
23
- gridSize: null,
24
- viewBackgroundColor: '#ffffff',
25
- },
26
- files: {},
27
- };
28
- }
29
-
30
- function normalizeAppState(appState = {}) {
31
- return {
32
- gridSize: appState?.gridSize ?? null,
33
- viewBackgroundColor: appState?.viewBackgroundColor ?? '#ffffff',
34
- };
35
- }
36
-
37
- function normalizeScene(raw) {
38
- if (!raw || typeof raw !== 'object') {
39
- return createEmptyScene();
40
- }
41
-
42
- return {
43
- type: EXCALIDRAW_TYPE,
44
- version: EXCALIDRAW_VERSION,
45
- source: EXCALIDRAW_SOURCE,
46
- elements: Array.isArray(raw.elements) ? raw.elements : [],
47
- appState: normalizeAppState(raw.appState),
48
- files: raw.files && typeof raw.files === 'object' ? raw.files : {},
49
- };
50
- }
51
-
52
- function parseSceneJson(rawJson, { fallbackToEmpty = true } = {}) {
53
- if (!rawJson) {
54
- return fallbackToEmpty ? createEmptyScene() : null;
55
- }
56
-
57
- try {
58
- return normalizeScene(JSON.parse(rawJson));
59
- } catch {
60
- return fallbackToEmpty ? createEmptyScene() : null;
61
- }
62
- }
63
-
64
16
  function cloneJsonValue(value) {
65
17
  return structuredClone(value);
66
18
  }
67
19
 
68
- function getRevisionKey(element) {
69
- const version = Number.isFinite(Number(element?.version)) ? Number(element.version) : 0;
70
- const versionNonce = Number.isFinite(Number(element?.versionNonce)) ? Number(element.versionNonce) : 0;
71
- const updated = Number.isFinite(Number(element?.updated)) ? Number(element.updated) : 0;
72
- return `${version}:${versionNonce}:${updated}`;
73
- }
74
-
75
20
  function compareElementVersions(left, right) {
76
21
  const leftVersion = Number(left?.version) || 0;
77
22
  const rightVersion = Number(right?.version) || 0;
@@ -143,14 +88,18 @@ function selectWinningElementFromSlot(slot) {
143
88
  }
144
89
 
145
90
  let winningElement = null;
146
- slot.forEach((value) => {
91
+ let winningKey = '';
92
+ slot.forEach((value, key) => {
147
93
  const candidate = readRevisionEntry(value);
148
94
  if (!candidate || !candidate.id) {
149
95
  return;
150
96
  }
151
97
 
152
- if (!winningElement || compareElementVersions(candidate, winningElement) > 0) {
98
+ // Y.Map iteration order can differ across replicas; equal revisions need a stable tie-break.
99
+ const comparison = winningElement ? compareElementVersions(candidate, winningElement) : 1;
100
+ if (comparison > 0 || (comparison === 0 && key > winningKey)) {
153
101
  winningElement = candidate;
102
+ winningKey = key;
154
103
  }
155
104
  });
156
105
 
@@ -160,12 +109,16 @@ function selectWinningElementFromSlot(slot) {
160
109
  function writeElementSlot(slot, element, {
161
110
  maxRevisions = 2,
162
111
  } = {}) {
163
- const revisionKey = getRevisionKey(element);
112
+ // Each writer keeps its own candidate so concurrent version/nonce winners survive.
113
+ // ponytail: metadata grows with writers, not edits; authoritative replace compacts
114
+ // legacy keys. Never replace a live slot while reconnecting peers can edit it.
115
+ const revisionKey = `writer:${slot.doc.clientID}`;
116
+ const previous = readRevisionEntry(slot.get(revisionKey));
117
+ if (previous && compareElementVersions(element, previous) < 0) {
118
+ return false;
119
+ }
164
120
  const serialized = cloneJsonValue(element);
165
- const previous = slot.get(revisionKey);
166
- const previousSerialized = previous && typeof previous === 'object'
167
- ? JSON.stringify(previous)
168
- : '';
121
+ const previousSerialized = previous ? JSON.stringify(previous) : '';
169
122
  const nextSerialized = JSON.stringify(serialized);
170
123
  if (previousSerialized === nextSerialized) {
171
124
  return false;
@@ -199,7 +152,8 @@ function pruneElementSlot(slot, maxRevisions = 2) {
199
152
  if (!right.element) {
200
153
  return 1;
201
154
  }
202
- return compareElementVersions(left.element, right.element);
155
+ return compareElementVersions(left.element, right.element)
156
+ || (left.key < right.key ? -1 : left.key > right.key ? 1 : 0);
203
157
  });
204
158
 
205
159
  while (revisions.length > maxRevisions) {
@@ -328,7 +282,7 @@ export function replaceExcalidrawRoomScene(ydoc, rawScene, {
328
282
  filesMap.set(key, cloneJsonValue(value));
329
283
  });
330
284
 
331
- const nextAppState = normalizeAppState(scene.appState);
285
+ const nextAppState = scene.appState;
332
286
  appStateMap.set('gridSize', nextAppState.gridSize);
333
287
  appStateMap.set('viewBackgroundColor', nextAppState.viewBackgroundColor);
334
288
  meta.set(EXCALIDRAW_REPLACE_GENERATION_KEY, readExcalidrawReplaceGeneration(ydoc) + 1);
@@ -372,7 +326,7 @@ export function applySceneDiffToExcalidrawRoom(ydoc, rawScene, {
372
326
  changed = true;
373
327
  });
374
328
 
375
- const nextAppState = normalizeAppState(scene.appState);
329
+ const nextAppState = scene.appState;
376
330
  Object.entries(nextAppState).forEach(([key, value]) => {
377
331
  if (appStateMap.get(key) === value) {
378
332
  return;
@@ -398,7 +352,7 @@ export function readLegacyExcalidrawRoomScene(ydoc) {
398
352
  }
399
353
 
400
354
  const rawJson = ydoc.getText(EXCALIDRAW_ROOM_TEXT_KEY).toString();
401
- return parseSceneJson(rawJson, { fallbackToEmpty: false });
355
+ return tryParseSceneJson(rawJson);
402
356
  }
403
357
 
404
358
  export function migrateLegacyExcalidrawRoomData(ydoc, rawScene, options = {}) {
@@ -406,7 +360,3 @@ export function migrateLegacyExcalidrawRoomData(ydoc, rawScene, options = {}) {
406
360
  replaceExcalidrawRoomScene(ydoc, scene, options);
407
361
  return scene;
408
362
  }
409
-
410
- export function tryParseExcalidrawSceneJson(rawJson) {
411
- return parseSceneJson(rawJson, { fallbackToEmpty: false });
412
- }
@@ -0,0 +1,48 @@
1
+ export function createEmptyScene() {
2
+ return {
3
+ type: 'excalidraw',
4
+ version: 2,
5
+ source: 'collabmd',
6
+ elements: [],
7
+ appState: {
8
+ gridSize: null,
9
+ viewBackgroundColor: '#ffffff',
10
+ },
11
+ files: {},
12
+ };
13
+ }
14
+
15
+ export function normalizeScene(raw) {
16
+ if (!raw || typeof raw !== 'object') {
17
+ return createEmptyScene();
18
+ }
19
+
20
+ return {
21
+ type: 'excalidraw',
22
+ version: 2,
23
+ source: 'collabmd',
24
+ elements: Array.isArray(raw.elements) ? raw.elements : [],
25
+ appState: {
26
+ gridSize: raw.appState?.gridSize ?? null,
27
+ viewBackgroundColor: raw.appState?.viewBackgroundColor ?? '#ffffff',
28
+ },
29
+ files: raw.files && typeof raw.files === 'object' ? raw.files : {},
30
+ };
31
+ }
32
+
33
+ export function parseSceneJson(rawJson) {
34
+ const parsed = tryParseSceneJson(rawJson);
35
+ return parsed || createEmptyScene();
36
+ }
37
+
38
+ export function tryParseSceneJson(rawJson) {
39
+ if (!rawJson) {
40
+ return null;
41
+ }
42
+
43
+ try {
44
+ return normalizeScene(JSON.parse(rawJson));
45
+ } catch {
46
+ return null;
47
+ }
48
+ }