excalidrop 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +62 -6
- package/dist/cli.js.map +1 -1
- package/dist/frontend/assets/{advancedFormat-13WcrIKs.js → advancedFormat-DE1yOycD.js} +1 -1
- package/dist/frontend/assets/{ar-SA-G6X2FPQ2-D8qDPMhv.js → ar-SA-G6X2FPQ2-QnaMc7JM.js} +1 -1
- package/dist/frontend/assets/{arc-B_uYwE6m.js → arc-Cg8U0Eq5.js} +1 -1
- package/dist/frontend/assets/{az-AZ-76LH7QW2-BVH7xgNf.js → az-AZ-76LH7QW2-BO9Hr9vy.js} +1 -1
- package/dist/frontend/assets/{bg-BG-XCXSNQG7-ByPUKhGL.js → bg-BG-XCXSNQG7-DsQdG8GQ.js} +1 -1
- package/dist/frontend/assets/{blockDiagram-38ab4fdb-CQvePe8Z.js → blockDiagram-38ab4fdb-Cfq7gTl5.js} +1 -1
- package/dist/frontend/assets/{blockDiagram-68f4deed-CwvcKSDG.js → blockDiagram-68f4deed-DKXvoBM4.js} +1 -1
- package/dist/frontend/assets/{bn-BD-2XOGV67Q-D4KqOeKh.js → bn-BD-2XOGV67Q-0GTwXdnx.js} +1 -1
- package/dist/frontend/assets/{c4Diagram-15b5d702-COmliiHE.js → c4Diagram-15b5d702-CzLwW3PM.js} +1 -1
- package/dist/frontend/assets/{c4Diagram-3d4e48cf-D7OkyBCG.js → c4Diagram-3d4e48cf-BtA5sIH_.js} +1 -1
- package/dist/frontend/assets/{ca-ES-6MX7JW3Y-CVSEc9Gr.js → ca-ES-6MX7JW3Y-D792TpuE.js} +1 -1
- package/dist/frontend/assets/channel-BiBGrGc2.js +1 -0
- package/dist/frontend/assets/{classDiagram-70f12bd4-CiR1mAxL.js → classDiagram-70f12bd4-CYlskbl7.js} +1 -1
- package/dist/frontend/assets/{classDiagram-d40c83e7-BOwtqvA-.js → classDiagram-d40c83e7-TFFAmI3n.js} +1 -1
- package/dist/frontend/assets/{classDiagram-v2-d5a6b087-CLfovOEZ.js → classDiagram-v2-d5a6b087-CuEs-vQM.js} +1 -1
- package/dist/frontend/assets/{classDiagram-v2-f2320105-BbgjahgF.js → classDiagram-v2-f2320105-CP2QUPIw.js} +1 -1
- package/dist/frontend/assets/clone-DP5GGGqv.js +1 -0
- package/dist/frontend/assets/{createText-2e5e7dd3-hFM4xCnY.js → createText-2e5e7dd3-B9buhJhz.js} +1 -1
- package/dist/frontend/assets/{createText-d213de94-BcC2siap.js → createText-d213de94-Dl7cGRq1.js} +1 -1
- package/dist/frontend/assets/{cs-CZ-2BRQDIVT-GLI3AmJq.js → cs-CZ-2BRQDIVT-BX_XTb-l.js} +1 -1
- package/dist/frontend/assets/{cytoscape-cose-bilkent-DIrtWvIC.js → cytoscape-cose-bilkent-bdLom2jo.js} +1 -1
- package/dist/frontend/assets/{da-DK-5WZEPLOC-BirYbTgL.js → da-DK-5WZEPLOC-Bfj3iC9L.js} +1 -1
- package/dist/frontend/assets/{de-DE-XR44H4JA-CpII26VX.js → de-DE-XR44H4JA-dlBwXmiG.js} +1 -1
- package/dist/frontend/assets/{edges-332bd1c7-CV1_ozEk.js → edges-332bd1c7-B1wvBqMI.js} +1 -1
- package/dist/frontend/assets/{edges-e0da2a9e-pqeZxZR9.js → edges-e0da2a9e-CdBHUaUf.js} +1 -1
- package/dist/frontend/assets/{el-GR-BZB4AONW-DFs7KhuG.js → el-GR-BZB4AONW-_x5lVXg8.js} +1 -1
- package/dist/frontend/assets/{elk.bundled-CK-SRvXT.js → elk.bundled-DtUPYeYN.js} +1 -1
- package/dist/frontend/assets/{erDiagram-880f2ed8-D8z0YP6a.js → erDiagram-880f2ed8-BsPsKkXE.js} +1 -1
- package/dist/frontend/assets/{erDiagram-9861fffd-5ZZvug0m.js → erDiagram-9861fffd-Bgpjn4d-.js} +1 -1
- package/dist/frontend/assets/{es-ES-U4NZUMDT-DKbN2UTU.js → es-ES-U4NZUMDT-CgmLkh9-.js} +1 -1
- package/dist/frontend/assets/{eu-ES-A7QVB2H4-7_Gn1vLd.js → eu-ES-A7QVB2H4-xmyjxW0n.js} +1 -1
- package/dist/frontend/assets/{fa-IR-HGAKTJCU-GYGVj_td.js → fa-IR-HGAKTJCU-BN1XqkA9.js} +1 -1
- package/dist/frontend/assets/{fi-FI-Z5N7JZ37-CSqOf1gy.js → fi-FI-Z5N7JZ37-DPGmsozE.js} +1 -1
- package/dist/frontend/assets/{flowDb-7c981674-hAdbykWR.js → flowDb-7c981674-D-Lz-ucy.js} +1 -1
- package/dist/frontend/assets/{flowDb-956e92f1-BT3sVrS_.js → flowDb-956e92f1-CGqQ4oJb.js} +1 -1
- package/dist/frontend/assets/{flowDiagram-66a62f08-BFbBUcUi.js → flowDiagram-66a62f08-yAsoSO4M.js} +1 -1
- package/dist/frontend/assets/{flowDiagram-cbd28bf7-D-6XLmjT.js → flowDiagram-cbd28bf7-Cv24oAFw.js} +1 -1
- package/dist/frontend/assets/flowDiagram-v2-96b9c2cf-DL-IsgmS.js +1 -0
- package/dist/frontend/assets/flowDiagram-v2-ffc7f31a-cm0Es-T3.js +1 -0
- package/dist/frontend/assets/{flowchart-elk-definition-36e2d292-9Nr5xJ91.js → flowchart-elk-definition-36e2d292-8RiRHcVG.js} +1 -1
- package/dist/frontend/assets/{flowchart-elk-definition-4a651766-Dh7uuQPf.js → flowchart-elk-definition-4a651766-Z37NlWB1.js} +1 -1
- package/dist/frontend/assets/{fr-FR-RHASNOE6-C_Z36lVW.js → fr-FR-RHASNOE6-daCFKfHs.js} +1 -1
- package/dist/frontend/assets/{ganttDiagram-04f9e578-DJ_dJIYA.js → ganttDiagram-04f9e578-BMq_3g8O.js} +1 -1
- package/dist/frontend/assets/{ganttDiagram-c361ad54-CQOWRFrH.js → ganttDiagram-c361ad54-D09Dl_OA.js} +1 -1
- package/dist/frontend/assets/{gitGraphDiagram-21fc4d3e-7pQNN07o.js → gitGraphDiagram-21fc4d3e-ffU3Oe9e.js} +1 -1
- package/dist/frontend/assets/{gitGraphDiagram-72cf32ee-BVi0ODi6.js → gitGraphDiagram-72cf32ee-B1qFZhLG.js} +1 -1
- package/dist/frontend/assets/{gl-ES-HMX3MZ6V-DV1iEV4R.js → gl-ES-HMX3MZ6V-Bi_ejBVO.js} +1 -1
- package/dist/frontend/assets/{graph-DPklf_4J.js → graph-Cld5o79d.js} +1 -1
- package/dist/frontend/assets/{graph-DZoF-TB0.js → graph-D0R7rXy3.js} +1 -1
- package/dist/frontend/assets/{he-IL-6SHJWFNN-qSfOYyrG.js → he-IL-6SHJWFNN-BxMAYMHO.js} +1 -1
- package/dist/frontend/assets/{hi-IN-IWLTKZ5I-CUUpX9FX.js → hi-IN-IWLTKZ5I-CEvdaxPD.js} +1 -1
- package/dist/frontend/assets/{hu-HU-A5ZG7DT2-jc9NuvMZ.js → hu-HU-A5ZG7DT2-DD25K3R6.js} +1 -1
- package/dist/frontend/assets/{id-ID-SAP4L64H-gAQX_ycs.js → id-ID-SAP4L64H-BbNSAn5U.js} +1 -1
- package/dist/frontend/assets/{index-DMNFnJz0.js → index-1WYcrLVJ.js} +4 -4
- package/dist/frontend/assets/{index-3862675e-DkeMPq9X.js → index-3862675e-B37xIMNY.js} +1 -1
- package/dist/frontend/assets/{index-6079d271-GJeDwDgK.js → index-6079d271-MI3jF-v5.js} +1 -1
- package/dist/frontend/assets/index-BQuFwudZ.js +349 -0
- package/dist/frontend/assets/{infoDiagram-4a4f5b27-D4VmHTt0.js → infoDiagram-4a4f5b27-Ct-SquLn.js} +1 -1
- package/dist/frontend/assets/{infoDiagram-f8f76790-CKGoMOTF.js → infoDiagram-f8f76790-DhHJqTvC.js} +1 -1
- package/dist/frontend/assets/{it-IT-JPQ66NNP-D8O8hsKi.js → it-IT-JPQ66NNP-DGCSNBVd.js} +1 -1
- package/dist/frontend/assets/{ja-JP-DBVTYXUO-CD5HWhjP.js → ja-JP-DBVTYXUO-BCiZKQS1.js} +1 -1
- package/dist/frontend/assets/{journeyDiagram-29694f62-Cj-S78w5.js → journeyDiagram-29694f62-JHRAdUlO.js} +1 -1
- package/dist/frontend/assets/{journeyDiagram-49397b02-Cs4WN5FP.js → journeyDiagram-49397b02-Cz3Xcr6V.js} +1 -1
- package/dist/frontend/assets/{kaa-6HZHGXH3-xebLrnfE.js → kaa-6HZHGXH3-BVSalYYt.js} +1 -1
- package/dist/frontend/assets/{kab-KAB-ZGHBKWFO-DvfjxFnt.js → kab-KAB-ZGHBKWFO-C9onfV-Y.js} +1 -1
- package/dist/frontend/assets/{kk-KZ-P5N5QNE5-BKr_G3W_.js → kk-KZ-P5N5QNE5-D7HmWmH6.js} +1 -1
- package/dist/frontend/assets/{km-KH-HSX4SM5Z-BC3jqWvk.js → km-KH-HSX4SM5Z--gSIK5hM.js} +1 -1
- package/dist/frontend/assets/{ko-KR-MTYHY66A-Dueq3BFJ.js → ko-KR-MTYHY66A-DX-ewFiI.js} +1 -1
- package/dist/frontend/assets/{ku-TR-6OUDTVRD-DOUVUhi3.js → ku-TR-6OUDTVRD-BzkN5jDn.js} +1 -1
- package/dist/frontend/assets/{layout-DNILJXpj.js → layout-Bg902Usv.js} +1 -1
- package/dist/frontend/assets/{layout-BC6d-Wwh.js → layout-DTqY_XPF.js} +1 -1
- package/dist/frontend/assets/{line-DHiJikCQ.js → line-CyQqGgtO.js} +1 -1
- package/dist/frontend/assets/{linear-CEqgKjcC.js → linear-Bs8n8jyN.js} +1 -1
- package/dist/frontend/assets/{lt-LT-XHIRWOB4-b-v2D9bi.js → lt-LT-XHIRWOB4-DYMQN62-.js} +1 -1
- package/dist/frontend/assets/{lv-LV-5QDEKY6T-DeSmLJYT.js → lv-LV-5QDEKY6T-Ba6KAHxv.js} +1 -1
- package/dist/frontend/assets/{mindmap-definition-ac74a2e8-CU4tLzl8.js → mindmap-definition-ac74a2e8-CFIgjLLb.js} +1 -1
- package/dist/frontend/assets/{mindmap-definition-fc14e90a-cr8cL-H3.js → mindmap-definition-fc14e90a-BrE0Pj3C.js} +1 -1
- package/dist/frontend/assets/{mr-IN-CRQNXWMA-CEN0CMR0.js → mr-IN-CRQNXWMA-CopS0bND.js} +1 -1
- package/dist/frontend/assets/{my-MM-5M5IBNSE-Bri-YGoK.js → my-MM-5M5IBNSE-CBjLWYW5.js} +1 -1
- package/dist/frontend/assets/{nb-NO-T6EIAALU-47lldcE5.js → nb-NO-T6EIAALU-CfqYpnNU.js} +1 -1
- package/dist/frontend/assets/{nl-NL-IS3SIHDZ-C4cm6lD2.js → nl-NL-IS3SIHDZ-CQao565c.js} +1 -1
- package/dist/frontend/assets/{nn-NO-6E72VCQL-pb1Jxyuz.js → nn-NO-6E72VCQL-BfcDB6Nm.js} +1 -1
- package/dist/frontend/assets/{oc-FR-POXYY2M6-tuCngTrJ.js → oc-FR-POXYY2M6-CBEuTLTI.js} +1 -1
- package/dist/frontend/assets/{pa-IN-N4M65BXN-Cosawm6d.js → pa-IN-N4M65BXN-CIRvxv_4.js} +1 -1
- package/dist/frontend/assets/{pica-Cqow9aeR.js → pica-n9a5bdBf.js} +1 -1
- package/dist/frontend/assets/{pie-C78Yrqjh.js → pie-Bw6jHLyi.js} +1 -1
- package/dist/frontend/assets/{pieDiagram-421022e6-AfZ8Wmiu.js → pieDiagram-421022e6-Bq7587Ql.js} +1 -1
- package/dist/frontend/assets/{pieDiagram-8a3498a8-Sb4RWl24.js → pieDiagram-8a3498a8-Cs30mQ4p.js} +1 -1
- package/dist/frontend/assets/{pl-PL-T2D74RX3-Chumgtd8.js → pl-PL-T2D74RX3-DtyedWZX.js} +1 -1
- package/dist/frontend/assets/{pt-BR-5N22H2LF-Y6yMB05f.js → pt-BR-5N22H2LF-DN1KIZAy.js} +1 -1
- package/dist/frontend/assets/{pt-PT-UZXXM6DQ-2XNNwJUO.js → pt-PT-UZXXM6DQ-BabgX2Go.js} +1 -1
- package/dist/frontend/assets/{quadrantDiagram-0957ecba-aT6ajsQz.js → quadrantDiagram-0957ecba-r08S29Gl.js} +1 -1
- package/dist/frontend/assets/{quadrantDiagram-120e2f19-DA8xtpNX.js → quadrantDiagram-120e2f19-Cr2SCg_P.js} +1 -1
- package/dist/frontend/assets/{relay-CO0fAEJb.js → relay-BgjIEMqw.js} +2 -2
- package/dist/frontend/assets/{requirementDiagram-23d650b8-BZtxzO7K.js → requirementDiagram-23d650b8-DWSUlPnt.js} +1 -1
- package/dist/frontend/assets/{requirementDiagram-deff3bca-CQYENSbT.js → requirementDiagram-deff3bca-D-4X-NA5.js} +1 -1
- package/dist/frontend/assets/{ro-RO-JPDTUUEW-BfolbfPU.js → ro-RO-JPDTUUEW-BTtFaTbo.js} +1 -1
- package/dist/frontend/assets/{ru-RU-B4JR7IUQ-BNWrm2pe.js → ru-RU-B4JR7IUQ-Cx7p9fCi.js} +1 -1
- package/dist/frontend/assets/{sankeyDiagram-04a897e0-D0OJOdMM.js → sankeyDiagram-04a897e0-b2SeMYG6.js} +1 -1
- package/dist/frontend/assets/{sankeyDiagram-23345273-DJYXL1_D.js → sankeyDiagram-23345273-DLciAh1g.js} +1 -1
- package/dist/frontend/assets/{selectAll-DOPd5EPW.js → selectAll-3cbo0gSx.js} +1 -1
- package/dist/frontend/assets/{sequenceDiagram-17ac3bff-DHJQ2Zdp.js → sequenceDiagram-17ac3bff-D4C97IMR.js} +1 -1
- package/dist/frontend/assets/{sequenceDiagram-704730f1-B013vXOZ.js → sequenceDiagram-704730f1-CsIwqj61.js} +1 -1
- package/dist/frontend/assets/{si-LK-N5RQ5JYF-D32y43Nh.js → si-LK-N5RQ5JYF-DRbkL9Bw.js} +1 -1
- package/dist/frontend/assets/{sk-SK-C5VTKIMK-ORKN2f5z.js → sk-SK-C5VTKIMK-b8KPqW9j.js} +1 -1
- package/dist/frontend/assets/{sl-SI-NN7IZMDC-orl2CefP.js → sl-SI-NN7IZMDC-DAgg3HEv.js} +1 -1
- package/dist/frontend/assets/{stateDiagram-587899a1-Bq1RJXU-.js → stateDiagram-587899a1-BrL0AJ2m.js} +1 -1
- package/dist/frontend/assets/{stateDiagram-9c5f0230-fS9zifGF.js → stateDiagram-9c5f0230-znRpiySU.js} +1 -1
- package/dist/frontend/assets/{stateDiagram-v2-51a3dcff-CBvwJ0uj.js → stateDiagram-v2-51a3dcff-Cm0gu2aT.js} +1 -1
- package/dist/frontend/assets/{stateDiagram-v2-d93cdb3a-BtvnfP6y.js → stateDiagram-v2-d93cdb3a-D1v21-Eu.js} +1 -1
- package/dist/frontend/assets/{styles-2ab5d517-CD2K6uvC.js → styles-2ab5d517-DegF9FpK.js} +1 -1
- package/dist/frontend/assets/{styles-5f03d8d2-BGwVkv5B.js → styles-5f03d8d2-rJg_uZ1y.js} +1 -1
- package/dist/frontend/assets/{styles-6aaf32cf-Cp8Xm4ia.js → styles-6aaf32cf-DZ1tE453.js} +1 -1
- package/dist/frontend/assets/{styles-9a916d00-BFniIAZ5.js → styles-9a916d00-8MQRBV5u.js} +1 -1
- package/dist/frontend/assets/{styles-c10674c1-CsoDZQ7K.js → styles-c10674c1-CoYU8Hxx.js} +1 -1
- package/dist/frontend/assets/{styles-edf9a4b0-CiM579LN.js → styles-edf9a4b0--FFAlqXa.js} +1 -1
- package/dist/frontend/assets/subset-shared.chunk.js +1 -1
- package/dist/frontend/assets/subset-worker.chunk.js +1 -1
- package/dist/frontend/assets/{sv-SE-XGPEYMSR-DHbvQRGF.js → sv-SE-XGPEYMSR-BupEJvWR.js} +1 -1
- package/dist/frontend/assets/{svgDrawCommon-08f97a94-BjVpQLSR.js → svgDrawCommon-08f97a94-CTj31sRY.js} +1 -1
- package/dist/frontend/assets/{svgDrawCommon-3ba9043b-DjE4ZK0L.js → svgDrawCommon-3ba9043b-BZHRpxTv.js} +1 -1
- package/dist/frontend/assets/{ta-IN-2NMHFXQM-Ca1t_Ko2.js → ta-IN-2NMHFXQM-DTr9GIu-.js} +1 -1
- package/dist/frontend/assets/{th-TH-HPSO5L25-2L4nZMR3.js → th-TH-HPSO5L25-BDPsaOgQ.js} +1 -1
- package/dist/frontend/assets/{timeline-definition-7e6b55e7-BFW1xuIt.js → timeline-definition-7e6b55e7-DYpxvJMC.js} +1 -1
- package/dist/frontend/assets/{timeline-definition-85554ec2-Bjtl-I1R.js → timeline-definition-85554ec2-qV8Ig3TX.js} +1 -1
- package/dist/frontend/assets/{tr-TR-DEFEU3FU-DTNddWux.js → tr-TR-DEFEU3FU-Cgh12nEY.js} +1 -1
- package/dist/frontend/assets/{uk-UA-QMV73CPH-L17E1Z9m.js → uk-UA-QMV73CPH-DsPGU0Dc.js} +1 -1
- package/dist/frontend/assets/{union-BOPJv_NW.js → union-BNBs5eWq.js} +1 -1
- package/dist/frontend/assets/{vi-VN-M7AON7JQ-B2rkMBha.js → vi-VN-M7AON7JQ-DCP17qnJ.js} +1 -1
- package/dist/frontend/assets/{xychartDiagram-b6496bcd-zkCAiikr.js → xychartDiagram-b6496bcd-BlZqZpsh.js} +1 -1
- package/dist/frontend/assets/{xychartDiagram-e933f94c-DgmjX1Cq.js → xychartDiagram-e933f94c-j14yGvbF.js} +1 -1
- package/dist/frontend/assets/{zh-CN-LNUGB5OW-C3MR_Iw2.js → zh-CN-LNUGB5OW-DtwvmVxH.js} +1 -1
- package/dist/frontend/assets/{zh-HK-E62DVLB3-Bp3C_l-n.js → zh-HK-E62DVLB3-ChF_vupN.js} +1 -1
- package/dist/frontend/assets/{zh-TW-RAJ6MFWO-DiA5M5RC.js → zh-TW-RAJ6MFWO-CU8L3VT-.js} +1 -1
- package/dist/frontend/assets/{zipObject-BXMcibol.js → zipObject-BENW7yI5.js} +1 -1
- package/dist/frontend/index.html +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +30 -4
- package/dist/mcp.js.map +1 -1
- package/package.json +2 -1
- package/worker/README.md +69 -0
- package/worker/src/index.js +170 -0
- package/worker/src/mcp.js +607 -0
- package/worker/src/relay.js +130 -0
- package/worker/wrangler.toml +20 -0
- package/dist/frontend/assets/channel-FdQr2Y2u.js +0 -1
- package/dist/frontend/assets/clone-Bww_2hMC.js +0 -1
- package/dist/frontend/assets/flowDiagram-v2-96b9c2cf-BrPX1C0T.js +0 -1
- package/dist/frontend/assets/flowDiagram-v2-ffc7f31a-DcmJmCpH.js +0 -1
- package/dist/frontend/assets/index-DPE4WCka.js +0 -349
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// One instance per repo. Verifies the caller's GitHub token per request (cached
|
|
2
|
+
// ~60s by hash); holds viewer sockets + pending rpc ≤30s. Nothing is persisted.
|
|
3
|
+
|
|
4
|
+
const AUTH_CACHE_MS = 60_000;
|
|
5
|
+
const AUTH_CACHE_PULL_MS = 600_000;
|
|
6
|
+
const RPC_TIMEOUT_MS = 30_000;
|
|
7
|
+
const MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
8
|
+
const authCache = new Map();
|
|
9
|
+
|
|
10
|
+
function hashToken(t) {
|
|
11
|
+
let h = 0x811c9dc5;
|
|
12
|
+
for (let i = 0; i < t.length; i++) { h ^= t.charCodeAt(i); h = Math.imul(h, 0x01000193); }
|
|
13
|
+
return (h >>> 0).toString(36);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const rate = new Map();
|
|
17
|
+
function rateOk(key, limit, windowMs) {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const cur = rate.get(key);
|
|
20
|
+
if (!cur || now > cur.reset) { rate.set(key, { count: 1, reset: now + windowMs }); return true; }
|
|
21
|
+
cur.count += 1;
|
|
22
|
+
return cur.count <= limit;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function verifyRepoAccess(token, repo, needPush) {
|
|
26
|
+
const key = `${hashToken(token)}:${repo}`;
|
|
27
|
+
const cached = authCache.get(key);
|
|
28
|
+
if (cached) {
|
|
29
|
+
const ttl = cached.push ? AUTH_CACHE_MS : AUTH_CACHE_PULL_MS;
|
|
30
|
+
if (Date.now() - cached.at < ttl) {
|
|
31
|
+
if (needPush && !cached.push) return { ok: false, status: 403 };
|
|
32
|
+
if (!cached.pull) return { ok: false, status: 403 };
|
|
33
|
+
return { ok: true, login: cached.login };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const headers = { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json', 'User-Agent': 'excalidrop-relay' };
|
|
37
|
+
const r = await fetch(`https://api.github.com/repos/${repo}`, { headers }).catch(() => null);
|
|
38
|
+
if (!r || r.status === 404) return { ok: false, status: 404 };
|
|
39
|
+
if (r.status === 401) return { ok: false, status: 403 };
|
|
40
|
+
if (!r.ok) return { ok: false, status: 403 };
|
|
41
|
+
const j = await r.json().catch(() => ({}));
|
|
42
|
+
const pull = !!(j.permissions?.pull ?? true);
|
|
43
|
+
const push = !!j.permissions?.push;
|
|
44
|
+
if (!pull || (needPush && !push)) return { ok: false, status: 403 };
|
|
45
|
+
const me = await fetch('https://api.github.com/user', { headers }).then((x) => x.json()).catch(() => ({}));
|
|
46
|
+
authCache.set(key, { at: Date.now(), login: me.login || '?', pull, push });
|
|
47
|
+
return { ok: true, login: me.login || '?' };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class RelayRoom {
|
|
51
|
+
constructor(state, env) {
|
|
52
|
+
this.state = state;
|
|
53
|
+
this.env = env;
|
|
54
|
+
this.viewers = new Set();
|
|
55
|
+
this.pending = new Map(); // reqId -> { resolve, timer }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async fetch(req) {
|
|
59
|
+
const url = new URL(req.url);
|
|
60
|
+
const repo = url.searchParams.get('repo') || '';
|
|
61
|
+
if (!/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i.test(repo)) {
|
|
62
|
+
return new Response(JSON.stringify({ error: 'bad repo' }), { status: 400 });
|
|
63
|
+
}
|
|
64
|
+
const ip = req.headers.get('cf-connecting-ip') || 'unknown';
|
|
65
|
+
|
|
66
|
+
if (req.headers.get('Upgrade') === 'websocket') {
|
|
67
|
+
if (!rateOk(`ws:${ip}`, 20, 60_000)) return new Response('rate limited', { status: 429 });
|
|
68
|
+
const pair = new WebSocketPair();
|
|
69
|
+
const [client, server] = Object.values(pair);
|
|
70
|
+
this.handleViewer(server, repo);
|
|
71
|
+
return new Response(null, { status: 101, webSocket: client });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const noStore = { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' };
|
|
75
|
+
if (req.method === 'POST') {
|
|
76
|
+
const token = (req.headers.get('Authorization') || '').replace(/^Bearer\s+/i, '');
|
|
77
|
+
if (!token) return new Response(JSON.stringify({ error: 'missing bearer' }), { status: 401, headers: noStore });
|
|
78
|
+
if (!rateOk(`rpc:${hashToken(token)}`, 30, 60_000) || !rateOk(`rpcip:${ip}`, 60, 60_000)) {
|
|
79
|
+
return new Response(JSON.stringify({ error: 'rate limited' }), { status: 429, headers: noStore });
|
|
80
|
+
}
|
|
81
|
+
const len = Number(req.headers.get('content-length') || 0);
|
|
82
|
+
if (len > MAX_BODY_BYTES) return new Response(JSON.stringify({ error: 'too large' }), { status: 413, headers: noStore });
|
|
83
|
+
let body;
|
|
84
|
+
try { body = await req.json(); } catch { return new Response(JSON.stringify({ error: 'bad json' }), { status: 400, headers: noStore }); }
|
|
85
|
+
const method = body.method || url.pathname.split('/').pop();
|
|
86
|
+
const needPush = method !== 'screenshot' && method !== 'viewport' && method !== 'export' && method !== 'describe';
|
|
87
|
+
const v = await verifyRepoAccess(token, repo, needPush);
|
|
88
|
+
const noStore = { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' };
|
|
89
|
+
if (!v.ok) return new Response(JSON.stringify({ error: v.status === 404 ? 'repo not found' : 'no access to this repo with this token' }), { status: v.status, headers: noStore });
|
|
90
|
+
if (this.viewers.size === 0) return new Response(JSON.stringify({ error: 'no viewer connected — open the canvas URL in a browser first' }), { status: 503, headers: noStore });
|
|
91
|
+
const reqId = body.reqId || `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
92
|
+
const msg = JSON.stringify({ type: 'relay_rpc', reqId, method, args: body.args || {} });
|
|
93
|
+
const result = await new Promise((resolve) => {
|
|
94
|
+
const timer = setTimeout(() => { this.pending.delete(reqId); resolve({ error: 'viewer timed out' }); }, RPC_TIMEOUT_MS);
|
|
95
|
+
this.pending.set(reqId, { resolve, timer });
|
|
96
|
+
for (const ws of this.viewers) { try { ws.send(msg); } catch { /* drop */ } }
|
|
97
|
+
});
|
|
98
|
+
if (result?.error) return new Response(JSON.stringify(result), { status: 504, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' } });
|
|
99
|
+
return new Response(JSON.stringify(result), { headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' } });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return new Response(JSON.stringify({ repo, viewers: this.viewers.size }), { headers: { 'Content-Type': 'application/json' } });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
handleViewer(ws, repo) {
|
|
106
|
+
ws.accept();
|
|
107
|
+
let authed = false;
|
|
108
|
+
ws.addEventListener('message', async (ev) => {
|
|
109
|
+
let msg;
|
|
110
|
+
try { msg = JSON.parse(ev.data); } catch { return; }
|
|
111
|
+
if (msg?.type === 'ping') { try { ws.send(JSON.stringify({ type: 'pong' })); } catch {} return; }
|
|
112
|
+
if (!authed) {
|
|
113
|
+
const v = msg?.token ? await verifyRepoAccess(msg.token, repo, false) : { ok: false };
|
|
114
|
+
if (!v.ok) { try { ws.send(JSON.stringify({ error: 'auth failed' })); } catch {} ws.close(4403, 'auth'); return; }
|
|
115
|
+
authed = true;
|
|
116
|
+
this.viewers.add(ws);
|
|
117
|
+
try { ws.send(JSON.stringify({ type: 'relay_ready', repo })); } catch {}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (msg?.reqId && this.pending.has(msg.reqId)) {
|
|
121
|
+
const p = this.pending.get(msg.reqId);
|
|
122
|
+
this.pending.delete(msg.reqId);
|
|
123
|
+
clearTimeout(p.timer);
|
|
124
|
+
p.resolve(msg.ok === false ? { error: msg.error || 'viewer error' } : (msg.data ?? msg.result ?? { ok: true }));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
ws.addEventListener('close', () => { this.viewers.delete(ws); });
|
|
128
|
+
ws.addEventListener('error', () => { this.viewers.delete(ws); });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name = "excalidrop"
|
|
2
|
+
main = "src/index.js"
|
|
3
|
+
compatibility_date = "2024-01-01"
|
|
4
|
+
|
|
5
|
+
# OAuth App client id (public). The secret goes via:
|
|
6
|
+
# wrangler secret put GITHUB_CLIENT_SECRET
|
|
7
|
+
[vars]
|
|
8
|
+
GITHUB_CLIENT_ID = "Iv23liuS2fx3QOEIoDmx"
|
|
9
|
+
# Comma-separated allowed canvas origins: exact ("https://wtf403.github.io")
|
|
10
|
+
# or "*.github.io"-style suffixes so one deployment serves every publisher.
|
|
11
|
+
# Add "*.pages.dev" + your custom domain when hosting private viewers on Cloudflare.
|
|
12
|
+
ALLOWED_REDIRECT_ORIGINS = "*.github.io,*.pages.dev"
|
|
13
|
+
|
|
14
|
+
[[durable_objects.bindings]]
|
|
15
|
+
name = "RELAY"
|
|
16
|
+
class_name = "RelayRoom"
|
|
17
|
+
|
|
18
|
+
[[migrations]]
|
|
19
|
+
tag = "v1"
|
|
20
|
+
new_sqlite_classes = ["RelayRoom"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,E as n}from"./index-DPE4WCka.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./union-BOPJv_NW.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{f as o,p as e}from"./flowDb-956e92f1-BT3sVrS_.js";import{f as a,a as t}from"./styles-c10674c1-CsoDZQ7K.js";import{t as i}from"./index-DMNFnJz0.js";import"./index-DPE4WCka.js";import"./graph-DZoF-TB0.js";import"./layout-DNILJXpj.js";import"./index-3862675e-DkeMPq9X.js";import"./union-BOPJv_NW.js";import"./clone-Bww_2hMC.js";import"./zipObject-BXMcibol.js";import"./edges-e0da2a9e-pqeZxZR9.js";import"./createText-2e5e7dd3-hFM4xCnY.js";import"./index-DGmpr33w.js";import"./line-DHiJikCQ.js";import"./array-BKyUJesY.js";import"./path-CbwjOpE9.js";import"./channel-FdQr2Y2u.js";import"./selectAll-DOPd5EPW.js";const x={parser:e,db:o,renderer:t,styles:a,init:r=>{r.flowchart||(r.flowchart={}),r.flowchart.arrowMarkerAbsolute=r.arrowMarkerAbsolute,i({flowchart:{arrowMarkerAbsolute:r.arrowMarkerAbsolute}}),t.setConf(r.flowchart),o.clear(),o.setGen("gen-2")}};export{x as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{f as o,p as e}from"./flowDb-7c981674-hAdbykWR.js";import{f as a,a as t}from"./styles-2ab5d517-CD2K6uvC.js";import{K as i}from"./index-DPE4WCka.js";import"./graph-DPklf_4J.js";import"./layout-BC6d-Wwh.js";import"./index-6079d271-GJeDwDgK.js";import"./union-BOPJv_NW.js";import"./clone-Bww_2hMC.js";import"./zipObject-BXMcibol.js";import"./edges-332bd1c7-CV1_ozEk.js";import"./createText-d213de94-BcC2siap.js";import"./index-DGmpr33w.js";import"./line-DHiJikCQ.js";import"./array-BKyUJesY.js";import"./path-CbwjOpE9.js";import"./channel-FdQr2Y2u.js";import"./selectAll-DOPd5EPW.js";const C={parser:e,db:o,renderer:t,styles:a,init:r=>{r.flowchart||(r.flowchart={}),r.flowchart.arrowMarkerAbsolute=r.arrowMarkerAbsolute,i({flowchart:{arrowMarkerAbsolute:r.arrowMarkerAbsolute}}),t.setConf(r.flowchart),o.clear(),o.setGen("gen-2")}};export{C as diagram};
|