excalidrop 0.1.2 → 0.1.4

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 (185) hide show
  1. package/dist/cli.d.ts +0 -21
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +1 -46
  4. package/dist/cli.js.map +1 -1
  5. package/dist/frontend/assets/{advancedFormat-bKUmsig-.js → advancedFormat-tiBAHNGo.js} +1 -1
  6. package/dist/frontend/assets/{ar-SA-G6X2FPQ2-C7K_UR3P.js → ar-SA-G6X2FPQ2-DVxiWV5Z.js} +1 -1
  7. package/dist/frontend/assets/{arc-BI_FJWE7.js → arc-Cc3ncJ1n.js} +1 -1
  8. package/dist/frontend/assets/{az-AZ-76LH7QW2-PkhuRuSr.js → az-AZ-76LH7QW2-Z_2BqDo-.js} +1 -1
  9. package/dist/frontend/assets/{bg-BG-XCXSNQG7-CgLRSYTl.js → bg-BG-XCXSNQG7-DrxGJZOG.js} +1 -1
  10. package/dist/frontend/assets/{blockDiagram-38ab4fdb-BFdBRYSn.js → blockDiagram-38ab4fdb-CDnkTFfP.js} +1 -1
  11. package/dist/frontend/assets/{blockDiagram-68f4deed-Ynbqr7bQ.js → blockDiagram-68f4deed-Bb0W6mxN.js} +1 -1
  12. package/dist/frontend/assets/{bn-BD-2XOGV67Q-CEvkU0mz.js → bn-BD-2XOGV67Q-BkGJ-w8k.js} +1 -1
  13. package/dist/frontend/assets/{c4Diagram-15b5d702-Dm7F1Pn_.js → c4Diagram-15b5d702-ByRV0tka.js} +1 -1
  14. package/dist/frontend/assets/{c4Diagram-3d4e48cf-COkK-e67.js → c4Diagram-3d4e48cf-QSVnzYYK.js} +1 -1
  15. package/dist/frontend/assets/{ca-ES-6MX7JW3Y-DzP6q9bE.js → ca-ES-6MX7JW3Y-BBJvOPE1.js} +1 -1
  16. package/dist/frontend/assets/channel-BQSIb3i3.js +1 -0
  17. package/dist/frontend/assets/{classDiagram-70f12bd4-CRzulwvH.js → classDiagram-70f12bd4-DDFBNGUt.js} +1 -1
  18. package/dist/frontend/assets/{classDiagram-d40c83e7-DNbA-n-a.js → classDiagram-d40c83e7-cgC3s7Nz.js} +1 -1
  19. package/dist/frontend/assets/{classDiagram-v2-d5a6b087-l-GglywH.js → classDiagram-v2-d5a6b087-BgB8AG2e.js} +1 -1
  20. package/dist/frontend/assets/{classDiagram-v2-f2320105-B_TY1zoc.js → classDiagram-v2-f2320105-Dtywkpeg.js} +1 -1
  21. package/dist/frontend/assets/clone-BoZziNL9.js +1 -0
  22. package/dist/frontend/assets/{createText-2e5e7dd3-DB_k52Pn.js → createText-2e5e7dd3-CqY00v-4.js} +1 -1
  23. package/dist/frontend/assets/{createText-d213de94-D-G49giw.js → createText-d213de94-D59sBfqq.js} +1 -1
  24. package/dist/frontend/assets/{cs-CZ-2BRQDIVT-Bf4TOzpR.js → cs-CZ-2BRQDIVT-CK09MAsg.js} +1 -1
  25. package/dist/frontend/assets/{cytoscape-cose-bilkent-DQYypj0P.js → cytoscape-cose-bilkent-CKy_tuGZ.js} +1 -1
  26. package/dist/frontend/assets/{da-DK-5WZEPLOC-jO-5kyXb.js → da-DK-5WZEPLOC-V4hdLKuT.js} +1 -1
  27. package/dist/frontend/assets/{de-DE-XR44H4JA-BkNXWOVh.js → de-DE-XR44H4JA-Dw8qkP9g.js} +1 -1
  28. package/dist/frontend/assets/drop-BFhuMYSw.png +0 -0
  29. package/dist/frontend/assets/{edges-332bd1c7-CVvMtkTa.js → edges-332bd1c7-D-u0KMZB.js} +1 -1
  30. package/dist/frontend/assets/{edges-e0da2a9e-DQBAvC8-.js → edges-e0da2a9e-B3UFqLqY.js} +1 -1
  31. package/dist/frontend/assets/{el-GR-BZB4AONW-Dv7Y9hMk.js → el-GR-BZB4AONW-BUdBQbYg.js} +1 -1
  32. package/dist/frontend/assets/{elk.bundled-YVS3PsMH.js → elk.bundled-BZA3Xcoo.js} +1 -1
  33. package/dist/frontend/assets/{erDiagram-880f2ed8-BjBeR38f.js → erDiagram-880f2ed8-CNxm7e1x.js} +1 -1
  34. package/dist/frontend/assets/{erDiagram-9861fffd-B2Bi3R45.js → erDiagram-9861fffd-C2u_ziAM.js} +1 -1
  35. package/dist/frontend/assets/{es-ES-U4NZUMDT-CWhs0SQY.js → es-ES-U4NZUMDT-DS0FAZqX.js} +1 -1
  36. package/dist/frontend/assets/{eu-ES-A7QVB2H4-BfkFwc3e.js → eu-ES-A7QVB2H4-D-D5uidc.js} +1 -1
  37. package/dist/frontend/assets/{fa-IR-HGAKTJCU-BgWzSj46.js → fa-IR-HGAKTJCU-mAW_2-jg.js} +1 -1
  38. package/dist/frontend/assets/{fi-FI-Z5N7JZ37-CUyvkum-.js → fi-FI-Z5N7JZ37-B9mW6nxS.js} +1 -1
  39. package/dist/frontend/assets/{flowDb-7c981674-BSZyyVBf.js → flowDb-7c981674-6JB2gd0I.js} +1 -1
  40. package/dist/frontend/assets/{flowDb-956e92f1-BC3-CLkF.js → flowDb-956e92f1-BbpkWRi7.js} +1 -1
  41. package/dist/frontend/assets/{flowDiagram-66a62f08-H57DAvmM.js → flowDiagram-66a62f08-DrhrQuXc.js} +1 -1
  42. package/dist/frontend/assets/{flowDiagram-cbd28bf7-Bw4Z2nBD.js → flowDiagram-cbd28bf7-BmNY7bvJ.js} +1 -1
  43. package/dist/frontend/assets/flowDiagram-v2-96b9c2cf-Z3H2d3Wj.js +1 -0
  44. package/dist/frontend/assets/flowDiagram-v2-ffc7f31a-CIQOMghC.js +1 -0
  45. package/dist/frontend/assets/{flowchart-elk-definition-36e2d292-1kZNdf3X.js → flowchart-elk-definition-36e2d292-4G1YiIlk.js} +1 -1
  46. package/dist/frontend/assets/{flowchart-elk-definition-4a651766-DDhG2Esi.js → flowchart-elk-definition-4a651766-Cm94SrrQ.js} +1 -1
  47. package/dist/frontend/assets/{fr-FR-RHASNOE6-7xzoRwbd.js → fr-FR-RHASNOE6-BXnmUxTA.js} +1 -1
  48. package/dist/frontend/assets/{ganttDiagram-04f9e578-CtUSsXCz.js → ganttDiagram-04f9e578-X0BweAnG.js} +1 -1
  49. package/dist/frontend/assets/{ganttDiagram-c361ad54-K42AklFY.js → ganttDiagram-c361ad54-D3vxZ5MQ.js} +1 -1
  50. package/dist/frontend/assets/{gitGraphDiagram-21fc4d3e-uW6XA6Y6.js → gitGraphDiagram-21fc4d3e-wznrpRWn.js} +1 -1
  51. package/dist/frontend/assets/{gitGraphDiagram-72cf32ee-CCNbhnBg.js → gitGraphDiagram-72cf32ee-B9zCS3Pw.js} +1 -1
  52. package/dist/frontend/assets/{gl-ES-HMX3MZ6V-CXuDDwNP.js → gl-ES-HMX3MZ6V-CrUx-ab6.js} +1 -1
  53. package/dist/frontend/assets/{graph-CYOmcSYN.js → graph-BQZ6SIVr.js} +1 -1
  54. package/dist/frontend/assets/{graph-o42dOfI7.js → graph-Cda8xSTx.js} +1 -1
  55. package/dist/frontend/assets/{he-IL-6SHJWFNN-O9dzh9EM.js → he-IL-6SHJWFNN-D33eaw6-.js} +1 -1
  56. package/dist/frontend/assets/{hi-IN-IWLTKZ5I-DlrOXhWs.js → hi-IN-IWLTKZ5I-DEnStF-g.js} +1 -1
  57. package/dist/frontend/assets/{hu-HU-A5ZG7DT2-C3eNg-uI.js → hu-HU-A5ZG7DT2-BjH2w8Sn.js} +1 -1
  58. package/dist/frontend/assets/{id-ID-SAP4L64H-6iM4pI5c.js → id-ID-SAP4L64H-Bc6R-JEz.js} +1 -1
  59. package/dist/frontend/assets/{index-3862675e-DrvLhypC.js → index-3862675e-CpYfS3Db.js} +1 -1
  60. package/dist/frontend/assets/{index-6079d271-BgVTRqg2.js → index-6079d271-Y2bgyRpa.js} +1 -1
  61. package/dist/frontend/assets/{index-HkUXslJy.js → index-D7eYnAQp.js} +4 -4
  62. package/dist/frontend/assets/{index-D-cr7jpJ.js → index-DIz4WrSB.js} +72 -72
  63. package/dist/frontend/assets/{infoDiagram-4a4f5b27-ZxmAcaW1.js → infoDiagram-4a4f5b27-Bm3Oq-Rq.js} +1 -1
  64. package/dist/frontend/assets/{infoDiagram-f8f76790-Bn-PhiFG.js → infoDiagram-f8f76790-oNVitBKM.js} +1 -1
  65. package/dist/frontend/assets/{it-IT-JPQ66NNP-B26NQzGp.js → it-IT-JPQ66NNP-BcxQABF2.js} +1 -1
  66. package/dist/frontend/assets/{ja-JP-DBVTYXUO-CB0fvnYJ.js → ja-JP-DBVTYXUO-D1zIM-nt.js} +1 -1
  67. package/dist/frontend/assets/{journeyDiagram-29694f62-ggDKs06f.js → journeyDiagram-29694f62-CamPk_3P.js} +1 -1
  68. package/dist/frontend/assets/{journeyDiagram-49397b02-pdDS-n-z.js → journeyDiagram-49397b02-D6w3tLtf.js} +1 -1
  69. package/dist/frontend/assets/{kaa-6HZHGXH3-YNdBdcwJ.js → kaa-6HZHGXH3-CoILysVg.js} +1 -1
  70. package/dist/frontend/assets/{kab-KAB-ZGHBKWFO-D86pwZO0.js → kab-KAB-ZGHBKWFO-B9ZbybBt.js} +1 -1
  71. package/dist/frontend/assets/{kk-KZ-P5N5QNE5-CpG5oheM.js → kk-KZ-P5N5QNE5-Dxi4GIQ7.js} +1 -1
  72. package/dist/frontend/assets/{km-KH-HSX4SM5Z-DYOZ3Azw.js → km-KH-HSX4SM5Z-DaJ7EtO2.js} +1 -1
  73. package/dist/frontend/assets/{ko-KR-MTYHY66A-BHorm6lC.js → ko-KR-MTYHY66A-DG57Ah12.js} +1 -1
  74. package/dist/frontend/assets/{ku-TR-6OUDTVRD-CM9RgEHv.js → ku-TR-6OUDTVRD-DnDf9E8a.js} +1 -1
  75. package/dist/frontend/assets/{layout-DW9Qf-At.js → layout-BsWfhUAF.js} +1 -1
  76. package/dist/frontend/assets/{layout-CCtkxrAf.js → layout-Drr-66M9.js} +1 -1
  77. package/dist/frontend/assets/{line-DvZfgg9P.js → line-DwQObOhP.js} +1 -1
  78. package/dist/frontend/assets/{linear-FwFrGRfa.js → linear-C36MjJps.js} +1 -1
  79. package/dist/frontend/assets/{lt-LT-XHIRWOB4-DvriKXBj.js → lt-LT-XHIRWOB4-D_zqS0yg.js} +1 -1
  80. package/dist/frontend/assets/{lv-LV-5QDEKY6T-DzQpwk87.js → lv-LV-5QDEKY6T-owIsIh1b.js} +1 -1
  81. package/dist/frontend/assets/{mindmap-definition-ac74a2e8-DsRo8f2w.js → mindmap-definition-ac74a2e8-Cf9JbrBJ.js} +1 -1
  82. package/dist/frontend/assets/{mindmap-definition-fc14e90a-dQ9reluI.js → mindmap-definition-fc14e90a-BpsNCNCp.js} +1 -1
  83. package/dist/frontend/assets/{mr-IN-CRQNXWMA-C7RzxxP5.js → mr-IN-CRQNXWMA-CS9XUj74.js} +1 -1
  84. package/dist/frontend/assets/{my-MM-5M5IBNSE-B-RRuy29.js → my-MM-5M5IBNSE-BKB060k9.js} +1 -1
  85. package/dist/frontend/assets/{nb-NO-T6EIAALU-B47x16Ik.js → nb-NO-T6EIAALU-CkmLUrvm.js} +1 -1
  86. package/dist/frontend/assets/{nl-NL-IS3SIHDZ-BxAKoQne.js → nl-NL-IS3SIHDZ-DdiLyJoz.js} +1 -1
  87. package/dist/frontend/assets/{nn-NO-6E72VCQL-dfpbEDSZ.js → nn-NO-6E72VCQL-Yevp6f_Y.js} +1 -1
  88. package/dist/frontend/assets/{oc-FR-POXYY2M6-gv6geBjV.js → oc-FR-POXYY2M6-D_M6GHup.js} +1 -1
  89. package/dist/frontend/assets/{pa-IN-N4M65BXN-CY30-qH7.js → pa-IN-N4M65BXN-1vuACN9n.js} +1 -1
  90. package/dist/frontend/assets/{pica-DWYGHLQV.js → pica-DDDx0iqx.js} +1 -1
  91. package/dist/frontend/assets/{pie-CDiWh1rj.js → pie-CFIpuQMO.js} +1 -1
  92. package/dist/frontend/assets/{pieDiagram-421022e6-Bgy-duyf.js → pieDiagram-421022e6-DO7e_Qgw.js} +1 -1
  93. package/dist/frontend/assets/{pieDiagram-8a3498a8-DH7FsbPK.js → pieDiagram-8a3498a8-BEoqChXo.js} +1 -1
  94. package/dist/frontend/assets/{pl-PL-T2D74RX3-TrHugsIA.js → pl-PL-T2D74RX3-Cc6Q5nSh.js} +1 -1
  95. package/dist/frontend/assets/{pt-BR-5N22H2LF-CJxdFp9c.js → pt-BR-5N22H2LF-3eEiAax3.js} +1 -1
  96. package/dist/frontend/assets/{pt-PT-UZXXM6DQ-CB-1q6YJ.js → pt-PT-UZXXM6DQ-CgnF0Le7.js} +1 -1
  97. package/dist/frontend/assets/{quadrantDiagram-0957ecba-DcwYI1oi.js → quadrantDiagram-0957ecba-C1Eo-ZUY.js} +1 -1
  98. package/dist/frontend/assets/{quadrantDiagram-120e2f19-CvHU5a9v.js → quadrantDiagram-120e2f19-Bdfsl_O7.js} +1 -1
  99. package/dist/frontend/assets/{requirementDiagram-23d650b8-tdagN8HP.js → requirementDiagram-23d650b8-DiOK6QW3.js} +1 -1
  100. package/dist/frontend/assets/{requirementDiagram-deff3bca-BMGM-fSI.js → requirementDiagram-deff3bca-BDJ-7T4h.js} +1 -1
  101. package/dist/frontend/assets/{ro-RO-JPDTUUEW-DQq9DBOd.js → ro-RO-JPDTUUEW-CbJ3IB7a.js} +1 -1
  102. package/dist/frontend/assets/{ru-RU-B4JR7IUQ-CWX32rfh.js → ru-RU-B4JR7IUQ-PQGmeGG4.js} +1 -1
  103. package/dist/frontend/assets/{sankeyDiagram-04a897e0-3i6zWpY2.js → sankeyDiagram-04a897e0-DV25bgN2.js} +1 -1
  104. package/dist/frontend/assets/{sankeyDiagram-23345273-ncj1Ol7S.js → sankeyDiagram-23345273-szSb_Sei.js} +1 -1
  105. package/dist/frontend/assets/{selectAll-DJwesbwT.js → selectAll-DsrPvhqV.js} +1 -1
  106. package/dist/frontend/assets/{sequenceDiagram-17ac3bff-ChyKKRZA.js → sequenceDiagram-17ac3bff-Dg88bSlc.js} +1 -1
  107. package/dist/frontend/assets/{sequenceDiagram-704730f1-D57_wP9k.js → sequenceDiagram-704730f1-DRIjLCxx.js} +1 -1
  108. package/dist/frontend/assets/{si-LK-N5RQ5JYF-Lkc5ZxyG.js → si-LK-N5RQ5JYF-BtIIudm3.js} +1 -1
  109. package/dist/frontend/assets/{sk-SK-C5VTKIMK-DyvYXjqZ.js → sk-SK-C5VTKIMK-CIwXticU.js} +1 -1
  110. package/dist/frontend/assets/{sl-SI-NN7IZMDC-D_MvP9Rh.js → sl-SI-NN7IZMDC-CXEdg57y.js} +1 -1
  111. package/dist/frontend/assets/{stateDiagram-587899a1-OjFTnFLS.js → stateDiagram-587899a1-BwRwgRo6.js} +1 -1
  112. package/dist/frontend/assets/{stateDiagram-9c5f0230-BzU36S5C.js → stateDiagram-9c5f0230-C8n96rER.js} +1 -1
  113. package/dist/frontend/assets/{stateDiagram-v2-51a3dcff-CfX1qo7U.js → stateDiagram-v2-51a3dcff-B7e5E4J7.js} +1 -1
  114. package/dist/frontend/assets/{stateDiagram-v2-d93cdb3a-BH7Ud4sU.js → stateDiagram-v2-d93cdb3a-B18iZQLw.js} +1 -1
  115. package/dist/frontend/assets/{styles-2ab5d517-CA8x9Nh5.js → styles-2ab5d517-CfWubwio.js} +1 -1
  116. package/dist/frontend/assets/{styles-5f03d8d2-BnO2pLhV.js → styles-5f03d8d2-C-_n19AB.js} +1 -1
  117. package/dist/frontend/assets/{styles-6aaf32cf-COnot1ea.js → styles-6aaf32cf-Dh-DHkVP.js} +1 -1
  118. package/dist/frontend/assets/{styles-9a916d00-C3QkBgTF.js → styles-9a916d00-Boy0hUEG.js} +1 -1
  119. package/dist/frontend/assets/{styles-c10674c1-CPAG2_rr.js → styles-c10674c1-BfxiK3Ns.js} +1 -1
  120. package/dist/frontend/assets/{styles-edf9a4b0-B8Q9fyu0.js → styles-edf9a4b0-T7mKViRF.js} +1 -1
  121. package/dist/frontend/assets/subset-shared.chunk.js +1 -1
  122. package/dist/frontend/assets/subset-worker.chunk.js +1 -1
  123. package/dist/frontend/assets/{sv-SE-XGPEYMSR-t6voGQSI.js → sv-SE-XGPEYMSR-dVrUAqld.js} +1 -1
  124. package/dist/frontend/assets/{svgDrawCommon-08f97a94-CdT21LWf.js → svgDrawCommon-08f97a94-fsWk6SQc.js} +1 -1
  125. package/dist/frontend/assets/{svgDrawCommon-3ba9043b-D1MU7jAE.js → svgDrawCommon-3ba9043b-BJ8X3qS-.js} +1 -1
  126. package/dist/frontend/assets/{ta-IN-2NMHFXQM-7VmfDDyV.js → ta-IN-2NMHFXQM-CtVVZfIT.js} +1 -1
  127. package/dist/frontend/assets/{th-TH-HPSO5L25-B5rLEY9P.js → th-TH-HPSO5L25-Do90CyDN.js} +1 -1
  128. package/dist/frontend/assets/{timeline-definition-7e6b55e7-BIcL44O_.js → timeline-definition-7e6b55e7-D_iHA485.js} +1 -1
  129. package/dist/frontend/assets/{timeline-definition-85554ec2-TgrYYwpU.js → timeline-definition-85554ec2-nhT8QMsO.js} +1 -1
  130. package/dist/frontend/assets/{tr-TR-DEFEU3FU-0CgOHXTn.js → tr-TR-DEFEU3FU-MfR-IQke.js} +1 -1
  131. package/dist/frontend/assets/{uk-UA-QMV73CPH-CzSFsIsx.js → uk-UA-QMV73CPH-CPet8B1O.js} +1 -1
  132. package/dist/frontend/assets/{union-CnQAJu0l.js → union-BgYwhB7T.js} +1 -1
  133. package/dist/frontend/assets/{vi-VN-M7AON7JQ-Bhx3rYU9.js → vi-VN-M7AON7JQ-3HD06T_8.js} +1 -1
  134. package/dist/frontend/assets/{xychartDiagram-b6496bcd-BMKDop6v.js → xychartDiagram-b6496bcd-D5vSaFT2.js} +1 -1
  135. package/dist/frontend/assets/{xychartDiagram-e933f94c-DAWithrN.js → xychartDiagram-e933f94c-DLIHXsUi.js} +1 -1
  136. package/dist/frontend/assets/{zh-CN-LNUGB5OW-Br52_wH4.js → zh-CN-LNUGB5OW-t2RyWPw2.js} +1 -1
  137. package/dist/frontend/assets/{zh-HK-E62DVLB3-Cj6mnIQ9.js → zh-HK-E62DVLB3-Bj22hc7e.js} +1 -1
  138. package/dist/frontend/assets/{zh-TW-RAJ6MFWO-yLEsVBbC.js → zh-TW-RAJ6MFWO-CBRhqhU1.js} +1 -1
  139. package/dist/frontend/assets/{zipObject-BeXj5PVd.js → zipObject-DMfHW2o8.js} +1 -1
  140. package/dist/frontend/index.html +2 -1
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.js +2 -28
  143. package/dist/index.js.map +1 -1
  144. package/dist/server.js +0 -9
  145. package/dist/server.js.map +1 -1
  146. package/dist/target.d.ts +0 -3
  147. package/dist/target.d.ts.map +1 -1
  148. package/dist/target.js +1 -20
  149. package/dist/target.js.map +1 -1
  150. package/dist/types.d.ts.map +1 -1
  151. package/dist/types.js +0 -8
  152. package/dist/types.js.map +1 -1
  153. package/dist/utils/auth.d.ts +0 -1
  154. package/dist/utils/auth.d.ts.map +1 -1
  155. package/dist/utils/auth.js +0 -1
  156. package/dist/utils/auth.js.map +1 -1
  157. package/dist/utils/github.d.ts +7 -9
  158. package/dist/utils/github.d.ts.map +1 -1
  159. package/dist/utils/github.js +57 -36
  160. package/dist/utils/github.js.map +1 -1
  161. package/dist/utils/logger.js +2 -2
  162. package/dist/utils/logger.js.map +1 -1
  163. package/dist/utils/r2store.d.ts +0 -7
  164. package/dist/utils/r2store.d.ts.map +1 -1
  165. package/dist/utils/r2store.js.map +1 -1
  166. package/frontend/drop.png +0 -0
  167. package/frontend/index.html +1 -0
  168. package/frontend/src/utils/ghSync.ts +99 -36
  169. package/frontend/src/utils/mermaidConverter.ts +2 -8
  170. package/frontend/src/utils/webmcp.ts +7 -27
  171. package/package.json +2 -1
  172. package/src/cli.ts +16 -47
  173. package/src/index.ts +11 -30
  174. package/src/server.ts +9 -9
  175. package/src/target.ts +10 -20
  176. package/src/types.ts +16 -18
  177. package/src/utils/auth.ts +1 -1
  178. package/src/utils/github.ts +61 -33
  179. package/src/utils/logger.ts +2 -2
  180. package/src/utils/r2store.ts +1 -7
  181. package/vite.config.js +0 -2
  182. package/dist/frontend/assets/channel-BqCiG5n3.js +0 -1
  183. package/dist/frontend/assets/clone-B6Jqcrku.js +0 -1
  184. package/dist/frontend/assets/flowDiagram-v2-96b9c2cf-CBjbm_oB.js +0 -1
  185. package/dist/frontend/assets/flowDiagram-v2-ffc7f31a-CoQufPp2.js +0 -1
package/src/cli.ts CHANGED
@@ -1,25 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * excalidrop — per-project Excalidraw canvas + MCP server setup.
4
- *
5
- * Modelled on the `chrome-devtools-mcp` install pattern (`npx -y <pkg>` +
6
- * `mcpServers` JSON), with one addition: per-project dynamic port selection
7
- * so multiple checkouts can run their own canvas concurrently.
8
- *
9
- * How the dynamic port works:
10
- * - `excalidrop init` picks a free port (default scan from 3030) and writes
11
- * it to `.excalidrop.json` in the project root.
12
- * - `excalidrop mcp` (what the AI agent runs via stdio) resolves that same
13
- * file by walking up from cwd, so each project transparently gets its own
14
- * canvas URL with nothing hardcoded in the agent config.
15
- *
16
- * Commands:
17
- * init pick a port, write .excalidrop.json + .mcp.json, offer agent install
18
- * up start the canvas server on this project's port
19
- * mcp run the MCP stdio server pointed at this project's canvas (for agents)
20
- * status show resolved port + canvas health
21
- * add print / run AI-agent install commands
22
- */
23
2
 
24
3
  import { spawn, spawnSync } from 'node:child_process';
25
4
  import { createConnection } from 'node:net';
@@ -41,11 +20,11 @@ const PORT_SCAN_SIZE = 200;
41
20
  interface DropConfig {
42
21
  port: number;
43
22
  canvasUrl: string;
44
- /** Remembered remote canvas (owner/repo) — MCP auto-loads it, agents skip switch_remote. */
23
+
45
24
  remote?: string;
46
25
  }
47
26
 
48
- // ─── port utils ──────────────────────────────────────────────────────────────
27
+
49
28
 
50
29
  function isPortFree(port: number, host = '127.0.0.1', timeoutMs = 300): Promise<boolean> {
51
30
  return new Promise((resolve) => {
@@ -71,7 +50,6 @@ async function findFreePort(preferred?: number, start = DEFAULT_START_PORT): Pro
71
50
  for (let port = start; port < start + PORT_SCAN_SIZE; port++) {
72
51
  if (await isPortFree(port)) return port;
73
52
  }
74
- // Fallback: random high port
75
53
  for (let i = 0; i < 50; i++) {
76
54
  const port = 32000 + Math.floor(Math.random() * 2000);
77
55
  if (await isPortFree(port)) return port;
@@ -79,7 +57,7 @@ async function findFreePort(preferred?: number, start = DEFAULT_START_PORT): Pro
79
57
  throw new Error('Could not find a free port for the excalidrop canvas server.');
80
58
  }
81
59
 
82
- // ─── config discovery ────────────────────────────────────────────────────────
60
+
83
61
 
84
62
  function findProjectRoot(cwd: string): string {
85
63
  let dir = path.resolve(cwd);
@@ -112,7 +90,7 @@ function findDropConfig(cwd: string): { dir: string; config: DropConfig } | null
112
90
  };
113
91
  }
114
92
  } catch {
115
- // corrupt config → ignore, treat as missing
93
+
116
94
  }
117
95
  }
118
96
  if (dir === root) return null;
@@ -130,7 +108,7 @@ function portFromExpressUrl(url: string | undefined): number | undefined {
130
108
  }
131
109
  }
132
110
 
133
- /** Resolve this project's canvas port without side effects (used by `mcp`). */
111
+
134
112
  function resolveSavedPort(cwd: string): number {
135
113
  const envPort = Number(process.env.EXCALIDROP_PORT);
136
114
  if (Number.isFinite(envPort) && envPort > 0) return envPort;
@@ -141,11 +119,10 @@ function resolveSavedPort(cwd: string): number {
141
119
  return DEFAULT_START_PORT;
142
120
  }
143
121
 
144
- // ─── agent config snippets (chrome-devtools-mcp style) ───────────────────────
122
+
145
123
 
146
124
  function mcpServerJson(): Record<string, unknown> {
147
- // No hardcoded port: `excalidrop mcp` resolves `.excalidrop.json` at runtime,
148
- // so the same snippet works for every project, concurrently.
125
+
149
126
  return {
150
127
  mcpServers: {
151
128
  excalidrop: {
@@ -216,7 +193,7 @@ function commandExists(cmd: string): boolean {
216
193
  return probe.status === 0;
217
194
  }
218
195
 
219
- // ─── commands ────────────────────────────────────────────────────────────────
196
+
220
197
 
221
198
  function detectSlug(): string {
222
199
  try {
@@ -237,17 +214,12 @@ async function cmdInit(args: string[]): Promise<void> {
237
214
  const slug = detectSlug();
238
215
 
239
216
  const port = await findFreePort(preferred);
240
- // Preselect this repo as the remote canvas: the MCP auto-loads it, so the
241
- // agent never needs switch_remote for its home project (chrome-devtools-mcp
242
- // wrapper pattern: in-memory default + persisted startup target — ours
243
- // persists in .excalidrop.json so it survives restarts too).
244
217
  const config: DropConfig = { port, canvasUrl: `http://127.0.0.1:${port}`, ...(slug ? { remote: slug } : {}) };
245
218
  fs.writeFileSync(path.join(root, CONFIG_NAME), JSON.stringify(config, null, 2) + '\n');
246
219
  console.log(`\nexcalidrop: canvas port ${port} saved to ${path.join(root, CONFIG_NAME)}`);
247
220
  if (slug) console.log(`excalidrop: remote canvas preselected: ${slug} (agent uses it automatically)`);
248
221
 
249
- // Seed canvas.excalidraw so `npm i -D excalidrop` leaves a visible file
250
- // that export_scene/import_scene round-trip through.
222
+
251
223
  const scenePath = path.join(root, 'canvas.excalidraw');
252
224
  if (!fs.existsSync(scenePath)) {
253
225
  fs.writeFileSync(
@@ -257,7 +229,7 @@ async function cmdInit(args: string[]): Promise<void> {
257
229
  console.log(`excalidrop: empty scene written to ${scenePath}`);
258
230
  }
259
231
 
260
- // Merge into .mcp.json (generic MCP clients + Claude Code project scope)
232
+
261
233
  const mcpPath = path.join(root, MCP_JSON);
262
234
  let mcp: Record<string, any> = {};
263
235
  if (fs.existsSync(mcpPath)) {
@@ -282,7 +254,7 @@ async function cmdInit(args: string[]): Promise<void> {
282
254
  return;
283
255
  }
284
256
 
285
- // Guided remote setup: gh auth → publish empty canvas → agent install → login
257
+
286
258
  if (slug) {
287
259
  if (!ghAuthed()) {
288
260
  console.log('GitHub: not logged in. Run `gh auth login` first (2FA via GitHub), then re-run init.\n');
@@ -308,7 +280,7 @@ async function cmdInit(args: string[]): Promise<void> {
308
280
  return;
309
281
  }
310
282
 
311
- // Try the CLIs that exist; fall back to printing snippets.
283
+
312
284
  let installed = false;
313
285
  if (commandExists('claude')) {
314
286
  const scopeAnswer = await prompt('Claude Code scope? [project/user] (default: project) ');
@@ -343,8 +315,7 @@ async function cmdUp(args: string[]): Promise<void> {
343
315
  const root = findProjectRoot(process.cwd());
344
316
  const existing = findDropConfig(process.cwd());
345
317
 
346
- // Reuse the saved port if it's still free (stable URL per project),
347
- // otherwise claim a new one so concurrent projects never collide.
318
+
348
319
  let port: number;
349
320
  if (preferred) {
350
321
  port = await findFreePort(preferred);
@@ -368,7 +339,7 @@ async function cmdUp(args: string[]): Promise<void> {
368
339
  }
369
340
 
370
341
  function cmdMcp(): void {
371
- // What the agent runs over stdio. Port resolves per-project at runtime.
342
+
372
343
  const port = resolveSavedPort(process.cwd());
373
344
  const canvasUrl = process.env.EXPRESS_SERVER_URL || `http://127.0.0.1:${port}`;
374
345
  const child = spawn(process.execPath, [MCP_ENTRY], {
@@ -409,8 +380,7 @@ function cmdRemote(): void {
409
380
  child.on('exit', (code) => process.exit(code ?? 0));
410
381
  }
411
382
 
412
- /** One-command per-user setup on ANY repo: gh auth → publish viewer → app install link. */
413
- async function cmdSetup(args: string[] = []): Promise<void> {
383
+ async function cmdSetup(args: string[]): Promise<void> {
414
384
  if (args.includes('--help') || args.includes('-h')) {
415
385
  console.log('Usage: npx excalidrop setup\n\nChecks `gh auth`, publishes the viewer to this repo\'s gh-pages\n(enabling Pages if needed), then prints the app-install link and next steps.');
416
386
  return;
@@ -467,7 +437,6 @@ async function cmdSetup(args: string[] = []): Promise<void> {
467
437
  console.log('\nLogin on the page: pill → device code → github.com/login/device (2FA via GitHub).');
468
438
  }
469
439
 
470
- /** Terminal GitHub login via device flow (same flow the agent's github_login uses). */
471
440
  async function cmdLogin(): Promise<void> {
472
441
  const { APP_CLIENT_ID } = await import('./target.js');
473
442
  const clientId = process.env.GITHUB_OAUTH_CLIENT_ID || APP_CLIENT_ID;
@@ -510,7 +479,7 @@ Each project gets its own port (scanned free from ${DEFAULT_START_PORT}), so sev
510
479
  checkouts can run concurrently. Agent config needs no hardcoded port.`);
511
480
  }
512
481
 
513
- // ─── entry ───────────────────────────────────────────────────────────────────
482
+
514
483
 
515
484
  async function main(): Promise<void> {
516
485
  const [cmd, ...rest] = process.argv.slice(2);
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Disable colors to prevent ANSI color codes from breaking JSON parsing
3
+
4
4
  process.env.NODE_DISABLE_COLORS = '1';
5
5
  process.env.NO_COLOR = '1';
6
6
 
@@ -30,10 +30,10 @@ import {
30
30
  } from './types.js';
31
31
  import fetch from 'node-fetch';
32
32
 
33
- // Load environment variables
33
+
34
34
  dotenv.config();
35
35
 
36
- // Safe file path validation to prevent path traversal attacks
36
+
37
37
  const ALLOWED_EXPORT_DIR = process.env.EXCALIDRAW_EXPORT_DIR || process.cwd();
38
38
 
39
39
  function sanitizeFilePath(filePath: string): string {
@@ -48,14 +48,14 @@ function sanitizeFilePath(filePath: string): string {
48
48
  return resolved;
49
49
  }
50
50
 
51
- // Express server configuration (mutable — switch_canvas repoints it at runtime)
51
+
52
52
  let ACTIVE_CANVAS_URL = process.env.EXPRESS_SERVER_URL || 'http://127.0.0.1:3000';
53
53
  function activeCanvasUrl(): string {
54
54
  return process.env.EXPRESS_SERVER_URL || ACTIVE_CANVAS_URL;
55
55
  }
56
- const ENABLE_CANVAS_SYNC = process.env.ENABLE_CANVAS_SYNC !== 'false'; // Default to true
56
+ const ENABLE_CANVAS_SYNC = process.env.ENABLE_CANVAS_SYNC !== 'false';
57
+
57
58
 
58
- // API Response types
59
59
  interface ApiResponse {
60
60
  success: boolean;
61
61
  element?: ServerElement;
@@ -70,7 +70,7 @@ interface SyncResponse {
70
70
  elements?: ServerElement[];
71
71
  }
72
72
 
73
- // Helper functions to sync with Express server (canvas) or remote GitHub target
73
+
74
74
  async function syncToCanvas(operation: string, data: any): Promise<SyncResponse | null> {
75
75
  const tgt = await import('./target.js');
76
76
  if (tgt.isRemote()) {
@@ -150,31 +150,26 @@ async function syncToCanvas(operation: string, data: any): Promise<SyncResponse
150
150
  }
151
151
  }
152
152
 
153
- // Helper to sync element creation to canvas
154
153
  async function createElementOnCanvas(elementData: ServerElement): Promise<ServerElement | null> {
155
154
  const result = await syncToCanvas('create', elementData);
156
155
  return result?.element || elementData;
157
156
  }
158
157
 
159
- // Helper to sync element update to canvas
160
158
  async function updateElementOnCanvas(elementData: Partial<ServerElement> & { id: string }): Promise<ServerElement | null> {
161
159
  const result = await syncToCanvas('update', elementData);
162
160
  return result?.element || null;
163
161
  }
164
162
 
165
- // Helper to sync element deletion to canvas
166
163
  async function deleteElementOnCanvas(elementId: string): Promise<any> {
167
164
  const result = await syncToCanvas('delete', { id: elementId });
168
165
  return result;
169
166
  }
170
167
 
171
- // Helper to sync batch creation to canvas
172
168
  async function batchCreateElementsOnCanvas(elementsData: ServerElement[]): Promise<ServerElement[] | null> {
173
169
  const result = await syncToCanvas('batch_create', elementsData);
174
170
  return result?.elements || elementsData;
175
171
  }
176
172
 
177
- // Helper to fetch element from canvas
178
173
  async function getElementFromCanvas(elementId: string): Promise<ServerElement | null> {
179
174
  const tgt = await import('./target.js');
180
175
  if (tgt.isRemote()) {
@@ -199,7 +194,6 @@ async function getElementFromCanvas(elementId: string): Promise<ServerElement |
199
194
  }
200
195
  }
201
196
 
202
- // In-memory storage for scene state
203
197
  interface SceneState {
204
198
  theme: string;
205
199
  viewport: { x: number; y: number; zoom: number };
@@ -214,12 +208,10 @@ const sceneState: SceneState = {
214
208
  groups: new Map()
215
209
  };
216
210
 
217
- // Points schema: accept both {x, y} objects and [x, y] tuples
218
211
  const PointObjectSchema = z.object({ x: z.number(), y: z.number() });
219
212
  const PointTupleSchema = z.tuple([z.number(), z.number()]);
220
213
  const PointSchema = z.union([PointObjectSchema, PointTupleSchema]);
221
214
 
222
- // Normalize points to [x, y] tuple format that Excalidraw expects
223
215
  function normalizePoints(points: Array<{ x: number; y: number } | [number, number]>): [number, number][] {
224
216
  return points.map(p => {
225
217
  if (Array.isArray(p)) return p as [number, number];
@@ -227,7 +219,6 @@ function normalizePoints(points: Array<{ x: number; y: number } | [number, numbe
227
219
  });
228
220
  }
229
221
 
230
- // Schema definitions using zod
231
222
  const ElementSchema = z.object({
232
223
  id: z.string().optional(),
233
224
  type: z.enum(Object.values(EXCALIDRAW_ELEMENT_TYPES) as [ExcalidrawElementType, ...ExcalidrawElementType[]]),
@@ -293,7 +284,6 @@ const ResourceSchema = z.object({
293
284
  resource: z.enum(['scene', 'library', 'theme', 'elements'])
294
285
  });
295
286
 
296
- // Diagram design guide — injected into LLM context via read_diagram_guide tool
297
287
  const DIAGRAM_DESIGN_GUIDE = `# Excalidraw Diagram Design Guide
298
288
 
299
289
  ## Color Palette
@@ -386,7 +376,7 @@ const DIAGRAM_DESIGN_GUIDE = `# Excalidraw Diagram Design Guide
386
376
  5. **Refinement** — align, distribute, adjust spacing, screenshot to verify
387
377
  `;
388
378
 
389
- // Tool definitions
379
+
390
380
  const tools: Tool[] = [
391
381
  {
392
382
  name: 'create_element',
@@ -910,7 +900,7 @@ const tools: Tool[] = [
910
900
  }
911
901
  ];
912
902
 
913
- // Initialize MCP server
903
+
914
904
  const server = new Server(
915
905
  {
916
906
  name: "mcp-excalidraw-server",
@@ -927,15 +917,13 @@ const server = new Server(
927
917
  }
928
918
  );
929
919
 
930
- // Helper function to convert text property to label format for Excalidraw
920
+
931
921
  function convertTextToLabel(element: ServerElement): ServerElement {
932
922
  const { text, ...rest } = element;
933
923
  if (text) {
934
- // For standalone text elements, keep text as direct property
935
924
  if (element.type === 'text') {
936
- return element; // Keep text as direct property
925
+ return element;
937
926
  }
938
- // For other elements (rectangle, ellipse, diamond), convert to label format
939
927
  return {
940
928
  ...rest,
941
929
  label: { text }
@@ -944,11 +932,8 @@ function convertTextToLabel(element: ServerElement): ServerElement {
944
932
  return element;
945
933
  }
946
934
 
947
- // Set up request handler for tool calls
948
935
  let toolQueue: Promise<void> = Promise.resolve();
949
936
 
950
- // Serialized: concurrent tool calls (e.g. switch+create+commit in one block)
951
- // must not interleave against the remote scene store.
952
937
  async function handleToolCall(request: CallToolRequest) {
953
938
  try {
954
939
  const { name, arguments: args } = request.params;
@@ -965,7 +950,6 @@ async function handleToolCall(request: CallToolRequest) {
965
950
  id,
966
951
  ...elementProps,
967
952
  points: elementProps.points ? normalizePoints(elementProps.points) : undefined,
968
- // Convert binding IDs to Excalidraw's start/end format
969
953
  ...(startElementId ? { start: { id: startElementId } } : {}),
970
954
  ...(endElementId ? { end: { id: endElementId } } : {}),
971
955
  createdAt: new Date().toISOString(),
@@ -973,17 +957,14 @@ async function handleToolCall(request: CallToolRequest) {
973
957
  version: 1
974
958
  };
975
959
 
976
- // Normalize fontFamily from string names to numeric values
977
960
  if (element.fontFamily !== undefined) {
978
961
  element.fontFamily = normalizeFontFamily(element.fontFamily);
979
962
  }
980
963
 
981
- // For bound arrows without explicit points, set a default
982
964
  if ((startElementId || endElementId) && !elementProps.points) {
983
965
  (element as any).points = [[0, 0], [100, 0]];
984
966
  }
985
967
 
986
- // Convert text to label format for Excalidraw
987
968
  const excalidrawElement = convertTextToLabel(element);
988
969
 
989
970
  // Create element directly on HTTP server (no local storage)
package/src/server.ts CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  import { z } from 'zod';
32
32
  import WebSocket from 'ws';
33
33
 
34
- // Load environment variables
34
+
35
35
  dotenv.config();
36
36
 
37
37
  const __filename = fileURLToPath(import.meta.url);
@@ -41,12 +41,12 @@ const app: Express = express();
41
41
  const server = createServer(app);
42
42
  const wss = new WebSocketServer({ server });
43
43
 
44
- // Middleware
44
+
45
45
  app.use(cors());
46
46
  app.use(express.json({ limit: '10mb' }));
47
47
  app.use(authOptional);
48
48
 
49
- // ─── R2 persistence (scene keyed by repo or SCENE_ID) ───
49
+
50
50
  const SCENE_KEY = `${process.env.GITHUB_REPOSITORY?.replace('/', '__') || process.env.SCENE_ID || 'default'}.json`;
51
51
  let r2Cfg = getR2Config();
52
52
  let persistTimer: ReturnType<typeof setTimeout> | null = null;
@@ -69,7 +69,7 @@ function schedulePersist(): void {
69
69
  }
70
70
  void loadFromR2();
71
71
 
72
- // ─── GitHub OAuth (2FA via github.com login; code lives 10min, session 30d cookie) ───
72
+
73
73
  app.get('/api/auth/login', (req, res) => {
74
74
  const cid = process.env.GITHUB_CLIENT_ID;
75
75
  if (!cid) return res.status(500).json({ success: false, error: 'GITHUB_CLIENT_ID not configured' });
@@ -93,7 +93,7 @@ app.get('/api/auth/callback', async (req, res) => {
93
93
  });
94
94
  app.get('/api/auth/me', (req, res) => res.json({ user: (req as any).user || null, publicRead: String(process.env.PUBLIC_READ || 'false') }));
95
95
  app.post('/api/auth/logout', (_req, res) => { res.setHeader('Set-Cookie', 'excalidrop_token=; Path=/; Max-Age=0'); res.json({ success: true }); });
96
- // Writes always authed (when OAuth configured); reads public iff PUBLIC_READ=true.
96
+
97
97
  const OPEN_WRITE_PATHS = new Set(['/api/export/image/result', '/api/viewport/result']);
98
98
  app.use('/api/', (req, res, next) => {
99
99
  if (req.path.startsWith('/auth')) return next();
@@ -106,17 +106,17 @@ app.use('/api/', (req, res, next) => {
106
106
  });
107
107
  const persist = () => schedulePersist();
108
108
 
109
- // Serve static files from the build directory
109
+
110
110
  const staticDir = path.join(__dirname, '../dist');
111
111
  app.use(express.static(staticDir));
112
- // Also serve frontend assets
112
+
113
113
  app.use(express.static(path.join(__dirname, '../dist/frontend')));
114
- // Serve Excalidraw fonts so the font subsetting worker can fetch them for export
114
+
115
115
  app.use('/assets/fonts', express.static(
116
116
  path.join(__dirname, '../node_modules/@excalidraw/excalidraw/dist/prod/fonts')
117
117
  ));
118
118
 
119
- // WebSocket connections
119
+
120
120
  const clients = new Set<WebSocket>();
121
121
 
122
122
  // Broadcast to all connected clients
package/src/target.ts CHANGED
@@ -1,8 +1,4 @@
1
- /** Dynamic backend target: local canvas (HTTP) or remote GitHub repo.
2
- * Agents switch with the switch_remote tool; writes commit straight to GitHub.
3
- * Token resolution (no user setup): GITHUB_TOKEN env → `gh auth token` →
4
- * ~/.config/excalidrop/gh_token (written by github_login device flow).
5
- */
1
+
6
2
  import { execSync } from 'node:child_process';
7
3
  import fs from 'node:fs';
8
4
  import os from 'node:os';
@@ -14,11 +10,11 @@ export type Target = { kind: 'local' } | { kind: 'remote'; repo: string };
14
10
  let active: Target = { kind: 'local' };
15
11
  export const getTarget = (): Target => active;
16
12
 
17
- /** Shared Excalidrop GitHub App Client ID (public, not a secret). */
13
+
18
14
  export const APP_CLIENT_ID = process.env.GITHUB_OAUTH_CLIENT_ID || 'Iv23liuS2fx3QOEIoDmx';
19
15
 
20
16
  const CONFIG_NAME = '.excalidrop.json';
21
- /** Walk up from cwd to find the project config (same pattern as the CLI's ports). */
17
+
22
18
  function findConfigDir(): string | null {
23
19
  let dir = process.cwd();
24
20
  const root = path.parse(dir).root;
@@ -31,7 +27,7 @@ function findConfigDir(): string | null {
31
27
  dir = path.dirname(dir);
32
28
  }
33
29
  }
34
- /** Remember the remote target per-project so agents don't pass it every call. */
30
+
35
31
  function persistTarget(repo: string | null): void {
36
32
  const dir = findConfigDir();
37
33
  if (!dir) return;
@@ -42,7 +38,7 @@ function persistTarget(repo: string | null): void {
42
38
  fs.writeFileSync(file, JSON.stringify(raw, null, 2) + '\n');
43
39
  } catch (e) { logger.warn('could not persist remote target: ' + (e as Error).message); }
44
40
  }
45
- /** Restore the remembered target (called once at MCP startup). */
41
+
46
42
  export function loadSavedTarget(): string | null {
47
43
  const dir = findConfigDir();
48
44
  if (!dir) return null;
@@ -70,7 +66,7 @@ export function storeToken(t: string): void {
70
66
  fs.writeFileSync(TOKEN_FILE, t + '\n', { mode: 0o600 });
71
67
  }
72
68
 
73
- /** Parse owner/repo from "owner/repo" or a https://<owner>.github.io/<repo>/ URL. */
69
+
74
70
  export function parseRepo(input: string): string {
75
71
  const s = input.trim().replace(/\/$/, '');
76
72
  const m = s.match(/^https?:\/\/([a-z0-9-]+)\.github\.io\/([a-z0-9_.-]+)/i);
@@ -79,7 +75,7 @@ export function parseRepo(input: string): string {
79
75
  throw new Error(`Cannot parse repo from "${input}" — use owner/repo or a *.github.io/<repo> URL`);
80
76
  }
81
77
 
82
- // ─── remote scene store (per-target memory + debounced commit) ───
78
+
83
79
  const scenes = new Map<string, { elements: Map<string, ServerElement>; sha: string | null; dirty: boolean }>();
84
80
  let timer: ReturnType<typeof setTimeout> | null = null;
85
81
  const SCENE_PATH = process.env.SCENE_PATH || 'canvas.excalidraw';
@@ -133,22 +129,20 @@ export async function commitNow(message?: string): Promise<{ sha: string; count:
133
129
  const st = current();
134
130
  const elements = Array.from(st.elements.values());
135
131
  const doc = { type: 'excalidraw', version: 2, source: 'excalidrop', elements };
136
- // Shared putFile handles: sha optimistic concurrency (409) + bootstrapping
137
- // main on empty repos (forks off gh-pages) — same path as the remote server.
138
132
  const gh = await import('./utils/github.js');
139
133
  const newSha = await gh.putFile(repo, SCENE_PATH, doc, message || `excalidrop: update ${elements.length} elements`, 'main', st.sha || undefined);
140
134
  st.sha = newSha;
141
135
  st.dirty = false;
142
- // mirror to gh-pages viewer copy
143
136
  try {
144
137
  const cur = await gh.getFile(repo, SCENE_PATH, 'gh-pages').catch(() => null);
145
138
  await gh.putFile(repo, SCENE_PATH, doc, 'excalidrop: sync viewer', 'gh-pages', cur?.sha);
139
+ await gh.updateRepoMetadata(repo, { homepage: `https://${repo.replace('/', '.github.io/')}/` });
146
140
  } catch (e) { logger.warn('viewer mirror failed: ' + (e as Error).message); }
147
141
  logger.info(`Committed ${elements.length} elements to ${repo}`);
148
142
  return { sha: st.sha as string, count: elements.length };
149
143
  }
150
144
 
151
- // Element ops (remote side)
145
+
152
146
  export function rCreate(el: ServerElement): ServerElement {
153
147
  const st = current();
154
148
  const full = { ...el, id: el.id || generateId() };
@@ -172,11 +166,7 @@ export function rList(type?: string): ServerElement[] {
172
166
  export function rClear(): number { const st = current(); const n = st.elements.size; st.elements.clear(); st.dirty = true; scheduleCommit(); return n; }
173
167
  export const isRemote = (): boolean => active.kind === 'remote';
174
168
 
175
- // ─── GitHub App device flow (Node — no CORS issues here) ───
176
- // NOTE: deliberate device-flow (not web flow): static hosting has nowhere to
177
- // keep a client_secret, and device flow is the only secretless path per docs.
178
- // App user-tokens carry no scopes — permissions = user ∩ app. Optional
179
- // repository_id restricts the token to a single repo (least privilege).
169
+
180
170
  export async function deviceStart(clientId: string): Promise<{ user_code: string; verification_uri: string; device_code: string; interval: number }> {
181
171
  const r = await fetch('https://github.com/login/device/code', {
182
172
  method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
package/src/types.ts CHANGED
@@ -108,7 +108,7 @@ export interface ExcalidrawBinding {
108
108
 
109
109
  export type ExcalidrawElementType = 'rectangle' | 'ellipse' | 'diamond' | 'arrow' | 'text' | 'line' | 'freedraw' | 'image';
110
110
 
111
- // Excalidraw element types
111
+
112
112
  export const EXCALIDRAW_ELEMENT_TYPES: Record<string, ExcalidrawElementType> = {
113
113
  RECTANGLE: 'rectangle',
114
114
  ELLIPSE: 'ellipse',
@@ -120,7 +120,7 @@ export const EXCALIDRAW_ELEMENT_TYPES: Record<string, ExcalidrawElementType> = {
120
120
  IMAGE: 'image'
121
121
  } as const;
122
122
 
123
- // Server-side element with metadata
123
+
124
124
  export interface ServerElement extends Omit<ExcalidrawElementBase, 'id'> {
125
125
  id: string;
126
126
  type: ExcalidrawElementType;
@@ -138,12 +138,12 @@ export interface ServerElement extends Omit<ExcalidrawElementBase, 'id'> {
138
138
  text: string;
139
139
  };
140
140
  points?: any;
141
- // Arrow element binding: connect arrows to shapes by element ID
141
+
142
142
  start?: { id: string };
143
143
  end?: { id: string };
144
144
  }
145
145
 
146
- // API Response types
146
+
147
147
  export interface ApiResponse<T = any> {
148
148
  success: boolean;
149
149
  data?: T;
@@ -167,7 +167,7 @@ export interface SyncResponse extends ApiResponse {
167
167
  afterCount: number;
168
168
  }
169
169
 
170
- // WebSocket message types
170
+
171
171
  export interface WebSocketMessage {
172
172
  type: WebSocketMessageType;
173
173
  [key: string]: any;
@@ -226,7 +226,7 @@ export interface MermaidConvertMessage extends WebSocketMessage {
226
226
  timestamp: string;
227
227
  }
228
228
 
229
- // Mermaid conversion types
229
+
230
230
  export interface MermaidConfig {
231
231
  startOnLoad?: boolean;
232
232
  flowchart?: {
@@ -250,13 +250,13 @@ export interface MermaidConversionResponse extends ApiResponse {
250
250
  count: number;
251
251
  }
252
252
 
253
- // Canvas cleared message
253
+
254
254
  export interface CanvasClearedMessage extends WebSocketMessage {
255
255
  type: 'canvas_cleared';
256
256
  timestamp: string;
257
257
  }
258
258
 
259
- // Image export types
259
+
260
260
  export interface ExportImageRequestMessage extends WebSocketMessage {
261
261
  type: 'export_image_request';
262
262
  requestId: string;
@@ -264,7 +264,7 @@ export interface ExportImageRequestMessage extends WebSocketMessage {
264
264
  background?: boolean;
265
265
  }
266
266
 
267
- // Viewport control types
267
+
268
268
  export interface SetViewportMessage extends WebSocketMessage {
269
269
  type: 'set_viewport';
270
270
  requestId: string;
@@ -275,20 +275,20 @@ export interface SetViewportMessage extends WebSocketMessage {
275
275
  offsetY?: number;
276
276
  }
277
277
 
278
- // Snapshot types
278
+
279
279
  export interface Snapshot {
280
280
  name: string;
281
281
  elements: ServerElement[];
282
282
  createdAt: string;
283
283
  }
284
284
 
285
- // In-memory storage for Excalidraw elements
285
+
286
286
  export const elements = new Map<string, ServerElement>();
287
287
 
288
- // In-memory storage for snapshots
288
+
289
289
  export const snapshots = new Map<string, Snapshot>();
290
290
 
291
- // In-memory file storage for image elements (Excalidraw BinaryFiles)
291
+
292
292
  export interface ExcalidrawFile {
293
293
  id: string;
294
294
  dataURL: string;
@@ -297,7 +297,7 @@ export interface ExcalidrawFile {
297
297
  }
298
298
  export const files = new Map<string, ExcalidrawFile>();
299
299
 
300
- // Validation function for Excalidraw elements
300
+
301
301
  export function validateElement(element: Partial<ServerElement>): element is ServerElement {
302
302
  const requiredFields: (keyof ServerElement)[] = ['type', 'x', 'y'];
303
303
  const hasRequiredFields = requiredFields.every(field => field in element);
@@ -313,14 +313,12 @@ export function validateElement(element: Partial<ServerElement>): element is Ser
313
313
  return true;
314
314
  }
315
315
 
316
- // Helper function to generate unique IDs
316
+
317
317
  export function generateId(): string {
318
318
  return Date.now().toString(36) + Math.random().toString(36).substring(2);
319
319
  }
320
320
 
321
- // Normalize fontFamily from string names to numeric values that Excalidraw expects
322
- // Excalidraw uses: 1 = Virgil (handwritten), 2 = Helvetica (sans-serif), 3 = Cascadia (monospace)
323
- // 5 = Excalifont, 6 = Nunito, 7 = Lilita One, 8 = Comic Shanns
321
+
324
322
  export function normalizeFontFamily(fontFamily: string | number | undefined): number | undefined {
325
323
  if (fontFamily === undefined) return undefined;
326
324
  if (typeof fontFamily === 'number') return fontFamily;
package/src/utils/auth.ts CHANGED
@@ -41,7 +41,7 @@ export function authOptional(req: Request, _res: Response, next: NextFunction) {
41
41
  next();
42
42
  }
43
43
 
44
- /** Writes always require auth when GitHub OAuth is configured. Reads are public iff PUBLIC_READ=true. */
44
+
45
45
  export function requireWriteAuth(req: Request, res: Response, next: NextFunction) {
46
46
  if (!process.env.GITHUB_CLIENT_ID) return next(); // local dev: open
47
47
  const tok = getToken(req);