termdock 1.4.167 → 1.4.169
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/ChangeWalkthroughPanel-u9y3e-pI.js +2 -0
- package/dist/client/assets/ChangeWalkthroughPanel-u9y3e-pI.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-u9y3e-pI.js.gz +0 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js +1 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js.br +0 -0
- package/dist/client/assets/DagPlayground-BLUwaOMM.js.gz +0 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js +370 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js.br +0 -0
- package/dist/client/assets/DiffLab-ThgXydJA.js.gz +0 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js +1 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js.br +0 -0
- package/dist/client/assets/DiffReview-DNkXOQ2y.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js +2 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CHyV1WMR.js.gz +0 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js +35 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js.br +0 -0
- package/dist/client/assets/DiffViewer-CxxOpsVz.js.gz +0 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css +1 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css.br +0 -0
- package/dist/client/assets/DiffViewer-T3uj2-aP.css.gz +0 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js +4112 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js.br +0 -0
- package/dist/client/assets/ModelPreview-DZzx3Tzo.js.gz +0 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js +55 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js.br +0 -0
- package/dist/client/assets/RightSidebar-Bv8Y6hqx.js.gz +0 -0
- package/dist/client/assets/RightSidebar-DW-JEgm2.css +1 -0
- package/dist/client/assets/{abnfDiagram-VRR7QNED-evEaZuvk.js → abnfDiagram-VCTEODGH-DKmZLRlf.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-DKmZLRlf.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-DKmZLRlf.js.gz +0 -0
- package/dist/client/assets/app-tT08GaCs.js +175 -0
- package/dist/client/assets/app-tT08GaCs.js.br +0 -0
- package/dist/client/assets/app-tT08GaCs.js.gz +0 -0
- package/dist/client/assets/arc-CjmHoRed.js +1 -0
- package/dist/client/assets/arc-CjmHoRed.js.br +0 -0
- package/dist/client/assets/arc-CjmHoRed.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js +36 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-B0EDOwYH.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js +129 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-CW-AaouZ.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js +38 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-aE7hFKfo.js.gz +0 -0
- package/dist/client/assets/channel-DhsPQnwY.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-mc5fifzP.js → chunk-2Q5K7J3B-FAEL5P17.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-BZB3rwoP.js → chunk-5VM5RSS4-BQJAvucM.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js +1 -0
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-DEkt187T.js.gz +0 -0
- package/dist/client/assets/{chunk-EX3LRPZG-Bvw9RqK9.js → chunk-IMKFNOWR-BfOJ-x_l.js} +5 -5
- package/dist/client/assets/chunk-IMKFNOWR-BfOJ-x_l.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-BfOJ-x_l.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-CSO1rP6P.js → chunk-JWPE2WC7-BN6q6jKH.js} +1 -1
- package/dist/client/assets/chunk-POPQ4Y6H-BrhQRNCn.js +1 -0
- package/dist/client/assets/{chunk-MOJQB5TN-Ds4d9rRG.js → chunk-SVP7TREG-CjZOC5Dj.js} +4 -4
- package/dist/client/assets/chunk-SVP7TREG-CjZOC5Dj.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-CjZOC5Dj.js.gz +0 -0
- package/dist/client/assets/{chunk-V7JOEXUC-DXbeWqbK.js → chunk-TICWLB2K-Wshj9ws7.js} +3 -3
- package/dist/client/assets/chunk-TICWLB2K-Wshj9ws7.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-Wshj9ws7.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-CQVKeEmY.js → chunk-XXDRQBXY-BPPghuc3.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-2OomHNTG.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-2OomHNTG.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CweTDwez.js → cose-bilkent-JH36ORCC-BjxJYQH8.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-BjxJYQH8.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-BjxJYQH8.js.gz +0 -0
- package/dist/client/assets/{cynefin-VYW2F7L2-B_1TU70O.js → cynefin-OW5HDTMX-QmUTVmd_.js} +38 -38
- package/dist/client/assets/cynefin-OW5HDTMX-QmUTVmd_.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-QmUTVmd_.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js +62 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CBJtWB9m.js.gz +0 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js.br +0 -0
- package/dist/client/assets/cytoscape.esm-D3_iZ_3b.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js +4 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-CJFctjtR.js.gz +0 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js.br +0 -0
- package/dist/client/assets/defaultLocale-CrowFXzY.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js +30 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-e7Jn-RGH.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js +41 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-B1G-uMf2.js.gz +0 -0
- package/dist/client/assets/{diagram-FQU43EPY-CA9ZCbUn.js → diagram-VSXAHHWV-cp7u53yF.js} +3 -3
- package/dist/client/assets/diagram-VSXAHHWV-cp7u53yF.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-cp7u53yF.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js +24 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-DJWrVfMd.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js +24 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-B-IZbqzJ.js.gz +0 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js +27 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js.br +0 -0
- package/dist/client/assets/diffWorker-CAzvFFr7.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-CCIWWBDH-C01FJ1W6.js → ebnfDiagram-PWID7BFC-Bt4zDbpn.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bt4zDbpn.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-Bt4zDbpn.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js +99 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-DUPOkndO.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js +168 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CBSvTIxa.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js +292 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-C7BvkSc8.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js +106 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C4v6Do2L.js.gz +0 -0
- package/dist/client/assets/index-BaBARzax.css +1 -0
- package/dist/client/assets/index-BaBARzax.css.br +0 -0
- package/dist/client/assets/index-BaBARzax.css.gz +0 -0
- package/dist/client/assets/{index-Ca-rq7yX.js → index-UqXCGE5m.js} +4 -4
- package/dist/client/assets/index-UqXCGE5m.js.br +0 -0
- package/dist/client/assets/index-UqXCGE5m.js.gz +0 -0
- package/dist/client/assets/infoDiagram-27XIBGKW-CVQtEdgb.js +2 -0
- package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-B_RdP3jn.js → ishikawaDiagram-5VMMS53U-Cf7tUoyW.js} +5 -5
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cf7tUoyW.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-Cf7tUoyW.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-5HDEW3XC-B2nObc7o.js → journeyDiagram-3NMN7TZE-B-9CWrlr.js} +5 -5
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B-9CWrlr.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-B-9CWrlr.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-HUTT4EX6-7b37SN5M.js → kanban-definition-UXKFOSKX-LDN2IZeo.js} +7 -7
- package/dist/client/assets/kanban-definition-UXKFOSKX-LDN2IZeo.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-LDN2IZeo.js.gz +0 -0
- package/dist/client/assets/katex-55ZPZeOF.css.br +0 -0
- package/dist/client/assets/katex-55ZPZeOF.css.gz +0 -0
- package/dist/client/assets/katex-DnlPpQZa.js.br +0 -0
- package/dist/client/assets/katex-DnlPpQZa.js.gz +0 -0
- package/dist/client/assets/katex-HP8lGamR.js.br +0 -0
- package/dist/client/assets/katex-HP8lGamR.js.gz +0 -0
- package/dist/client/assets/layout-DvqSuFgF.js +1 -0
- package/dist/client/assets/layout-DvqSuFgF.js.br +0 -0
- package/dist/client/assets/layout-DvqSuFgF.js.gz +0 -0
- package/dist/client/assets/{linear-6VNI0WmU.js → linear-D43LQnis.js} +1 -1
- package/dist/client/assets/linear-D43LQnis.js.br +0 -0
- package/dist/client/assets/linear-D43LQnis.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js +308 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js.br +0 -0
- package/dist/client/assets/mermaid.core-DiblHLKe.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-LN4V7U3C-DjuOw0RL.js → mindmap-definition-YA3MSWOX-k3f4uWuu.js} +3 -3
- package/dist/client/assets/mindmap-definition-YA3MSWOX-k3f4uWuu.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-k3f4uWuu.js.gz +0 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js.br +0 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-2B236MQR-CflwKQn8.js → pegDiagram-XKGWAZYB-Dj32Fl3j.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dj32Fl3j.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-Dj32Fl3j.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js +39 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-DWGSixfl.js.gz +0 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js +3 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js.br +0 -0
- package/dist/client/assets/purify.es-4eNOHKSq.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-XlkePQlX.js → quadrantDiagram-AXDQQJYC-BPScfZWR.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPScfZWR.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-BPScfZWR.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js +1 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-CL00HIC2.js.gz +0 -0
- package/dist/client/assets/react-XDCjal2T.js.br +0 -0
- package/dist/client/assets/react-XDCjal2T.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-TGXJPOKE-DQzmk2Py.js → requirementDiagram-BXWQKSXE-CosES4L6.js} +12 -12
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CosES4L6.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CosES4L6.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js +40 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-CjM8CYFn.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-COlWE5v4.js → sequenceDiagram-WJ2MYXX4-3RKv_35o.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-3RKv_35o.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-3RKv_35o.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-BAyWY8FR.js → sizeCapture-INFHLROL-BrVkA4VD.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-BrVkA4VD.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-BrVkA4VD.js.gz +0 -0
- package/dist/client/assets/sparkles-B3pwUd8-.js +1 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js +1 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DeWhyAVC.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DvdrGmTm.js +1 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js +1 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js.br +0 -0
- package/dist/client/assets/swimlanes-42K2YHIH-i2m0Wmhn.js.gz +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DIzij9pB.js +8 -0
- package/dist/client/assets/terminal-C7X98Amf.js.br +0 -0
- package/dist/client/assets/terminal-C7X98Amf.js.gz +0 -0
- package/dist/client/assets/{timeline-definition-FHXFAJF6-CBpp3qTq.js → timeline-definition-24CTP7MA-BImN0AS_.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-BImN0AS_.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BImN0AS_.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js +34 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DVUHKmvC.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-EHGQE667-BgYh502A.js → wardleyDiagram-VM6X3IG4-B9qi-hc7.js} +4 -4
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B9qi-hc7.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-B9qi-hc7.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js +7 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-3jgBcYVl.js.gz +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-38-022d7c89c800.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-39-63f8fa5b3eba.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3a-2d8d46cc4dca.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3b-e75aed5d3969.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c-ac2534aae681.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c0-8c49a98e75c4.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c1-971c5e7a86ce.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c2-e5c4893acfb9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c3-156f2560c871.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c4-49f0d18a7492.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c5-33d81ad28c5c.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3c6-5c301879d053.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-icons-3d-52c90894de44.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Bold-text-9e8d9df2dd02.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-38-7942d3c93afb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-39-19989a2be535.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3a-7786ff4a4dd9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3b-a759fd623d7e.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c-2a1178076740.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c0-6f2c7518f354.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c1-4bf64cae9dd2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c2-7f26d4c7240b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c3-fc8e5a85d620.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c4-91819b7977d3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c5-26933eec54e2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3c6-af186404c8af.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-icons-3d-b004d85f5642.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-BoldItalic-text-da002b4e56d3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-38-b3e69191d92f.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-39-c4d8d66882cb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3a-27609324e8a3.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3b-5e73d85d7506.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c-7e535d65bbdb.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c0-6465060a06a1.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c1-9fd72ccd9350.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c2-ea7dd77de270.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c3-12808f88907a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c4-14b598e5e739.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c5-3d40530ce6c2.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3c6-7020aec0d9e1.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-icons-3d-19831897003a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Italic-text-b7a9c776b048.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-38-a637901140d8.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-39-838726e8eeca.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3a-ec149087d0b9.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3b-db8e5a24d580.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c-2290d2ad4621.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c0-3b9edaf85d65.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c1-5e7fb0696bbc.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c2-cfad2884adf5.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c3-d641de88278b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c4-3b0227356b3b.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c5-9dc67c4d20b4.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3c6-c5b444110c62.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-icons-3d-2b19b65bb43a.woff2 +0 -0
- package/dist/client/fonts/terminal/JetBrainsMonoNLNerdFontMono-Regular-text-d7b9316fdf4f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-4e-46bdca5c323f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-4f-17200dc0dd0d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-50-370e36250c30.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-51-66352f738581.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-52-191f4025d2b5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-53-fb0a637c39bf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-54-66f2e72c9ca0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-55-54b538fd4fd8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-56-88f45aeb2030.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-57-154d4324f0ce.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-58-1660c86b8a05.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-59-31a4c5afa3aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5a-fa1d1941710e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5b-031a2b2ebeb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5c-065b634c07b3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5d-71f6cd3ed180.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5e-f59de7a6e5c5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-5f-8cbe737b6011.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-60-22913526da09.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-61-c810c1d1a3a3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-62-9464d5d87d65.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-63-79564d99f5da.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-64-4b7cff1dae6f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-65-8dd48db5e297.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-66-a808e22a3d14.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-67-ae5f61af3f79.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-68-a46bf47bd9ba.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-69-28210414eafb.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6a-6bfb1f5e4fb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6b-39be890e04e4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6c-79a4ff740d98.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6d-2de5a763980e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6e-8e55b339244d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-6f-a56caf9fc7fc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-70-d70c6ee8e03c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-71-ac6f5f86dfef.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-72-db3d346ecc61.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-73-e7371bd71f0b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-74-43946d9b2f0b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-75-ea7cf53e31fa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-76-04c7fa4e0ebf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-77-24d70898f6b8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-78-c6a5d7135296.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-79-7812cb6432aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7a-6e123be5cd36.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7b-a183ddc6890f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7c-0895291ece9c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7d-1d44252384cf.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7e-7be4dc6f056e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-7f-0d8e987db151.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-80-c0c154bb8be0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-81-5343baca5ce7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-82-6d89af9614ce.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-83-fa17ef529c5b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-84-287ecb493fad.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-85-fea695c48165.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-86-8bb35373cb82.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-87-f83e9f70a6cc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-88-894cd19292c1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-89-2903a6eaf546.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8a-3ce275bfcf96.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8b-3aaeb26309a6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8c-719b6608b746.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8d-a7f1ccd0dfb7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8e-d503ad5c4958.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-8f-18c6d04746c8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-90-e9d94d915dfe.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-91-c258b07ec626.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-92-e4833a556b60.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-94-0889f5b84499.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-95-7ef116efe7ee.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-96-afbc0d2cacda.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-97-df3903d86f65.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-98-0f21094931ee.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-99-eb95f4bead58.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9a-764e8b8723ec.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9b-33a540b9196a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9c-60d6040aa049.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9e-4a64c65bf44d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-cjk-9f-4d84fba11345.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Bold-Subset-punctuation-f1b7708e797a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-4e-bb1ec5541ecc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-4f-d6e8daa67360.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-50-63c2ae7f85e8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-51-41b6e0624888.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-52-57de15003b8d.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-53-94382657e2bc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-54-177141086f32.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-55-5ec6fae9813a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-56-720aa493b429.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-57-a8884711a286.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-58-42a3e7e1fe9a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-59-887ee4253daa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5a-c45806889e3c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5b-da142b99dca9.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5c-2bb495e5b511.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5d-9da87d6061f2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5e-e4010764e593.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-5f-a9c9021f6e01.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-60-306f229a68e0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-61-6e4546c5f52a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-62-a73e47933059.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-63-e8f49f472799.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-64-37b54957eadc.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-65-2742b20127ad.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-66-239656e7fe56.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-67-5dfa72b26c3f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-68-fe3d1fc05aae.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-69-22535dbbd090.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6a-c4117cd520aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6b-895d3349f7de.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6c-56a0c71eb1b4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6d-9ec807661604.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6e-3b633363cd57.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-6f-91a1f1c31b75.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-70-3a904a2a2371.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-71-e8efb60879b0.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-72-591318b99498.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-73-d8f444050aa7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-74-55a832a12d7e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-75-660977996a4c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-76-441a04df9fb5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-77-5915143c4398.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-78-242fbc33c745.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-79-24d13953150a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7a-41973af74017.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7b-f9661fdaf003.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7c-ef5167770bf7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7d-d84ad5d95f37.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7e-66841a1c6381.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-7f-5090e017351a.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-80-9ad74a67c2b9.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-81-423a60a6dcf1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-82-aad812217807.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-83-3dc74dbac89c.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-84-68db7802ffe8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-85-fa235a7160e4.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-86-75a6a33d0db2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-87-7d98ea8ce063.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-88-363fa8f178aa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-89-f2d185e8721f.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8a-e372253a07f5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8b-0af53db9bdc1.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8c-6a43d3643480.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8d-09c4b5345b99.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8e-122a752954a6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-8f-c651bbfffeb3.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-90-ab0a5fef3083.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-91-e07b5cbe4792.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-92-cba0a8ee6758.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-94-e7a6bd14e248.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-95-420f721d52ba.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-96-90fd476b83f2.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-97-34036fc287f7.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-98-5c3cdd76911e.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-99-73e6090fd7c8.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9a-673ebaebe683.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9b-90a5a3ee22d6.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9c-116d201c978b.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9e-78db36865caa.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-cjk-9f-27e8d16243d5.woff2 +0 -0
- package/dist/client/fonts/terminal/NotoSansMonoCJKsc-Subset-punctuation-a4288065ed29.woff2 +0 -0
- package/dist/client/fonts/terminal/manifest.json +1349 -0
- package/dist/client/fonts/terminal/manifest.json.br +0 -0
- package/dist/client/fonts/terminal/manifest.json.gz +0 -0
- package/dist/client/icons/agents/claude.svg.br +0 -0
- package/dist/client/icons/agents/claude.svg.gz +0 -0
- package/dist/client/icons/agents/codex.svg.br +0 -0
- package/dist/client/icons/agents/codex.svg.gz +0 -0
- package/dist/client/icons/agents/copilot.svg.br +0 -0
- package/dist/client/icons/agents/copilot.svg.gz +0 -0
- package/dist/client/icons/agents/droid.svg.br +0 -0
- package/dist/client/icons/agents/droid.svg.gz +0 -0
- package/dist/client/icons/agents/gemini.svg.br +0 -0
- package/dist/client/icons/agents/gemini.svg.gz +0 -0
- package/dist/client/icons/agents/goose.svg.br +0 -0
- package/dist/client/icons/agents/goose.svg.gz +0 -0
- package/dist/client/index.html +7 -52
- package/dist/client/index.html.br +0 -0
- package/dist/client/index.html.gz +0 -0
- package/dist/client/sw-notifications.js.br +0 -0
- package/dist/client/sw-notifications.js.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/client/workbox-9845bf53.js.br +0 -0
- package/dist/client/workbox-9845bf53.js.gz +0 -0
- package/dist/server/agent/installers.js +47 -27
- package/dist/server/cli.js +4 -4
- package/dist/server/entry.js +57 -145
- package/dist/server/routes/auth.js +9 -3
- package/dist/server/routes/filesystem.js +39 -9
- package/dist/server/routes/local.js +3 -2
- package/dist/server/routes/terminal.js +337 -225
- package/dist/server/utils/apiAccess.js +27 -0
- package/dist/server/utils/apiCachePolicy.js +10 -0
- package/dist/server/utils/authProtection.js +140 -38
- package/dist/server/utils/cookieSecurity.js +3 -2
- package/dist/server/utils/csrfProtection.js +2 -6
- package/dist/server/utils/previewValidation.js +16 -0
- package/dist/server/utils/publicSecurity.js +44 -0
- package/dist/server/utils/requestDeadline.js +2 -0
- package/dist/server/utils/requestSecurity.js +23 -28
- package/dist/server/utils/staticAssets.js +97 -0
- package/dist/server/utils/terminalClientAttachment.js +61 -0
- package/dist/server/utils/terminalHandshakeDimensions.js +9 -0
- package/dist/server/utils/terminalOutputDelivery.js +90 -0
- package/dist/server/utils/tmuxClientRedraw.js +16 -0
- package/dist/server/utils/tmuxInitialScreen.js +50 -0
- package/dist/server/utils/tmuxResizeReady.js +56 -0
- package/dist/server/utils/webSocketSecurity.js +28 -0
- package/package.json +7 -4
- package/runtime-manifest.json +4 -4
- package/scripts/generate-font-subsets.py +88 -0
- package/scripts/precompress-client.mjs +28 -0
- package/dist/client/assets/ModelPreview-BzNON-7A.js +0 -4108
- package/dist/client/assets/app-qUUCmslY.js +0 -632
- package/dist/client/assets/arc-Cc4T1vtw.js +0 -1
- package/dist/client/assets/architectureDiagram-ZJ3FMSHR-CA5578rJ.js +0 -36
- package/dist/client/assets/blockDiagram-677ZJIJ3-CCyKnFX-.js +0 -132
- package/dist/client/assets/c4Diagram-LMCZKHZV-SjGfmHL4.js +0 -10
- package/dist/client/assets/channel-DsQFJkms.js +0 -1
- package/dist/client/assets/chunk-32BRIVSS-CF9O6bVF.js +0 -1
- package/dist/client/assets/chunk-RYQCIY6F-DaVQTtgL.js +0 -1
- package/dist/client/assets/chunk-VR4S4FIN-DEcVDuQJ.js +0 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-BiBG6J-j.js +0 -1
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-BiBG6J-j.js +0 -1
- package/dist/client/assets/cynefinDiagram-TSTJHNR4-DGjbhF2-.js +0 -62
- package/dist/client/assets/dagre-VKFMJZFB-CoLOphm4.js +0 -4
- package/dist/client/assets/diagram-G47NLZAW-BpR2yCdT.js +0 -24
- package/dist/client/assets/diagram-NH7WQ7WH-DIZpypfO.js +0 -24
- package/dist/client/assets/diagram-OA4YK3LP-S9oRNVSL.js +0 -30
- package/dist/client/assets/diagram-WEI45ONY-Dv-XqhXv.js +0 -41
- package/dist/client/assets/diffWorker-Bg2YXCD-.js +0 -27
- package/dist/client/assets/erDiagram-Q63AITRT-CMDd2A57.js +0 -85
- package/dist/client/assets/flowDiagram-23GEKE2U-Bu5kfa1t.js +0 -156
- package/dist/client/assets/ganttDiagram-NO4QXBWP-tfVpOhLu.js +0 -292
- package/dist/client/assets/gitGraphDiagram-IHSO6WYX-CWM8oPLo.js +0 -106
- package/dist/client/assets/graph-D2o_JWn5.js +0 -1
- package/dist/client/assets/index-C13NrW5y.css +0 -1
- package/dist/client/assets/infoDiagram-FWYZ7A6U-CYuG0BfG.js +0 -2
- package/dist/client/assets/layout-1eBIAoSl.js +0 -1
- package/dist/client/assets/map-BdqsVdb3.js +0 -1
- package/dist/client/assets/mermaid.core-BMGv3SNm.js +0 -306
- package/dist/client/assets/pieDiagram-ENE6RG2P-Dp5j3kXt.js +0 -39
- package/dist/client/assets/purify.es-CC4Brkr_.js +0 -3
- package/dist/client/assets/railroadDiagram-RFXS5EU6-Dzq5SEwb.js +0 -1
- package/dist/client/assets/sankeyDiagram-HTMAVEWB-Yuu-Dn7F.js +0 -40
- package/dist/client/assets/stateDiagram-2N3HPSRC-DE_g6UKp.js +0 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-CuFHnjvX.js +0 -1
- package/dist/client/assets/swimlanes-5IMT3BWC-SdPYQWPe.js +0 -2
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-f7M07VuB.js +0 -8
- package/dist/client/assets/vennDiagram-L72KCM5P-Cfm5mfc0.js +0 -34
- package/dist/client/assets/xychartDiagram-FW5EYKEG-mAm5oI6Y.js +0 -7
- package/dist/client/registerSW.js +0 -1
package/dist/server/entry.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { apiAccessGate, isTrustedLocalRequest } from './utils/apiAccess.js';
|
|
2
|
+
import { assertPublicSecurity, securityHeaders } from './utils/publicSecurity.js';
|
|
3
|
+
import { guardWebSocketSession } from './utils/webSocketSecurity.js';
|
|
4
|
+
import { readTerminalHandshakeDimensions } from './utils/terminalHandshakeDimensions.js';
|
|
5
|
+
import { apiCachePolicy } from './utils/apiCachePolicy.js';
|
|
1
6
|
import 'dotenv/config';
|
|
2
7
|
import express from 'express';
|
|
3
8
|
import { createServer as createHttpServer } from 'http';
|
|
@@ -5,7 +10,7 @@ import { createServer as createHttpsServer } from 'https';
|
|
|
5
10
|
import crypto from 'crypto';
|
|
6
11
|
import fs from 'fs';
|
|
7
12
|
import path from 'path';
|
|
8
|
-
import
|
|
13
|
+
import { createStaticCompressionMiddleware, setStaticCacheHeaders } from './utils/staticAssets.js';
|
|
9
14
|
import { homedir } from 'os';
|
|
10
15
|
import cookieParser from 'cookie-parser';
|
|
11
16
|
import { fileURLToPath } from 'url';
|
|
@@ -18,9 +23,9 @@ import { createOnboardingRouter } from './routes/onboarding.js';
|
|
|
18
23
|
import { createLocalRouter } from './routes/local.js';
|
|
19
24
|
import { csrfProtection } from './utils/csrfProtection.js';
|
|
20
25
|
import { pathValidator } from './utils/pathValidator.js';
|
|
21
|
-
import { isUpgradeRequestAuthenticated, requireAuth } from './utils/authProtection.js';
|
|
26
|
+
import { isUpgradeRequestAuthenticated, requireAuth, renewSessionMiddleware } from './utils/authProtection.js';
|
|
22
27
|
import { localAccessManager } from './utils/localAccess.js';
|
|
23
|
-
import { isAllowedHost, isUpgradeOriginAllowed, validateHostMiddleware, } from './utils/requestSecurity.js';
|
|
28
|
+
import { isAllowedHost, isUpgradeOriginAllowed, validateHostMiddleware, validateOriginMiddleware, } from './utils/requestSecurity.js';
|
|
24
29
|
import { getCookieSecurityOptions, setSecureCookieMode } from './utils/cookieSecurity.js';
|
|
25
30
|
import { requestDeadlineMiddleware } from './utils/requestDeadline.js';
|
|
26
31
|
import { RuntimeMonitor } from './utils/runtimeMonitor.js';
|
|
@@ -135,128 +140,19 @@ function getDiffTraceEvent(message) {
|
|
|
135
140
|
return message;
|
|
136
141
|
return message.slice(spaceIndex + 1);
|
|
137
142
|
}
|
|
138
|
-
// 静态资源压缩中间件(零依赖,用 Node 内置 zlib)。
|
|
139
|
-
// 动机:跨城/弱网首刷(或 PWA SW 更新后)要下载未压缩的 JS/CSS bundle,
|
|
140
|
-
// express.static 默认不压缩。这里对文本类资源做 br/gzip 压缩,跨城下能把
|
|
141
|
-
// bundle 下载体积砍到 ~1/4,明显缩短首屏等待。
|
|
142
|
-
// 设计要点:
|
|
143
|
-
// - 只压文本类扩展名;图片/字体/woff2 等已是压缩格式,跳过避免做无用功。
|
|
144
|
-
// - 编译产物在运行期不变,按 (绝对路径 + mtimeMs + 编码) 缓存压缩结果到内存,
|
|
145
|
-
// 只在第一次请求时压一次,后续直接命中,不占 CPU。
|
|
146
|
-
// - 路径必须落在 dist 目录内且文件真实存在,否则交回后续中间件(含 SPA
|
|
147
|
-
// fallback),不影响 index.html 路由与 /api 等。
|
|
148
|
-
const COMPRESSIBLE_EXT = new Set(['.js', '.mjs', '.css', '.html', '.json', '.svg', '.webmanifest', '.map', '.txt']);
|
|
149
|
-
// 扩展名 → Content-Type。自己维护一张小表,不依赖 express.static.mime
|
|
150
|
-
// (express 5 运行期不暴露该字段,访问会抛 TypeError)。
|
|
151
|
-
const CONTENT_TYPE_BY_EXT = {
|
|
152
|
-
'.js': 'text/javascript; charset=utf-8',
|
|
153
|
-
'.mjs': 'text/javascript; charset=utf-8',
|
|
154
|
-
'.css': 'text/css; charset=utf-8',
|
|
155
|
-
'.html': 'text/html; charset=utf-8',
|
|
156
|
-
'.json': 'application/json; charset=utf-8',
|
|
157
|
-
'.svg': 'image/svg+xml',
|
|
158
|
-
'.webmanifest': 'application/manifest+json; charset=utf-8',
|
|
159
|
-
'.map': 'application/json; charset=utf-8',
|
|
160
|
-
'.txt': 'text/plain; charset=utf-8',
|
|
161
|
-
};
|
|
162
|
-
function setStaticCacheHeaders(req, res) {
|
|
163
|
-
let pathname;
|
|
164
|
-
try {
|
|
165
|
-
pathname = decodeURIComponent(new URL(req.url, 'http://localhost').pathname);
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
pathname = req.path || req.url || '';
|
|
169
|
-
}
|
|
170
|
-
if (pathname === '/'
|
|
171
|
-
|| pathname.endsWith('/index.html')
|
|
172
|
-
|| pathname === '/sw.js'
|
|
173
|
-
|| pathname === '/registerSW.js'
|
|
174
|
-
|| pathname === '/manifest.webmanifest') {
|
|
175
|
-
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
176
|
-
res.setHeader('Pragma', 'no-cache');
|
|
177
|
-
res.setHeader('Expires', '0');
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
if (pathname.startsWith('/assets/')) {
|
|
181
|
-
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
function createStaticCompressionMiddleware(rootDir) {
|
|
185
|
-
const resolvedRoot = path.resolve(rootDir);
|
|
186
|
-
const cache = new Map();
|
|
187
|
-
return (req, res, next) => {
|
|
188
|
-
if (req.method !== 'GET' && req.method !== 'HEAD')
|
|
189
|
-
return next();
|
|
190
|
-
const acceptEncoding = String(req.headers['accept-encoding'] || '');
|
|
191
|
-
const useBr = /\bbr\b/.test(acceptEncoding);
|
|
192
|
-
const useGzip = /\bgzip\b/.test(acceptEncoding);
|
|
193
|
-
if (!useBr && !useGzip)
|
|
194
|
-
return next();
|
|
195
|
-
// 解析并防目录穿越:只服务 dist 内的文件。
|
|
196
|
-
let pathname;
|
|
197
|
-
try {
|
|
198
|
-
pathname = decodeURIComponent(new URL(req.url, 'http://localhost').pathname);
|
|
199
|
-
}
|
|
200
|
-
catch {
|
|
201
|
-
return next();
|
|
202
|
-
}
|
|
203
|
-
const ext = path.extname(pathname).toLowerCase();
|
|
204
|
-
if (!COMPRESSIBLE_EXT.has(ext))
|
|
205
|
-
return next();
|
|
206
|
-
const filePath = path.resolve(resolvedRoot, '.' + pathname);
|
|
207
|
-
if (filePath !== resolvedRoot && !filePath.startsWith(resolvedRoot + path.sep))
|
|
208
|
-
return next();
|
|
209
|
-
let stat;
|
|
210
|
-
try {
|
|
211
|
-
stat = fs.statSync(filePath);
|
|
212
|
-
}
|
|
213
|
-
catch {
|
|
214
|
-
return next();
|
|
215
|
-
}
|
|
216
|
-
if (!stat.isFile())
|
|
217
|
-
return next();
|
|
218
|
-
const encoding = useBr ? 'br' : 'gzip';
|
|
219
|
-
const cacheKey = `${filePath}|${encoding}`;
|
|
220
|
-
let entry = cache.get(cacheKey);
|
|
221
|
-
if (!entry || entry.mtimeMs !== stat.mtimeMs) {
|
|
222
|
-
let raw;
|
|
223
|
-
try {
|
|
224
|
-
raw = fs.readFileSync(filePath);
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
return next();
|
|
228
|
-
}
|
|
229
|
-
const body = encoding === 'br'
|
|
230
|
-
? zlib.brotliCompressSync(raw, {
|
|
231
|
-
params: {
|
|
232
|
-
[zlib.constants.BROTLI_PARAM_QUALITY]: 9,
|
|
233
|
-
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: raw.length,
|
|
234
|
-
},
|
|
235
|
-
})
|
|
236
|
-
: zlib.gzipSync(raw, { level: 7 });
|
|
237
|
-
entry = { encoding, body, mtimeMs: stat.mtimeMs };
|
|
238
|
-
cache.set(cacheKey, entry);
|
|
239
|
-
}
|
|
240
|
-
res.setHeader('Content-Encoding', encoding);
|
|
241
|
-
res.setHeader('Vary', 'Accept-Encoding');
|
|
242
|
-
const type = CONTENT_TYPE_BY_EXT[ext];
|
|
243
|
-
if (type)
|
|
244
|
-
res.setHeader('Content-Type', type);
|
|
245
|
-
setStaticCacheHeaders(req, res);
|
|
246
|
-
res.setHeader('Content-Length', entry.body.length);
|
|
247
|
-
if (req.method === 'HEAD') {
|
|
248
|
-
res.end();
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
res.end(entry.body);
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
143
|
export function createApp(options = {}) {
|
|
144
|
+
assertPublicSecurity();
|
|
255
145
|
const app = express();
|
|
146
|
+
app.disable('x-powered-by');
|
|
147
|
+
app.use(securityHeaders);
|
|
256
148
|
app.use(validateHostMiddleware);
|
|
149
|
+
// Authenticate before allocating request bodies, including future API routes.
|
|
150
|
+
app.use(cookieParser());
|
|
151
|
+
app.use('/api', renewSessionMiddleware);
|
|
152
|
+
app.use('/api', apiAccessGate(options.localApiToken));
|
|
257
153
|
// 基础中间件
|
|
154
|
+
app.use('/api/auth', express.json({ limit: '2kb' }));
|
|
258
155
|
app.use(express.json({ limit: '5mb' }));
|
|
259
|
-
app.use(cookieParser());
|
|
260
156
|
// Note: clientId cookie is no longer used for session persistence (sessions are global).
|
|
261
157
|
// Kept for potential future use and backward compatibility.
|
|
262
158
|
app.use((req, res, next) => {
|
|
@@ -284,6 +180,7 @@ export function createApp(options = {}) {
|
|
|
284
180
|
return req.path || req.url || '';
|
|
285
181
|
}
|
|
286
182
|
})();
|
|
183
|
+
const logPathname = pathname.replace(/(\/fs\/preview\/)[0-9a-f]{32}(?=\/)/gi, '$1[redacted]');
|
|
287
184
|
const routeFamily = getRouteFamily(pathname);
|
|
288
185
|
let logged = false;
|
|
289
186
|
const log = (event) => {
|
|
@@ -295,7 +192,7 @@ export function createApp(options = {}) {
|
|
|
295
192
|
writeJsonLog('access.log', {
|
|
296
193
|
event,
|
|
297
194
|
method: req.method,
|
|
298
|
-
path:
|
|
195
|
+
path: logPathname,
|
|
299
196
|
routeFamily,
|
|
300
197
|
statusCode: res.statusCode,
|
|
301
198
|
durationMs: Math.round(durationMs * 100) / 100,
|
|
@@ -308,7 +205,7 @@ export function createApp(options = {}) {
|
|
|
308
205
|
source: 'access',
|
|
309
206
|
event,
|
|
310
207
|
method: req.method,
|
|
311
|
-
path:
|
|
208
|
+
path: logPathname,
|
|
312
209
|
routeFamily,
|
|
313
210
|
statusCode: res.statusCode,
|
|
314
211
|
durationMs: Math.round(durationMs * 100) / 100,
|
|
@@ -327,19 +224,7 @@ export function createApp(options = {}) {
|
|
|
327
224
|
// 全局请求兜底超时:任何 handler 挂起最多活 30s(长连接流按表豁免),
|
|
328
225
|
// 到期销毁 socket 释放浏览器连接槽。必须在所有路由与静态资源之前挂载。
|
|
329
226
|
app.use(requestDeadlineMiddleware());
|
|
330
|
-
app.use('/api',
|
|
331
|
-
// JSON/API responses must never hit browser conditional caching. A 304 with
|
|
332
|
-
// an empty body breaks fetch().json() callers and looks like random IO
|
|
333
|
-
// failures in the sidebar. The KiCad preview endpoint is a binary response,
|
|
334
|
-
// so it deliberately keeps validators to avoid retransferring multi-MB GLBs.
|
|
335
|
-
const conditionalBinaryPreview = req.path === '/terminal/fs/eda-preview';
|
|
336
|
-
if (!conditionalBinaryPreview) {
|
|
337
|
-
delete req.headers['if-none-match'];
|
|
338
|
-
delete req.headers['if-modified-since'];
|
|
339
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
340
|
-
}
|
|
341
|
-
next();
|
|
342
|
-
});
|
|
227
|
+
app.use('/api', apiCachePolicy);
|
|
343
228
|
// 安全中间件:CSRF令牌生成(在所有路由之前)
|
|
344
229
|
app.use(csrfProtection.tokenMiddleware());
|
|
345
230
|
// 健康检查端点(不需要CSRF保护,也不需要登录)
|
|
@@ -368,7 +253,7 @@ export function createApp(options = {}) {
|
|
|
368
253
|
});
|
|
369
254
|
// Client-side log relay — enables collecting browser/device logs
|
|
370
255
|
// on the server, critical for debugging mobile Safari / PWA issues.
|
|
371
|
-
app.post('/api/client-log', (req, res) => {
|
|
256
|
+
app.post('/api/client-log', requireAuth(), validateOriginMiddleware, (req, res) => {
|
|
372
257
|
const { level, message, data } = req.body ?? {};
|
|
373
258
|
if (!shouldWriteClientLog(level, message)) {
|
|
374
259
|
res.json({ ok: true, suppressed: true });
|
|
@@ -423,12 +308,7 @@ export function createApp(options = {}) {
|
|
|
423
308
|
// A locally installed Agent/plugin CLI uses the mode-0600 local API token.
|
|
424
309
|
// Keep this bypass loopback-only: possession of the token must not turn the
|
|
425
310
|
// LAN-facing terminal API into a bearer-token endpoint.
|
|
426
|
-
const isTrustedLocalCliRequest = (req) =>
|
|
427
|
-
if (!options.localApiToken || req.header('X-Termdock-Local-Token') !== options.localApiToken)
|
|
428
|
-
return false;
|
|
429
|
-
const address = req.socket.remoteAddress ?? '';
|
|
430
|
-
return address === '127.0.0.1' || address === '::1' || address === '::ffff:127.0.0.1';
|
|
431
|
-
};
|
|
311
|
+
const isTrustedLocalCliRequest = (req) => isTrustedLocalRequest(req, options.localApiToken);
|
|
432
312
|
app.get('/api/diagnostics/runtime', requireAuth({ bypass: isTrustedLocalCliRequest }), async (_req, res) => {
|
|
433
313
|
if (!options.runtimeMonitor) {
|
|
434
314
|
res.status(503).json({ error: 'Runtime monitor is not active', code: 'RUNTIME_MONITOR_INACTIVE' });
|
|
@@ -441,7 +321,7 @@ export function createApp(options = {}) {
|
|
|
441
321
|
// session cookie, then get redirected to a short-lived URL token so the
|
|
442
322
|
// sandboxed iframe's subresource requests (which browsers refuse to send
|
|
443
323
|
// cookies for) can still load images/css/js.
|
|
444
|
-
app.use('/api/terminal', requireAuth({ bypass: (req) => req.path
|
|
324
|
+
app.use('/api/terminal', requireAuth({ bypass: (req) => /^\/fs\/preview\//i.test(req.path) || isTrustedLocalCliRequest(req) }));
|
|
445
325
|
app.use('/api/terminal', csrfProtection.verifyMiddleware({ bypass: isTrustedLocalCliRequest }));
|
|
446
326
|
// 终端路由
|
|
447
327
|
app.use('/api/terminal', terminalRoutes);
|
|
@@ -472,6 +352,14 @@ export function createApp(options = {}) {
|
|
|
472
352
|
res.sendFile(path.join(clientPath, 'index.html'));
|
|
473
353
|
});
|
|
474
354
|
}
|
|
355
|
+
// Never expose parser errors, submitted passwords, or stack traces to callers.
|
|
356
|
+
app.use((error, _req, res, next) => {
|
|
357
|
+
if (res.headersSent)
|
|
358
|
+
return next(error);
|
|
359
|
+
const candidate = error?.status;
|
|
360
|
+
const status = typeof candidate === 'number' && candidate >= 400 && candidate <= 599 ? candidate : 500;
|
|
361
|
+
res.status(status).json({ error: status === 413 ? 'Request body too large' : status < 500 ? 'Invalid request' : 'Internal server error', code: 'REQUEST_ERROR' });
|
|
362
|
+
});
|
|
475
363
|
return app;
|
|
476
364
|
}
|
|
477
365
|
function createServerForApp(app, options) {
|
|
@@ -492,9 +380,13 @@ function reloadHttpsCertificate(server, options) {
|
|
|
492
380
|
return true;
|
|
493
381
|
}
|
|
494
382
|
export function startServer(options = {}) {
|
|
383
|
+
assertPublicSecurity();
|
|
495
384
|
const stopLogMaintenance = startTermdockLogMaintenance();
|
|
496
385
|
const port = options.port ?? Number(process.env.PORT || DEFAULT_PORT);
|
|
497
386
|
const host = options.host ?? (process.env.HOST || DEFAULT_HOST);
|
|
387
|
+
if (process.env.TERMDOCK_PUBLIC_ORIGIN && !(options.httpsCertPath && options.httpsKeyPath) && !['127.0.0.1', '::1', 'localhost'].includes(host)) {
|
|
388
|
+
throw new Error('Public access requires HTTPS certificates, or a loopback-only listener behind a TLS proxy.');
|
|
389
|
+
}
|
|
498
390
|
const runtimeMonitor = new RuntimeMonitor({
|
|
499
391
|
stateDirectory: path.join(homedir(), '.termdock'),
|
|
500
392
|
historyPath: path.join(homedir(), '.termdock', 'runtime-metrics.log'),
|
|
@@ -507,6 +399,12 @@ export function startServer(options = {}) {
|
|
|
507
399
|
runtimeMonitor,
|
|
508
400
|
});
|
|
509
401
|
const { server, scheme } = createServerForApp(app, options);
|
|
402
|
+
server.headersTimeout = 10_000;
|
|
403
|
+
server.requestTimeout = 120_000;
|
|
404
|
+
server.keepAliveTimeout = 5_000;
|
|
405
|
+
server.maxHeadersCount = 64;
|
|
406
|
+
server.maxRequestsPerSocket = 1000;
|
|
407
|
+
server.maxConnections = 1024;
|
|
510
408
|
server.on('connection', (socket) => runtimeMonitor.trackSocket(socket));
|
|
511
409
|
server.once('close', () => runtimeMonitor.stop());
|
|
512
410
|
setSecureCookieMode(scheme === 'https');
|
|
@@ -557,6 +455,7 @@ export function startServer(options = {}) {
|
|
|
557
455
|
// - serverNoContextTakeover:每条消息独立压缩上下文,降低长连接常驻内存。
|
|
558
456
|
const wss = new WebSocketServer({
|
|
559
457
|
noServer: true,
|
|
458
|
+
maxPayload: 1024 * 1024,
|
|
560
459
|
perMessageDeflate: {
|
|
561
460
|
threshold: 1024,
|
|
562
461
|
concurrencyLimit: 10,
|
|
@@ -568,12 +467,23 @@ export function startServer(options = {}) {
|
|
|
568
467
|
const WS_PATH_RE = /^\/api\/terminal\/([^/]+)\/ws$/;
|
|
569
468
|
const CONTROL_WS_PATH = '/api/control/ws';
|
|
570
469
|
server.on('upgrade', (request, socket, head) => {
|
|
470
|
+
if (wss.clients.size >= 256) {
|
|
471
|
+
socket.end('HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
571
474
|
if (!isAllowedHost(request.headers.host) || !isUpgradeOriginAllowed(request.headers.origin, request.headers.host)) {
|
|
572
475
|
socket.write('HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n');
|
|
573
476
|
socket.destroy();
|
|
574
477
|
return;
|
|
575
478
|
}
|
|
576
|
-
|
|
479
|
+
let url;
|
|
480
|
+
try {
|
|
481
|
+
url = new URL(request.url ?? '/', `${scheme}://${request.headers.host ?? 'localhost'}`);
|
|
482
|
+
}
|
|
483
|
+
catch {
|
|
484
|
+
socket.destroy();
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
577
487
|
const pathname = url.pathname;
|
|
578
488
|
// Reject the upgrade before the WebSocket handshake completes if auth
|
|
579
489
|
// is enabled and the client cookie is missing/expired. We respond with
|
|
@@ -590,6 +500,7 @@ export function startServer(options = {}) {
|
|
|
590
500
|
const clientId = crypto.randomUUID();
|
|
591
501
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
592
502
|
handleControlWebSocket(ws, clientId);
|
|
503
|
+
guardWebSocketSession(ws, cookieHeader);
|
|
593
504
|
});
|
|
594
505
|
return;
|
|
595
506
|
}
|
|
@@ -606,7 +517,8 @@ export function startServer(options = {}) {
|
|
|
606
517
|
const sinceParam = url.searchParams.get('since');
|
|
607
518
|
const sinceSeq = sinceParam ? Math.max(0, Number.parseInt(sinceParam, 10) || 0) : 0;
|
|
608
519
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
609
|
-
handleTerminalWebSocket(ws, sessionId, clientId, { sinceSeq, pushClientId });
|
|
520
|
+
handleTerminalWebSocket(ws, sessionId, clientId, { sinceSeq, pushClientId, streamEpoch: url.searchParams.get('epoch') ?? undefined, flowControl: url.searchParams.get('flow') === '2', independentTmux: url.searchParams.get('transport') === 'tmux-client', outputActive: url.searchParams.get('active') !== '0' }, readTerminalHandshakeDimensions(url.searchParams));
|
|
521
|
+
guardWebSocketSession(ws, cookieHeader);
|
|
610
522
|
});
|
|
611
523
|
});
|
|
612
524
|
server.listen(port, host, () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import { AUTH_COOKIE, clearSessionCookie, createSession, destroySession, getClientIp, getLoginBlockMs, isAuthEnabled, isRequestAuthenticated, recordLoginFailure, recordLoginSuccess, setSessionCookie,
|
|
2
|
+
import { AUTH_COOKIE, clearSessionCookie, createSession, destroySession, getClientIp, getLoginBlockMs, isAuthEnabled, isRequestAuthenticated, recordLoginFailure, recordLoginSuccess, setSessionCookie, verifyPasswordAsync, } from '../utils/authProtection.js';
|
|
3
3
|
import { validateOriginMiddleware } from '../utils/requestSecurity.js';
|
|
4
4
|
const router = express.Router();
|
|
5
5
|
// GET /api/auth/status — public; tells the client whether auth is enabled
|
|
@@ -12,7 +12,7 @@ router.get('/status', (req, res) => {
|
|
|
12
12
|
});
|
|
13
13
|
// POST /api/auth/login — public; verifies password, issues session cookie.
|
|
14
14
|
// Rate-limited per source IP via exponential backoff.
|
|
15
|
-
router.post('/login', validateOriginMiddleware, (req, res) => {
|
|
15
|
+
router.post('/login', validateOriginMiddleware, async (req, res) => {
|
|
16
16
|
if (!isAuthEnabled()) {
|
|
17
17
|
return res.status(400).json({ error: 'Authentication is not enabled', code: 'AUTH_DISABLED' });
|
|
18
18
|
}
|
|
@@ -27,12 +27,18 @@ router.post('/login', validateOriginMiddleware, (req, res) => {
|
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
const password = typeof req.body?.password === 'string' ? req.body.password : '';
|
|
30
|
-
|
|
30
|
+
const verified = await verifyPasswordAsync(password);
|
|
31
|
+
if (verified === null) {
|
|
32
|
+
res.setHeader('Retry-After', '60');
|
|
33
|
+
return res.status(429).json({ error: 'Login capacity exceeded. Please retry later.', code: 'RATE_LIMITED', retryAfterMs: 60_000 });
|
|
34
|
+
}
|
|
35
|
+
if (!verified) {
|
|
31
36
|
recordLoginFailure(ip);
|
|
32
37
|
// Same generic message regardless of cause to avoid user-enumeration.
|
|
33
38
|
return res.status(401).json({ error: 'Invalid password', code: 'INVALID_PASSWORD' });
|
|
34
39
|
}
|
|
35
40
|
recordLoginSuccess(ip);
|
|
41
|
+
destroySession(req.cookies?.[AUTH_COOKIE]);
|
|
36
42
|
const session = createSession();
|
|
37
43
|
setSessionCookie(res, session.token);
|
|
38
44
|
res.json({ ok: true });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AUTH_COOKIE, isSessionValid } from '../utils/authProtection.js';
|
|
1
2
|
import { Router } from 'express';
|
|
2
3
|
import crypto from 'crypto';
|
|
3
4
|
import fs from 'fs';
|
|
@@ -5,6 +6,7 @@ import os from 'os';
|
|
|
5
6
|
import path from 'path';
|
|
6
7
|
import { execFile, spawn } from 'child_process';
|
|
7
8
|
import busboy from 'busboy';
|
|
9
|
+
import { validatePreview } from '../utils/previewValidation.js';
|
|
8
10
|
import { pathValidator } from '../utils/pathValidator.js';
|
|
9
11
|
import { isAuthEnabled, isRequestAuthenticated } from '../utils/authProtection.js';
|
|
10
12
|
import { getImageDimensions, parseImageDimensions } from '../utils/imageDimensions.js';
|
|
@@ -2957,6 +2959,8 @@ router.get('/read', async (req, res) => {
|
|
|
2957
2959
|
if (!stat.isFile()) {
|
|
2958
2960
|
throw new Error('Path is not a regular file');
|
|
2959
2961
|
}
|
|
2962
|
+
if (validatePreview(req, res, resolvedPath, stat, `text-v1-${MAX_FILE_SIZE}`))
|
|
2963
|
+
return null;
|
|
2960
2964
|
const bytesToRead = Math.min(stat.size, MAX_FILE_SIZE);
|
|
2961
2965
|
const truncated = stat.size > bytesToRead;
|
|
2962
2966
|
const buffer = await readBytesPrefix(resolvedPath, bytesToRead);
|
|
@@ -2967,6 +2971,10 @@ router.get('/read', async (req, res) => {
|
|
|
2967
2971
|
throwIfAborted(controller.signal, 'fs.read');
|
|
2968
2972
|
return { resolvedPath, stat, buffer, binary, truncated };
|
|
2969
2973
|
})(), FS_ROUTE_TIMEOUT_MS, 'File preview took too long. The file may be on slow storage or currently blocked by another process.', 'FS_READ_TIMEOUT');
|
|
2974
|
+
if (!result) {
|
|
2975
|
+
logFsIo({ id: requestId, action, op: 'fs.read', startedAt, status: 'ok', path: requestedPath, bytes: 0, extra: { cache: 'revalidated', requestSlotId } });
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2970
2978
|
logFsIo({ id: requestId, action, op: 'fs.read', startedAt, status: 'ok', path: result.resolvedPath, bytes: Math.min(result.stat.size, MAX_FILE_SIZE), total: result.stat.size, truncated: result.truncated, extra: { requestSlotId } });
|
|
2971
2979
|
res.json({
|
|
2972
2980
|
path: result.resolvedPath,
|
|
@@ -3122,6 +3130,7 @@ router.get('/eda-preview', async (req, res) => {
|
|
|
3122
3130
|
res.setHeader('Cache-Control', 'private, no-cache');
|
|
3123
3131
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
3124
3132
|
res.setHeader('X-Eda-View', requestedView);
|
|
3133
|
+
res.setHeader('X-Termdock-Source-Path', encodeURIComponent(resolvedPath));
|
|
3125
3134
|
if (requestAcceptsEtag(req.headers['if-none-match'], etag)) {
|
|
3126
3135
|
res.setHeader('X-Eda-Cache', 'revalidated');
|
|
3127
3136
|
res.status(304).end();
|
|
@@ -3297,6 +3306,10 @@ router.get('/blob', async (req, res) => {
|
|
|
3297
3306
|
}
|
|
3298
3307
|
return { resolvedPath, stat, mimeType };
|
|
3299
3308
|
})(), FS_ROUTE_TIMEOUT_MS, 'Image preview took too long. The file may be on slow storage or currently blocked by another process.', 'FS_BLOB_TIMEOUT');
|
|
3309
|
+
if (validatePreview(req, res, resolvedPath, stat, 'image-v1')) {
|
|
3310
|
+
logOnce('ok', { path: resolvedPath, bytes: 0, extra: { cache: 'revalidated' } });
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3300
3313
|
let responseBody = null;
|
|
3301
3314
|
let responseMimeType = mimeType;
|
|
3302
3315
|
let responseFilename = path.basename(resolvedPath);
|
|
@@ -3315,7 +3328,7 @@ router.get('/blob', async (req, res) => {
|
|
|
3315
3328
|
res.setHeader('Content-Type', responseMimeType);
|
|
3316
3329
|
res.setHeader('Content-Length', responseSize.toString());
|
|
3317
3330
|
res.setHeader('Last-Modified', stat.mtime.toUTCString());
|
|
3318
|
-
res.setHeader('Cache-Control', 'no-
|
|
3331
|
+
res.setHeader('Cache-Control', 'private, no-cache');
|
|
3319
3332
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
3320
3333
|
res.setHeader('Content-Disposition', buildContentDisposition('inline', responseFilename));
|
|
3321
3334
|
// Expose dimensions so markdown image previews can reserve the final
|
|
@@ -3517,29 +3530,29 @@ export function isPathWithinPreviewRoot(root, targetPath) {
|
|
|
3517
3530
|
const prefix = resolvedRoot.endsWith(path.sep) ? resolvedRoot : `${resolvedRoot}${path.sep}`;
|
|
3518
3531
|
return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(prefix);
|
|
3519
3532
|
}
|
|
3520
|
-
//
|
|
3521
|
-
// that keeps loading subresources stays usable without re-authenticating.
|
|
3533
|
+
// Absolute expiration and owner-session validation prevent indefinite bearer access.
|
|
3522
3534
|
export function validatePreviewToken(token, targetPath) {
|
|
3523
3535
|
const entry = previewTokens.get(token);
|
|
3524
3536
|
if (!entry)
|
|
3525
3537
|
return false;
|
|
3526
|
-
if (entry.expiresAt
|
|
3538
|
+
if (entry.expiresAt <= Date.now() || (entry.ownerSession ? !isSessionValid(entry.ownerSession) : isAuthEnabled())) {
|
|
3527
3539
|
previewTokens.delete(token);
|
|
3528
3540
|
return false;
|
|
3529
3541
|
}
|
|
3530
3542
|
if (!isPathWithinPreviewRoot(entry.root, targetPath))
|
|
3531
3543
|
return false;
|
|
3532
|
-
entry.expiresAt = Date.now() + PREVIEW_TOKEN_TTL_MS;
|
|
3533
3544
|
return true;
|
|
3534
3545
|
}
|
|
3535
|
-
export function mintPreviewToken(root) {
|
|
3546
|
+
export function mintPreviewToken(root, ownerSession) {
|
|
3536
3547
|
const now = Date.now();
|
|
3537
3548
|
for (const [token, entry] of previewTokens) {
|
|
3538
3549
|
if (entry.expiresAt < now)
|
|
3539
3550
|
previewTokens.delete(token);
|
|
3540
3551
|
}
|
|
3552
|
+
if (previewTokens.size >= 128)
|
|
3553
|
+
previewTokens.delete(previewTokens.keys().next().value);
|
|
3541
3554
|
const token = crypto.randomBytes(16).toString('hex');
|
|
3542
|
-
previewTokens.set(token, { root: path.resolve(root), expiresAt: now + PREVIEW_TOKEN_TTL_MS });
|
|
3555
|
+
previewTokens.set(token, { root: path.resolve(root), expiresAt: now + PREVIEW_TOKEN_TTL_MS, ownerSession });
|
|
3543
3556
|
return token;
|
|
3544
3557
|
}
|
|
3545
3558
|
function tokenizePreviewUrl(previewBaseUrl, token) {
|
|
@@ -3551,7 +3564,8 @@ function tokenizePreviewUrl(previewBaseUrl, token) {
|
|
|
3551
3564
|
export function injectHtmlPreviewBase(html, baseUrl) {
|
|
3552
3565
|
if (/<base\b/i.test(html))
|
|
3553
3566
|
return html;
|
|
3554
|
-
const
|
|
3567
|
+
const escapedBaseUrl = baseUrl.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
3568
|
+
const baseTag = `<base href="${escapedBaseUrl}">`;
|
|
3555
3569
|
const headMatch = html.match(/<head\b[^>]*>/i);
|
|
3556
3570
|
if (headMatch && typeof headMatch.index === 'number') {
|
|
3557
3571
|
const insertAt = headMatch.index + headMatch[0].length;
|
|
@@ -3606,7 +3620,18 @@ router.get('/preview/*path', async (req, res) => {
|
|
|
3606
3620
|
res.status(401).json({ error: 'Authentication required', code: 'AUTH_REQUIRED' });
|
|
3607
3621
|
return;
|
|
3608
3622
|
}
|
|
3623
|
+
if (maybeToken) {
|
|
3624
|
+
const entry = previewTokens.get(maybeToken);
|
|
3625
|
+
if (!entry || !validatePreviewToken(maybeToken, entry.root)) {
|
|
3626
|
+
res.status(403).json({ error: 'Preview token invalid or expired', code: 'PREVIEW_TOKEN_INVALID' });
|
|
3627
|
+
return;
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3609
3630
|
const validatedPath = await pathValidator.validatePathAsync(requestedPath);
|
|
3631
|
+
if (maybeToken && !validatePreviewToken(maybeToken, validatedPath)) {
|
|
3632
|
+
res.status(403).json({ error: 'Preview path outside token scope', code: 'PREVIEW_TOKEN_INVALID' });
|
|
3633
|
+
return;
|
|
3634
|
+
}
|
|
3610
3635
|
let stat = await fs.promises.stat(validatedPath);
|
|
3611
3636
|
let targetPath = validatedPath;
|
|
3612
3637
|
let redirectUrl = null;
|
|
@@ -3633,9 +3658,13 @@ router.get('/preview/*path', async (req, res) => {
|
|
|
3633
3658
|
// relative reference the document makes.
|
|
3634
3659
|
if (authEnabled && !maybeToken) {
|
|
3635
3660
|
const root = stat.isDirectory() ? validatedPath : path.dirname(validatedPath);
|
|
3636
|
-
const tokenized = tokenizePreviewUrl(previewBaseUrl, mintPreviewToken(root));
|
|
3661
|
+
const tokenized = tokenizePreviewUrl(previewBaseUrl, mintPreviewToken(root, req.cookies?.[AUTH_COOKIE]));
|
|
3637
3662
|
redirectUrl = stat.isDirectory() && !previewBaseUrl.endsWith('/') ? `${tokenized}/` : tokenized;
|
|
3638
3663
|
}
|
|
3664
|
+
if (maybeToken && !validatePreviewToken(maybeToken, targetPath)) {
|
|
3665
|
+
res.status(403).json({ error: 'Preview token invalid or expired', code: 'PREVIEW_TOKEN_INVALID' });
|
|
3666
|
+
return;
|
|
3667
|
+
}
|
|
3639
3668
|
if (redirectUrl) {
|
|
3640
3669
|
res.redirect(302, redirectUrl);
|
|
3641
3670
|
return;
|
|
@@ -3737,6 +3766,7 @@ router.get('/download', async (req, res) => {
|
|
|
3737
3766
|
res.setHeader('Cache-Control', 'no-store');
|
|
3738
3767
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
3739
3768
|
res.setHeader('Content-Disposition', buildContentDisposition('attachment', path.basename(resolvedPath)));
|
|
3769
|
+
res.setHeader('X-Termdock-Source-Path', encodeURIComponent(resolvedPath));
|
|
3740
3770
|
const stream = fs.createReadStream(resolvedPath);
|
|
3741
3771
|
stream.on('error', (error) => {
|
|
3742
3772
|
if (!res.headersSent) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { isTrustedLocalRequest } from '../utils/apiAccess.js';
|
|
1
2
|
import { Router } from 'express';
|
|
2
3
|
import { injectBranchAudit, injectChangeAudit } from '../utils/changeAuditStore.js';
|
|
3
4
|
export function createLocalRouter(options = {}) {
|
|
4
5
|
const router = Router();
|
|
5
6
|
router.post('/change-audit', (req, res) => {
|
|
6
|
-
if (!
|
|
7
|
+
if (!isTrustedLocalRequest(req, options.token)) {
|
|
7
8
|
res.status(401).json({ error: 'Unauthorized local request' });
|
|
8
9
|
return;
|
|
9
10
|
}
|
|
@@ -16,7 +17,7 @@ export function createLocalRouter(options = {}) {
|
|
|
16
17
|
res.json({ ok: true, inserted: result.inserted, total: result.total, walkthroughs: result.walkthroughs });
|
|
17
18
|
});
|
|
18
19
|
router.post('/branch-audit', (req, res) => {
|
|
19
|
-
if (!
|
|
20
|
+
if (!isTrustedLocalRequest(req, options.token)) {
|
|
20
21
|
res.status(401).json({ error: 'Unauthorized local request' });
|
|
21
22
|
return;
|
|
22
23
|
}
|