termdock 1.4.240 → 1.4.242
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/App-CVuPbhP4.js +155 -0
- package/dist/client/assets/App-CVuPbhP4.js.br +0 -0
- package/dist/client/assets/App-CVuPbhP4.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-9whVVXTr.js → ChangeWalkthroughPanel-4kynRLRs.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-4kynRLRs.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-4kynRLRs.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-y80OTTQj.js → DagPlayground-Yx7XBwmM.js} +1 -1
- package/dist/client/assets/DagPlayground-Yx7XBwmM.js.br +0 -0
- package/dist/client/assets/DagPlayground-Yx7XBwmM.js.gz +0 -0
- package/dist/client/assets/{DiffLab-BY2wbRtg.js → DiffLab-Cn1f9iHY.js} +1 -1
- package/dist/client/assets/DiffLab-Cn1f9iHY.js.br +0 -0
- package/dist/client/assets/DiffLab-Cn1f9iHY.js.gz +0 -0
- package/dist/client/assets/{DiffReview-DLlDJbK1.js → DiffReview-BJQ92hBr.js} +1 -1
- package/dist/client/assets/DiffReview-BJQ92hBr.js.br +0 -0
- package/dist/client/assets/DiffReview-BJQ92hBr.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CEpa_B8I.js → DiffReviewLab-CN3a3LhH.js} +1 -1
- package/dist/client/assets/DiffReviewLab-CN3a3LhH.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CN3a3LhH.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-GLkd1zMQ.js → DiffViewer-BFn2Gz8v.js} +1 -1
- package/dist/client/assets/DiffViewer-BFn2Gz8v.js.br +0 -0
- package/dist/client/assets/DiffViewer-BFn2Gz8v.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-DB8tw45f.js → ModelPreview-CC8Uf4et.js} +1 -1
- package/dist/client/assets/ModelPreview-CC8Uf4et.js.br +0 -0
- package/dist/client/assets/ModelPreview-CC8Uf4et.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-aoJjOQGX.js → RightSidebar-Bz9BkzCR.js} +4 -4
- package/dist/client/assets/RightSidebar-Bz9BkzCR.js.br +0 -0
- package/dist/client/assets/RightSidebar-Bz9BkzCR.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-RBGYciHa.js → abnfDiagram-VCTEODGH-hQSzKoeJ.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-hQSzKoeJ.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-hQSzKoeJ.js.gz +0 -0
- package/dist/client/assets/{app-Ctrh4Bku.js → app-CgwJz96Y.js} +9 -9
- package/dist/client/assets/app-CgwJz96Y.js.br +0 -0
- package/dist/client/assets/app-CgwJz96Y.js.gz +0 -0
- package/dist/client/assets/{arc-CzQsNCup.js → arc-DNdtsFHs.js} +1 -1
- package/dist/client/assets/arc-DNdtsFHs.js.br +0 -0
- package/dist/client/assets/arc-DNdtsFHs.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-sDp6hSiy.js → architectureDiagram-5GKGNRK7-ClYN-ZWK.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-ClYN-ZWK.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-ClYN-ZWK.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-C-AHqZPo.js → blockDiagram-I7D4REHJ-ybw8N2u6.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-ybw8N2u6.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-ybw8N2u6.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-B8VGhLwN.js → c4Diagram-7LVT6UL2-BUySB1D8.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-BUySB1D8.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-BUySB1D8.js.gz +0 -0
- package/dist/client/assets/channel-C6y0-VyK.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-D56jCJTr.js → chunk-2Q5K7J3B-DEG-dAIQ.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-cga3WKIM.js → chunk-5VM5RSS4-DkNem54n.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-BNOR_7WA.js → chunk-F27PBJKO-D32jqKl9.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-D32jqKl9.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-D32jqKl9.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-Dk12DKtC.js → chunk-IMKFNOWR-JxJHaym5.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-JxJHaym5.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-JxJHaym5.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-CVqdLg0d.js → chunk-JWPE2WC7-CS7uV1GH.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-Y6gEzK15.js → chunk-POPQ4Y6H-B02kbaJZ.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-BIJtdFBL.js → chunk-SVP7TREG-Bc9XpKmH.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-Bc9XpKmH.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-Bc9XpKmH.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-CS3jsxv7.js → chunk-TICWLB2K-DW69sulY.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-DW69sulY.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-DW69sulY.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-BYgvxPrj.js → chunk-XXDRQBXY-CqHkJ6cA.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-zxEN3eAk.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-zxEN3eAk.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-9udJiW7h.js → cose-bilkent-JH36ORCC-DJAx_fGd.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-DJAx_fGd.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-DJAx_fGd.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-D-6q-6N2.js → cynefin-OW5HDTMX-BJmu05nC.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-BJmu05nC.js.br +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-D-6q-6N2.js.gz → cynefin-OW5HDTMX-BJmu05nC.js.gz} +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-B5c37uFA.js → cynefinDiagram-5FMLGOSQ-B0m0YIa6.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B0m0YIa6.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B0m0YIa6.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-DoFMIka4.js → dagre-GXQ25YYZ-Cbs-u5oy.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-Cbs-u5oy.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-Cbs-u5oy.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-DrAwxGx7.js → diagram-S7CK7UJ4-DnFgNCva.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-DnFgNCva.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DnFgNCva.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-DbWfEzKd.js → diagram-UQ7AKVKN-CRbBEuHO.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-CRbBEuHO.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-CRbBEuHO.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-zKcVacRq.js → diagram-VSXAHHWV-CIPivMwW.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-CIPivMwW.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-CIPivMwW.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-BNAI-5sG.js → diagram-VX7I27RA-CY8G867I.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-CY8G867I.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-CY8G867I.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-ChB9ZeuK.js → diagram-Z3DM3KII-owVjuxom.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-owVjuxom.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-owVjuxom.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-Fe8VFmWJ.js → ebnfDiagram-PWID7BFC-DMoOEDnf.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-DMoOEDnf.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-DMoOEDnf.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-CC7DagoX.js → erDiagram-RLTQ6QDP-DuEHUYT0.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-DuEHUYT0.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DuEHUYT0.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-BBIgixMV.js → flowDiagram-HODETNUW-Duys8g5v.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-Duys8g5v.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-Duys8g5v.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-CHRaIQ9P.js → ganttDiagram-EL5Y4UJY-4uNGC3eO.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-4uNGC3eO.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-4uNGC3eO.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-5c1oGojb.js → gestureArbiter-CTk63JTf.js} +1 -1
- package/dist/client/assets/gestureArbiter-CTk63JTf.js.br +0 -0
- package/dist/client/assets/gestureArbiter-CTk63JTf.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-iJPivC9C.js → gitGraphDiagram-WWUBYQGX-CoNcYxET.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-CoNcYxET.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-CoNcYxET.js.gz +0 -0
- package/dist/client/assets/{index-BzglvLj5.css → index-QFRD5OND.css} +1 -1
- package/dist/client/assets/index-QFRD5OND.css.br +0 -0
- package/dist/client/assets/{index-BzglvLj5.css.gz → index-QFRD5OND.css.gz} +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-CWjxPUb1.js → infoDiagram-27XIBGKW-D1APvjL0.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-2dN_H6WK.js → ishikawaDiagram-5VMMS53U-B0CGmgD9.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-B0CGmgD9.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-B0CGmgD9.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-BqY-OLE2.js → journeyDiagram-3NMN7TZE-BIcr4OmP.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BIcr4OmP.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BIcr4OmP.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-CSOXhjNh.js → kanban-definition-UXKFOSKX-BGY-UCFp.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-BGY-UCFp.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-BGY-UCFp.js.gz +0 -0
- package/dist/client/assets/{layout-BxIcRRf7.js → layout-Dy-XBjcQ.js} +1 -1
- package/dist/client/assets/layout-Dy-XBjcQ.js.br +0 -0
- package/dist/client/assets/layout-Dy-XBjcQ.js.gz +0 -0
- package/dist/client/assets/{linear-BYWiw-Yd.js → linear-DGdoGGqI.js} +1 -1
- package/dist/client/assets/linear-DGdoGGqI.js.br +0 -0
- package/dist/client/assets/linear-DGdoGGqI.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DhRpdkKn.js → mermaid.core-uUtQ6Zvd.js} +5 -5
- package/dist/client/assets/mermaid.core-uUtQ6Zvd.js.br +0 -0
- package/dist/client/assets/mermaid.core-uUtQ6Zvd.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-DwBcGwTF.js → mindmap-definition-YA3MSWOX-BBMP8prO.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-BBMP8prO.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-BBMP8prO.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-BkAa-DO2.js → passwordBootstrap-CazWrYzP.js} +1 -1
- package/dist/client/assets/{passwordBootstrap-BkAa-DO2.js.br → passwordBootstrap-CazWrYzP.js.br} +0 -0
- package/dist/client/assets/{passwordBootstrap-BkAa-DO2.js.gz → passwordBootstrap-CazWrYzP.js.gz} +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-D_04AQMs.js → pegDiagram-XKGWAZYB-BvxAwgS8.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-BvxAwgS8.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BvxAwgS8.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-DgHIGdDc.js → pieDiagram-E7YTZNPT-DZ4F26FA.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-DZ4F26FA.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DZ4F26FA.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BrxP_uCp.js → quadrantDiagram-AXDQQJYC-FJGBvmNp.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-FJGBvmNp.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-FJGBvmNp.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-Bj8aV8et.js → railroadDiagram-O6MQD6OU-B4f16qlN.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-B4f16qlN.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-B4f16qlN.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-CG4k8F2W.js → referenceLongPress-4ydKrZtC.js} +1 -1
- package/dist/client/assets/referenceLongPress-4ydKrZtC.js.br +0 -0
- package/dist/client/assets/referenceLongPress-4ydKrZtC.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-DHOBnmaH.js → requirementDiagram-BXWQKSXE-DDEDP28y.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DDEDP28y.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DDEDP28y.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-B46rNwzQ.js → sankeyDiagram-P5KCCOFB-eZbHgAJ2.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-eZbHgAJ2.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-eZbHgAJ2.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-D8PnDgC6.js → sequenceDiagram-WJ2MYXX4-C26sID_J.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-C26sID_J.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-C26sID_J.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CjofpSnZ.js → sizeCapture-INFHLROL-CunqRjZH.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-CunqRjZH.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CunqRjZH.js.gz +0 -0
- package/dist/client/assets/{sparkles-Zi8g0TMb.js → sparkles-Cs8KAbL4.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-BX_StFJV.js → stateDiagram-D77RDMKH-BDCgrd2K.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-BDCgrd2K.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BDCgrd2K.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-JBMsRqan.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-bxGulCYh.js → swimlanes-42K2YHIH-ClJ98iVo.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-ClJ98iVo.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-ClJ98iVo.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BvtpepbK.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-DcHYPI0d.js → timeline-definition-24CTP7MA-CDCDunzZ.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-CDCDunzZ.js.br +0 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-DcHYPI0d.js.gz → timeline-definition-24CTP7MA-CDCDunzZ.js.gz} +0 -0
- package/dist/client/assets/{triangle-alert-BXXcxTk8.js → triangle-alert-B0gXRJJm.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CjIGwkZf.js → vennDiagram-4TSXK5OY-BBqRUM5-.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-CjIGwkZf.js.br → vennDiagram-4TSXK5OY-BBqRUM5-.js.br} +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-BBqRUM5-.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-B-WK3Fil.js → wardleyDiagram-VM6X3IG4-DKpVgjww.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DKpVgjww.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-DKpVgjww.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-4RzKQfNK.js → xychartDiagram-S5SC5T6Z-CHwA2dfA.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-CHwA2dfA.js.br +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-4RzKQfNK.js.gz → xychartDiagram-S5SC5T6Z-CHwA2dfA.js.gz} +0 -0
- package/dist/client/index.html +2 -2
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw.js +1 -1
- package/dist/client/sw.js.br +0 -0
- package/dist/client/sw.js.gz +0 -0
- package/dist/server/cli.js +56 -42
- package/dist/server/entry.js +24 -2
- package/dist/server/federation/relay.js +3 -0
- package/dist/server/federation/routeAccess.js +39 -2
- package/dist/server/federation/runtime.js +5 -0
- package/dist/server/federation/selfRelay.js +182 -0
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/dist/client/assets/App-CmlGDKDj.js +0 -155
- package/dist/client/assets/App-CmlGDKDj.js.br +0 -0
- package/dist/client/assets/App-CmlGDKDj.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-9whVVXTr.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-9whVVXTr.js.gz +0 -0
- package/dist/client/assets/DagPlayground-y80OTTQj.js.br +0 -0
- package/dist/client/assets/DagPlayground-y80OTTQj.js.gz +0 -0
- package/dist/client/assets/DiffLab-BY2wbRtg.js.br +0 -0
- package/dist/client/assets/DiffLab-BY2wbRtg.js.gz +0 -0
- package/dist/client/assets/DiffReview-DLlDJbK1.js.br +0 -0
- package/dist/client/assets/DiffReview-DLlDJbK1.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CEpa_B8I.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CEpa_B8I.js.gz +0 -0
- package/dist/client/assets/DiffViewer-GLkd1zMQ.js.br +0 -0
- package/dist/client/assets/DiffViewer-GLkd1zMQ.js.gz +0 -0
- package/dist/client/assets/ModelPreview-DB8tw45f.js.br +0 -0
- package/dist/client/assets/ModelPreview-DB8tw45f.js.gz +0 -0
- package/dist/client/assets/RightSidebar-aoJjOQGX.js.br +0 -0
- package/dist/client/assets/RightSidebar-aoJjOQGX.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-RBGYciHa.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-RBGYciHa.js.gz +0 -0
- package/dist/client/assets/app-Ctrh4Bku.js.br +0 -0
- package/dist/client/assets/app-Ctrh4Bku.js.gz +0 -0
- package/dist/client/assets/arc-CzQsNCup.js.br +0 -0
- package/dist/client/assets/arc-CzQsNCup.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-sDp6hSiy.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-sDp6hSiy.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-C-AHqZPo.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-C-AHqZPo.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-B8VGhLwN.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-B8VGhLwN.js.gz +0 -0
- package/dist/client/assets/channel-zK78er-R.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-BNOR_7WA.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-BNOR_7WA.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-Dk12DKtC.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-Dk12DKtC.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BIJtdFBL.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-BIJtdFBL.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CS3jsxv7.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CS3jsxv7.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-BMh5Sak3.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BMh5Sak3.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-9udJiW7h.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-9udJiW7h.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-D-6q-6N2.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B5c37uFA.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-B5c37uFA.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-DoFMIka4.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-DoFMIka4.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DrAwxGx7.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-DrAwxGx7.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DbWfEzKd.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DbWfEzKd.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-zKcVacRq.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-zKcVacRq.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-BNAI-5sG.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-BNAI-5sG.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-ChB9ZeuK.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-ChB9ZeuK.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Fe8VFmWJ.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Fe8VFmWJ.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CC7DagoX.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CC7DagoX.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BBIgixMV.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-BBIgixMV.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CHRaIQ9P.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CHRaIQ9P.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-5c1oGojb.js.br +0 -0
- package/dist/client/assets/gestureArbiter-5c1oGojb.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-iJPivC9C.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-iJPivC9C.js.gz +0 -0
- package/dist/client/assets/index-BzglvLj5.css.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-2dN_H6WK.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-2dN_H6WK.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BqY-OLE2.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-BqY-OLE2.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CSOXhjNh.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CSOXhjNh.js.gz +0 -0
- package/dist/client/assets/layout-BxIcRRf7.js.br +0 -0
- package/dist/client/assets/layout-BxIcRRf7.js.gz +0 -0
- package/dist/client/assets/linear-BYWiw-Yd.js.br +0 -0
- package/dist/client/assets/linear-BYWiw-Yd.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DhRpdkKn.js.br +0 -0
- package/dist/client/assets/mermaid.core-DhRpdkKn.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DwBcGwTF.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DwBcGwTF.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-D_04AQMs.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-D_04AQMs.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DgHIGdDc.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DgHIGdDc.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BrxP_uCp.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BrxP_uCp.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Bj8aV8et.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-Bj8aV8et.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-CG4k8F2W.js.br +0 -0
- package/dist/client/assets/referenceLongPress-CG4k8F2W.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DHOBnmaH.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-DHOBnmaH.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-B46rNwzQ.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-B46rNwzQ.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D8PnDgC6.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D8PnDgC6.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CjofpSnZ.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CjofpSnZ.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BX_StFJV.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BX_StFJV.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CMG96YGj.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-bxGulCYh.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-bxGulCYh.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-sPKOywKp.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-DcHYPI0d.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-CjIGwkZf.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B-WK3Fil.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B-WK3Fil.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-4RzKQfNK.js.br +0 -0
package/dist/server/entry.js
CHANGED
|
@@ -14,6 +14,7 @@ import { RouteInvitationStore } from './federation/routeInvitations.js';
|
|
|
14
14
|
import { attachRegisteredDirectTargets, verifyDirectTarget } from './federation/directRoutes.js';
|
|
15
15
|
import { secureChannelOriginAllowed } from './federation/originPolicy.js';
|
|
16
16
|
import { RelayRouter } from './federation/relay.js';
|
|
17
|
+
import { DesktopSelfRelay } from './federation/selfRelay.js';
|
|
17
18
|
import { assertPublicSecurity, securityHeaders } from './utils/publicSecurity.js';
|
|
18
19
|
import { apiCachePolicy } from './utils/apiCachePolicy.js';
|
|
19
20
|
import 'dotenv/config';
|
|
@@ -415,13 +416,15 @@ export function startServer(options = {}) {
|
|
|
415
416
|
let entrySubjectAllowed = (_subjectId) => false;
|
|
416
417
|
let routeInvitations;
|
|
417
418
|
let federationServiceId = '';
|
|
419
|
+
let activeRouteIds = () => [];
|
|
418
420
|
const desktopTargets = () => desktopDirectTargets(path.join(homedir(), '.termdock', 'desktop.json'), federationServiceId);
|
|
419
|
-
const routeAccess = new RouteAccess(path.join(homedir(), '.termdock', 'federation', 'routes.json'), Date.now, (subjectId, targetServiceId) => routeInvitations?.allows(subjectId, targetServiceId) === true || collaborationTransport?.canRoute(subjectId, targetServiceId) === true, desktopTargets);
|
|
421
|
+
const routeAccess = new RouteAccess(path.join(homedir(), '.termdock', 'federation', 'routes.json'), Date.now, (subjectId, targetServiceId) => routeInvitations?.allows(subjectId, targetServiceId) === true || collaborationTransport?.canRoute(subjectId, targetServiceId) === true, desktopTargets, () => activeRouteIds());
|
|
420
422
|
const relayRouter = new RelayRouter({
|
|
421
423
|
authenticate: context => context,
|
|
422
424
|
allowRegister: (principal, serviceId) => routeAccess.allowRegister(principal, serviceId),
|
|
423
425
|
allowRoute: (principal, serviceId) => routeAccess.allowRoute(principal, serviceId),
|
|
424
426
|
});
|
|
427
|
+
activeRouteIds = () => relayRouter.activeRouteIds();
|
|
425
428
|
const dynamicDirectTargets = new Map();
|
|
426
429
|
const refreshDirectTargets = () => {
|
|
427
430
|
const desired = new Map(routeAccess.configuredDirectTargets().filter(target => target.serviceId !== federationServiceId).map(target => [target.serviceId, target]));
|
|
@@ -493,6 +496,7 @@ export function startServer(options = {}) {
|
|
|
493
496
|
},
|
|
494
497
|
revokeRouteAccess: id => routeInvitations?.revoke(id) || false,
|
|
495
498
|
issueRouteTicket: (subjectId, serviceId) => routeAccess.issueRouteTicket(subjectId, serviceId),
|
|
499
|
+
issueSelfRelayTicket: (serviceId) => routeAccess.issueSelfRelayTicket(serviceId),
|
|
496
500
|
hasRouteGrant: (subjectId, serviceId) => routeInvitations?.allows(subjectId, serviceId) === true || collaborationTransport?.canRoute(subjectId, serviceId) === true,
|
|
497
501
|
createRouteInvitation: (issuerId, serviceId) => {
|
|
498
502
|
if (!routeInvitations)
|
|
@@ -567,6 +571,20 @@ export function startServer(options = {}) {
|
|
|
567
571
|
issuerAllowed: subjectId => entrySubjectAllowed(subjectId),
|
|
568
572
|
targetAvailable: serviceId => routeAccess.hasConfiguredTarget(serviceId) && relayRouter.hasRoute(serviceId),
|
|
569
573
|
});
|
|
574
|
+
let localCa;
|
|
575
|
+
if (scheme === 'https' && options.httpsCaPath)
|
|
576
|
+
try {
|
|
577
|
+
localCa = fs.readFileSync(options.httpsCaPath);
|
|
578
|
+
}
|
|
579
|
+
catch { /* System trust may still validate the local certificate. */ }
|
|
580
|
+
const localHostname = ['0.0.0.0', '::'].includes(host) ? 'localhost' : host;
|
|
581
|
+
const localAuthority = localHostname.includes(':') && !localHostname.startsWith('[') ? `[${localHostname}]` : localHostname;
|
|
582
|
+
const selfRelay = new DesktopSelfRelay({
|
|
583
|
+
desktopFile: path.join(homedir(), '.termdock', 'desktop.json'), identity: runtime.identity, serviceId: runtime.serviceId,
|
|
584
|
+
localOrigin: `${scheme}://${localAuthority}:${port}`, ...(localCa ? { localCa } : {}),
|
|
585
|
+
});
|
|
586
|
+
selfRelay.start();
|
|
587
|
+
server.once('close', () => selfRelay.close());
|
|
570
588
|
}).catch(() => console.error('Route invitations unavailable; uninitialized route grants remain denied.'));
|
|
571
589
|
void federation.catch(() => console.error('Encrypted access initialization failed; business access remains closed.'));
|
|
572
590
|
server.once('close', () => { void federation.then(runtime => runtime.close()).catch(() => { }); });
|
|
@@ -661,7 +679,11 @@ export function startServer(options = {}) {
|
|
|
661
679
|
socket.end('HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n');
|
|
662
680
|
return;
|
|
663
681
|
}
|
|
664
|
-
const
|
|
682
|
+
const routeToken = url.searchParams.get('routeToken');
|
|
683
|
+
const selfRelayToken = url.searchParams.get('selfRelayToken');
|
|
684
|
+
const principal = selfRelayToken && !request.headers.authorization && !routeToken
|
|
685
|
+
? routeAccess.authenticateSelfRelay(selfRelayToken)
|
|
686
|
+
: !selfRelayToken ? routeAccess.authenticate(request.headers.authorization, routeToken) : null;
|
|
665
687
|
if (!principal) {
|
|
666
688
|
socket.end('HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n');
|
|
667
689
|
return;
|
|
@@ -111,6 +111,9 @@ export class RelayRouter {
|
|
|
111
111
|
const route = this.routes.get(serviceId);
|
|
112
112
|
return !this.stopped && !!route && route.expires > Date.now() && route.peer.ws.readyState === 1 && this.canRegister(route.peer, serviceId);
|
|
113
113
|
}
|
|
114
|
+
activeRouteIds() {
|
|
115
|
+
return [...this.routes.keys()].filter(serviceId => this.hasRoute(serviceId));
|
|
116
|
+
}
|
|
114
117
|
/** Trusted local configuration only. Clients never supply a target URL or factory. */
|
|
115
118
|
registerDirect(serviceId, connect) {
|
|
116
119
|
if (this.stopped || !identifier(serviceId) || typeof connect !== 'function' || this.hasRoute(serviceId))
|
|
@@ -9,12 +9,15 @@ export class RouteAccess {
|
|
|
9
9
|
now;
|
|
10
10
|
canRouteSubject;
|
|
11
11
|
additionalTargets;
|
|
12
|
+
additionalTargetIds;
|
|
12
13
|
tickets = new Map();
|
|
13
|
-
|
|
14
|
+
selfRelayTickets = new Map();
|
|
15
|
+
constructor(filePath, now = Date.now, canRouteSubject = () => false, additionalTargets = () => [], additionalTargetIds = () => []) {
|
|
14
16
|
this.filePath = filePath;
|
|
15
17
|
this.now = now;
|
|
16
18
|
this.canRouteSubject = canRouteSubject;
|
|
17
19
|
this.additionalTargets = additionalTargets;
|
|
20
|
+
this.additionalTargetIds = additionalTargetIds;
|
|
18
21
|
}
|
|
19
22
|
registry() {
|
|
20
23
|
const empty = { relays: [], directTargets: [] };
|
|
@@ -62,6 +65,34 @@ export class RouteAccess {
|
|
|
62
65
|
this.tickets.set(digest(routeToken).toString('hex'), { subjectId, serviceId, expiresAt });
|
|
63
66
|
return { routeToken, expiresAt };
|
|
64
67
|
}
|
|
68
|
+
/** A Noise-authenticated service can advertise only its own identity. The
|
|
69
|
+
* short-lived token merely transfers that identity onto the relay socket; it
|
|
70
|
+
* grants neither route use nor target-service access. */
|
|
71
|
+
issueSelfRelayTicket(serviceId) {
|
|
72
|
+
if (!validId(serviceId))
|
|
73
|
+
throw new Error('INVALID_SELF_RELAY_IDENTITY');
|
|
74
|
+
for (const [key, value] of this.selfRelayTickets)
|
|
75
|
+
if (value.expiresAt <= this.now())
|
|
76
|
+
this.selfRelayTickets.delete(key);
|
|
77
|
+
if (this.selfRelayTickets.size >= 1024)
|
|
78
|
+
throw new Error('SELF_RELAY_TICKET_LIMIT');
|
|
79
|
+
const selfRelayToken = randomBytes(32).toString('base64url');
|
|
80
|
+
const expiresAt = this.now() + 30_000;
|
|
81
|
+
this.selfRelayTickets.set(digest(selfRelayToken).toString('hex'), { serviceId, expiresAt });
|
|
82
|
+
return { selfRelayToken, expiresAt };
|
|
83
|
+
}
|
|
84
|
+
/** Single-use, fail-closed transfer from the authenticated Noise channel to
|
|
85
|
+
* the opaque relay transport. */
|
|
86
|
+
authenticateSelfRelay(selfRelayToken) {
|
|
87
|
+
if (!selfRelayToken || selfRelayToken.length > 512)
|
|
88
|
+
return null;
|
|
89
|
+
const key = digest(selfRelayToken).toString('hex');
|
|
90
|
+
const ticket = this.selfRelayTickets.get(key);
|
|
91
|
+
this.selfRelayTickets.delete(key);
|
|
92
|
+
if (!ticket || ticket.expiresAt <= this.now())
|
|
93
|
+
return null;
|
|
94
|
+
return { kind: 'self-relay', serviceId: ticket.serviceId };
|
|
95
|
+
}
|
|
65
96
|
/** Called once before upgrading. A route ticket is consumed even if expired. */
|
|
66
97
|
authenticate(authorization, routeToken) {
|
|
67
98
|
if (authorization && routeToken)
|
|
@@ -83,6 +114,8 @@ export class RouteAccess {
|
|
|
83
114
|
return { kind: 'client', subjectId: ticket.subjectId, serviceId: ticket.serviceId };
|
|
84
115
|
}
|
|
85
116
|
allowRegister(principal, serviceId) {
|
|
117
|
+
if (principal.kind === 'self-relay')
|
|
118
|
+
return principal.serviceId === serviceId;
|
|
86
119
|
return principal.kind === 'relay' && this.relays().some(r => r.id === principal.id && digest(r.token).toString('hex') === principal.tokenHash && r.targets.includes(serviceId));
|
|
87
120
|
}
|
|
88
121
|
allowRoute(principal, serviceId) {
|
|
@@ -92,7 +125,8 @@ export class RouteAccess {
|
|
|
92
125
|
if (!validId(serviceId))
|
|
93
126
|
return false;
|
|
94
127
|
const registry = this.registry();
|
|
95
|
-
return registry.relays.some(relay => relay.targets.includes(serviceId)) || registry.directTargets.some(target => target.serviceId === serviceId)
|
|
128
|
+
return registry.relays.some(relay => relay.targets.includes(serviceId)) || registry.directTargets.some(target => target.serviceId === serviceId)
|
|
129
|
+
|| this.additionalTargets().some(target => target.serviceId === serviceId) || this.additionalTargetIds().includes(serviceId);
|
|
96
130
|
}
|
|
97
131
|
addDirectTarget(target) {
|
|
98
132
|
const url = new URL(target.url);
|
|
@@ -139,6 +173,9 @@ export class RouteAccess {
|
|
|
139
173
|
url.protocol = 'https:';
|
|
140
174
|
targets.set(target.serviceId, { serviceId: target.serviceId, url: url.origin, ...(target.label ? { label: target.label } : {}) });
|
|
141
175
|
}
|
|
176
|
+
for (const serviceId of this.additionalTargetIds())
|
|
177
|
+
if (validId(serviceId) && !targets.has(serviceId))
|
|
178
|
+
targets.set(serviceId, { serviceId });
|
|
142
179
|
return [...targets.values()];
|
|
143
180
|
}
|
|
144
181
|
}
|
|
@@ -356,6 +356,11 @@ export async function createFederationRuntime(app, directory, handlers, options
|
|
|
356
356
|
});
|
|
357
357
|
send({ type: 'result', id: packet.id, items });
|
|
358
358
|
}
|
|
359
|
+
else if (packet.type === 'self-relay-ticket') {
|
|
360
|
+
if (!options.issueSelfRelayTicket)
|
|
361
|
+
throw new Error('SELF_RELAY_UNAVAILABLE');
|
|
362
|
+
send({ type: 'result', id: packet.id, serviceId: subjectId, ...options.issueSelfRelayTicket(subjectId) });
|
|
363
|
+
}
|
|
359
364
|
else if (packet.type === 'route-invite-create') {
|
|
360
365
|
check('authorization.manage');
|
|
361
366
|
if (!options.createRouteInvitation || typeof packet.serviceId !== 'string' || !packet.serviceId || packet.serviceId.length > 512)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { desktopDirectTargets } from './desktopTargets.js';
|
|
3
|
+
import { RelayClient } from './relay.js';
|
|
4
|
+
import { readPinnedCertificateAuthority } from './trustedCa.js';
|
|
5
|
+
import { connectCollaborationRpc } from '../agent/collaborationPeerTransport.js';
|
|
6
|
+
function relayEndpoint(origin, selfRelayToken) {
|
|
7
|
+
const url = new URL('/api/federation/relay', origin);
|
|
8
|
+
url.protocol = 'wss:';
|
|
9
|
+
url.searchParams.set('selfRelayToken', selfRelayToken);
|
|
10
|
+
return url.href;
|
|
11
|
+
}
|
|
12
|
+
function secureEndpoint(origin) {
|
|
13
|
+
const url = new URL('/api/federation/secure', origin);
|
|
14
|
+
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
15
|
+
return url.href;
|
|
16
|
+
}
|
|
17
|
+
function openSocket(url, ca, maxPayload = 256 * 1024) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const secure = new URL(url).protocol === 'wss:';
|
|
20
|
+
const socket = new WebSocket(url, {
|
|
21
|
+
...(secure ? { ...(ca ? { ca } : {}), rejectUnauthorized: true } : {}),
|
|
22
|
+
followRedirects: false,
|
|
23
|
+
handshakeTimeout: 10_000,
|
|
24
|
+
maxPayload,
|
|
25
|
+
});
|
|
26
|
+
const failed = () => { cleanup(); socket.terminate(); reject(new Error('SELF_RELAY_CONNECTION_FAILED')); };
|
|
27
|
+
const opened = () => { cleanup(); socket.on('error', () => socket.terminate()); resolve(socket); };
|
|
28
|
+
const cleanup = () => { socket.off('open', opened); socket.off('error', failed); socket.off('close', failed); };
|
|
29
|
+
socket.once('open', opened);
|
|
30
|
+
socket.once('error', failed);
|
|
31
|
+
socket.once('close', failed);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function waitForReady(socket) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const timer = setTimeout(() => fail(), 10_000);
|
|
37
|
+
timer.unref?.();
|
|
38
|
+
const cleanup = () => { clearTimeout(timer); socket.off('message', ready); socket.off('close', fail); };
|
|
39
|
+
const fail = () => { cleanup(); socket.terminate(); reject(new Error('SELF_RELAY_AUTHENTICATION_FAILED')); };
|
|
40
|
+
const ready = (raw, binary) => {
|
|
41
|
+
try {
|
|
42
|
+
const frame = binary ? null : JSON.parse(raw.toString());
|
|
43
|
+
if (frame?.type !== 'ready') {
|
|
44
|
+
fail();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
cleanup();
|
|
48
|
+
resolve();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
fail();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
socket.once('message', ready);
|
|
55
|
+
socket.once('close', fail);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A local Termdock service may publish only its own stable identity to other
|
|
60
|
+
* services pinned by the same Desktop installation. Desktop supplies addresses
|
|
61
|
+
* and CA pins only; the service proves itself with its own Noise identity and
|
|
62
|
+
* no browser/device authorization is copied into this process.
|
|
63
|
+
*/
|
|
64
|
+
export class DesktopSelfRelay {
|
|
65
|
+
options;
|
|
66
|
+
states = new Map();
|
|
67
|
+
timer;
|
|
68
|
+
stopped = false;
|
|
69
|
+
constructor(options) {
|
|
70
|
+
this.options = options;
|
|
71
|
+
}
|
|
72
|
+
start() {
|
|
73
|
+
if (this.timer || this.stopped)
|
|
74
|
+
return;
|
|
75
|
+
this.refresh();
|
|
76
|
+
this.timer = setInterval(() => this.refresh(), 2_000);
|
|
77
|
+
this.timer.unref?.();
|
|
78
|
+
}
|
|
79
|
+
close() {
|
|
80
|
+
if (this.stopped)
|
|
81
|
+
return;
|
|
82
|
+
this.stopped = true;
|
|
83
|
+
clearInterval(this.timer);
|
|
84
|
+
this.timer = undefined;
|
|
85
|
+
for (const state of this.states.values())
|
|
86
|
+
this.stopState(state);
|
|
87
|
+
this.states.clear();
|
|
88
|
+
}
|
|
89
|
+
refresh() {
|
|
90
|
+
if (this.stopped)
|
|
91
|
+
return;
|
|
92
|
+
const desired = new Map(desktopDirectTargets(this.options.desktopFile, this.options.serviceId)
|
|
93
|
+
.map(target => [target.serviceId, target]));
|
|
94
|
+
for (const [serviceId, state] of this.states) {
|
|
95
|
+
const target = desired.get(serviceId);
|
|
96
|
+
const signature = target && JSON.stringify([target.url, target.caFingerprint256]);
|
|
97
|
+
if (!target || signature !== state.signature) {
|
|
98
|
+
this.stopState(state);
|
|
99
|
+
this.states.delete(serviceId);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const [serviceId, target] of desired)
|
|
103
|
+
if (!this.states.has(serviceId)) {
|
|
104
|
+
const state = { signature: JSON.stringify([target.url, target.caFingerprint256]), stopped: false };
|
|
105
|
+
this.states.set(serviceId, state);
|
|
106
|
+
void this.run(state, target);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
stopState(state) {
|
|
110
|
+
if (state.stopped)
|
|
111
|
+
return;
|
|
112
|
+
state.stopped = true;
|
|
113
|
+
state.wake?.();
|
|
114
|
+
state.wake = undefined;
|
|
115
|
+
state.client?.close();
|
|
116
|
+
state.client = undefined;
|
|
117
|
+
state.upstream?.terminate();
|
|
118
|
+
state.upstream = undefined;
|
|
119
|
+
}
|
|
120
|
+
async run(state, target) {
|
|
121
|
+
let delay = 1_000;
|
|
122
|
+
while (!this.stopped && !state.stopped) {
|
|
123
|
+
try {
|
|
124
|
+
await this.connect(state, target);
|
|
125
|
+
delay = 1_000;
|
|
126
|
+
}
|
|
127
|
+
catch { /* Offline and older entries remain dormant and retry with backoff. */ }
|
|
128
|
+
if (this.stopped || state.stopped)
|
|
129
|
+
break;
|
|
130
|
+
await new Promise(resolve => {
|
|
131
|
+
const timer = setTimeout(() => { state.wake = undefined; resolve(); }, delay);
|
|
132
|
+
timer.unref?.();
|
|
133
|
+
state.wake = () => { clearTimeout(timer); state.wake = undefined; resolve(); };
|
|
134
|
+
});
|
|
135
|
+
delay = Math.min(delay * 2, 30_000);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async connect(state, target) {
|
|
139
|
+
const peer = { serviceId: target.serviceId, origin: target.url, ...(target.caFingerprint256 ? { caFingerprint256: target.caFingerprint256 } : {}) };
|
|
140
|
+
const rpc = await connectCollaborationRpc(this.options.identity, peer);
|
|
141
|
+
let selfRelayToken;
|
|
142
|
+
try {
|
|
143
|
+
const result = await rpc.request({ type: 'self-relay-ticket' });
|
|
144
|
+
if (result.serviceId !== this.options.serviceId || typeof result.selfRelayToken !== 'string'
|
|
145
|
+
|| !/^[A-Za-z0-9_-]{43}$/.test(result.selfRelayToken))
|
|
146
|
+
throw new Error('INVALID_SELF_RELAY_TICKET');
|
|
147
|
+
selfRelayToken = result.selfRelayToken;
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
rpc.close();
|
|
151
|
+
}
|
|
152
|
+
if (this.stopped || state.stopped)
|
|
153
|
+
return;
|
|
154
|
+
const ca = target.caFingerprint256 ? await readPinnedCertificateAuthority(target.url, target.caFingerprint256) : undefined;
|
|
155
|
+
const upstream = await openSocket(relayEndpoint(target.url, selfRelayToken), ca);
|
|
156
|
+
state.upstream = upstream;
|
|
157
|
+
try {
|
|
158
|
+
if (this.stopped || state.stopped)
|
|
159
|
+
return;
|
|
160
|
+
await waitForReady(upstream);
|
|
161
|
+
if (this.stopped || state.stopped)
|
|
162
|
+
return;
|
|
163
|
+
const client = new RelayClient(upstream, { targets: new Map([[this.options.serviceId,
|
|
164
|
+
() => openSocket(secureEndpoint(this.options.localOrigin), this.options.localCa, 1024 * 1024)]]) });
|
|
165
|
+
state.client = client;
|
|
166
|
+
await new Promise(resolve => {
|
|
167
|
+
if (upstream.readyState !== WebSocket.OPEN)
|
|
168
|
+
resolve();
|
|
169
|
+
else
|
|
170
|
+
upstream.once('close', () => resolve());
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
state.client?.close();
|
|
175
|
+
state.client = undefined;
|
|
176
|
+
if (upstream.readyState !== WebSocket.CLOSED)
|
|
177
|
+
upstream.terminate();
|
|
178
|
+
if (state.upstream === upstream)
|
|
179
|
+
state.upstream = undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
package/package.json
CHANGED
package/runtime-manifest.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "termdock",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.242",
|
|
5
5
|
"runtimeProtocolVersion": 1,
|
|
6
6
|
"minimumDesktopVersion": "1.4.46",
|
|
7
7
|
"nodeMajor": 22,
|
|
8
8
|
"dependencyHash": "sha256-K4KyYJuVoQDpZsBM8ZX1Rw3MddOxAzVdp/cPm0iGZz0=",
|
|
9
|
-
"serverBundleHash": "sha256-
|
|
10
|
-
"clientBundleHash": "sha256-
|
|
9
|
+
"serverBundleHash": "sha256-pd6lxkGXO9l4hUWug+Q8/kxaLYDXfSgODkoynCdwgBI=",
|
|
10
|
+
"clientBundleHash": "sha256-v2rqdMlmZKYLB5hGGTlyCG7qH299aT0k0G7gFdoGCCw=",
|
|
11
11
|
"entrypoint": "dist/server/cli.js",
|
|
12
12
|
"clientEntrypoint": "dist/client/index.html"
|
|
13
13
|
}
|