termdock 1.4.334 → 1.4.336
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-CA8oXFgS.js → App-B1lqBSPB.js} +16 -16
- package/dist/client/assets/App-B1lqBSPB.js.br +0 -0
- package/dist/client/assets/App-B1lqBSPB.js.gz +0 -0
- package/dist/client/assets/{ArchitecturePanel-BkB57agj.js → ArchitecturePanel-BOq2FG6t.js} +2 -2
- package/dist/client/assets/ArchitecturePanel-BOq2FG6t.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-BOq2FG6t.js.gz +0 -0
- package/dist/client/assets/{ChangeWalkthroughPanel-vh6Z641M.js → ChangeWalkthroughPanel-CxqwQxYc.js} +1 -1
- package/dist/client/assets/ChangeWalkthroughPanel-CxqwQxYc.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-CxqwQxYc.js.gz +0 -0
- package/dist/client/assets/{CollaborationMainWorkspace-dTXq04jE.js → CollaborationMainWorkspace-vvAVjIlQ.js} +1 -1
- package/dist/client/assets/CollaborationMainWorkspace-vvAVjIlQ.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-vvAVjIlQ.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-Bx6Z5gEL.js +2 -0
- package/dist/client/assets/{ComputerControlView-Cmar8PMd.js → ComputerControlView-mR6vlp9k.js} +3 -3
- package/dist/client/assets/ComputerControlView-mR6vlp9k.js.br +0 -0
- package/dist/client/assets/ComputerControlView-mR6vlp9k.js.gz +0 -0
- package/dist/client/assets/{DagPlayground-C-JZfG9-.js → DagPlayground-nUK9xIql.js} +1 -1
- package/dist/client/assets/DagPlayground-nUK9xIql.js.br +0 -0
- package/dist/client/assets/DagPlayground-nUK9xIql.js.gz +0 -0
- package/dist/client/assets/{DiffLab-rOEPk8iI.js → DiffLab-D6XhZtPW.js} +1 -1
- package/dist/client/assets/DiffLab-D6XhZtPW.js.br +0 -0
- package/dist/client/assets/DiffLab-D6XhZtPW.js.gz +0 -0
- package/dist/client/assets/{DiffReview-aIj4WHDS.js → DiffReview-BhyYqkD4.js} +1 -1
- package/dist/client/assets/DiffReview-BhyYqkD4.js.br +0 -0
- package/dist/client/assets/DiffReview-BhyYqkD4.js.gz +0 -0
- package/dist/client/assets/{DiffReviewLab-CU4vENL5.js → DiffReviewLab-CvNWVrbl.js} +1 -1
- package/dist/client/assets/DiffReviewLab-CvNWVrbl.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CvNWVrbl.js.gz +0 -0
- package/dist/client/assets/{DiffViewer-SKlbS7b4.js → DiffViewer-BSbMa2mq.js} +1 -1
- package/dist/client/assets/DiffViewer-BSbMa2mq.js.br +0 -0
- package/dist/client/assets/DiffViewer-BSbMa2mq.js.gz +0 -0
- package/dist/client/assets/{ModelPreview-mGhBeBla.js → ModelPreview-B_VPlNYr.js} +1 -1
- package/dist/client/assets/ModelPreview-B_VPlNYr.js.br +0 -0
- package/dist/client/assets/ModelPreview-B_VPlNYr.js.gz +0 -0
- package/dist/client/assets/{RightSidebar-BtHbt-XD.js → RightSidebar-Cakd9qUZ.js} +3 -3
- package/dist/client/assets/RightSidebar-Cakd9qUZ.js.br +0 -0
- package/dist/client/assets/RightSidebar-Cakd9qUZ.js.gz +0 -0
- package/dist/client/assets/{abnfDiagram-VCTEODGH-BazK9AUo.js → abnfDiagram-VCTEODGH-vWK7F-r_.js} +1 -1
- package/dist/client/assets/abnfDiagram-VCTEODGH-vWK7F-r_.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-vWK7F-r_.js.gz +0 -0
- package/dist/client/assets/{app-1SAb4dhI.js → app-BZBIr89q.js} +3 -3
- package/dist/client/assets/app-BZBIr89q.js.br +0 -0
- package/dist/client/assets/app-BZBIr89q.js.gz +0 -0
- package/dist/client/assets/{arc-DW2qA73J.js → arc-Bdjvby9b.js} +1 -1
- package/dist/client/assets/arc-Bdjvby9b.js.br +0 -0
- package/dist/client/assets/arc-Bdjvby9b.js.gz +0 -0
- package/dist/client/assets/{architectureDiagram-5GKGNRK7-CVkFu36h.js → architectureDiagram-5GKGNRK7-DTR5hJkG.js} +1 -1
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DTR5hJkG.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-DTR5hJkG.js.gz +0 -0
- package/dist/client/assets/{blockDiagram-I7D4REHJ-Cw0LbdUV.js → blockDiagram-I7D4REHJ-DPz3axsu.js} +1 -1
- package/dist/client/assets/blockDiagram-I7D4REHJ-DPz3axsu.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-DPz3axsu.js.gz +0 -0
- package/dist/client/assets/{c4Diagram-7LVT6UL2-D-7cVLVY.js → c4Diagram-7LVT6UL2-d5ZwPpcN.js} +1 -1
- package/dist/client/assets/c4Diagram-7LVT6UL2-d5ZwPpcN.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-d5ZwPpcN.js.gz +0 -0
- package/dist/client/assets/channel-M_h_h55d.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-DHms9xFG.js → chunk-2Q5K7J3B-BpEmNpto.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-DT9NVgVz.js → chunk-5VM5RSS4-CXDCiEbN.js} +1 -1
- package/dist/client/assets/{chunk-F27PBJKO-BPQlePZ0.js → chunk-F27PBJKO-C1L__gXc.js} +1 -1
- package/dist/client/assets/chunk-F27PBJKO-C1L__gXc.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-C1L__gXc.js.gz +0 -0
- package/dist/client/assets/{chunk-IMKFNOWR-CYpkOg4N.js → chunk-IMKFNOWR-CX0r7pV5.js} +1 -1
- package/dist/client/assets/chunk-IMKFNOWR-CX0r7pV5.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CX0r7pV5.js.gz +0 -0
- package/dist/client/assets/{chunk-JWPE2WC7-BetVwCtg.js → chunk-JWPE2WC7-DkbhnrKh.js} +1 -1
- package/dist/client/assets/{chunk-POPQ4Y6H-CHVqavTY.js → chunk-POPQ4Y6H-CH-o5PVe.js} +1 -1
- package/dist/client/assets/{chunk-SVP7TREG-TridS3zl.js → chunk-SVP7TREG-C1x5c5cy.js} +1 -1
- package/dist/client/assets/chunk-SVP7TREG-C1x5c5cy.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-C1x5c5cy.js.gz +0 -0
- package/dist/client/assets/{chunk-TICWLB2K-CrSU9J1Y.js → chunk-TICWLB2K-DAktkamN.js} +1 -1
- package/dist/client/assets/chunk-TICWLB2K-DAktkamN.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-DAktkamN.js.gz +0 -0
- package/dist/client/assets/{chunk-XXDRQBXY-DvrlcFpp.js → chunk-XXDRQBXY-emNetBN1.js} +1 -1
- package/dist/client/assets/classDiagram-ZZMXUADV-BVuw_2Ox.js +1 -0
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-BVuw_2Ox.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-BPspdiZq.js → cose-bilkent-JH36ORCC-kBGroiho.js} +1 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-kBGroiho.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-kBGroiho.js.gz +0 -0
- package/dist/client/assets/{cynefin-OW5HDTMX-CdZ2Ij-1.js → cynefin-OW5HDTMX-C0TjwB46.js} +1 -1
- package/dist/client/assets/cynefin-OW5HDTMX-C0TjwB46.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-C0TjwB46.js.gz +0 -0
- package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CS4dSANt.js → cynefinDiagram-5FMLGOSQ-CbLSUTuV.js} +1 -1
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CbLSUTuV.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CbLSUTuV.js.gz +0 -0
- package/dist/client/assets/{dagre-GXQ25YYZ-jz406NVd.js → dagre-GXQ25YYZ-BoznXKfa.js} +1 -1
- package/dist/client/assets/dagre-GXQ25YYZ-BoznXKfa.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-BoznXKfa.js.gz +0 -0
- package/dist/client/assets/{diagram-S7CK7UJ4-BXz7D6hW.js → diagram-S7CK7UJ4-iY9ia7F5.js} +1 -1
- package/dist/client/assets/diagram-S7CK7UJ4-iY9ia7F5.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-iY9ia7F5.js.gz +0 -0
- package/dist/client/assets/{diagram-UQ7AKVKN-BtSwQGmR.js → diagram-UQ7AKVKN-DhnC8gBw.js} +1 -1
- package/dist/client/assets/diagram-UQ7AKVKN-DhnC8gBw.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-DhnC8gBw.js.gz +0 -0
- package/dist/client/assets/{diagram-VSXAHHWV-B2lDfe93.js → diagram-VSXAHHWV-JFg8cbqX.js} +1 -1
- package/dist/client/assets/diagram-VSXAHHWV-JFg8cbqX.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-JFg8cbqX.js.gz +0 -0
- package/dist/client/assets/{diagram-VX7I27RA-QDrY0hNk.js → diagram-VX7I27RA-dvyXUTpo.js} +1 -1
- package/dist/client/assets/diagram-VX7I27RA-dvyXUTpo.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-dvyXUTpo.js.gz +0 -0
- package/dist/client/assets/{diagram-Z3DM3KII-D1AFu390.js → diagram-Z3DM3KII-DmjwsCUU.js} +1 -1
- package/dist/client/assets/diagram-Z3DM3KII-DmjwsCUU.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-DmjwsCUU.js.gz +0 -0
- package/dist/client/assets/{ebnfDiagram-PWID7BFC-L5aoZUCG.js → ebnfDiagram-PWID7BFC-BxCdDL0c.js} +1 -1
- package/dist/client/assets/ebnfDiagram-PWID7BFC-BxCdDL0c.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-BxCdDL0c.js.gz +0 -0
- package/dist/client/assets/{erDiagram-RLTQ6QDP-CFUfoWVL.js → erDiagram-RLTQ6QDP-BWvvnoz1.js} +1 -1
- package/dist/client/assets/erDiagram-RLTQ6QDP-BWvvnoz1.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-BWvvnoz1.js.gz +0 -0
- package/dist/client/assets/{flowDiagram-HODETNUW-A-hvg2q9.js → flowDiagram-HODETNUW-CVU0l_6c.js} +1 -1
- package/dist/client/assets/flowDiagram-HODETNUW-CVU0l_6c.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-CVU0l_6c.js.gz +0 -0
- package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DSMsjMS7.js → ganttDiagram-EL5Y4UJY-CjO521RP.js} +1 -1
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CjO521RP.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-CjO521RP.js.gz +0 -0
- package/dist/client/assets/{gestureArbiter-BvkspAa2.js → gestureArbiter-D_fs_PXp.js} +1 -1
- package/dist/client/assets/gestureArbiter-D_fs_PXp.js.br +0 -0
- package/dist/client/assets/gestureArbiter-D_fs_PXp.js.gz +0 -0
- package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-BhpWzivx.js → gitGraphDiagram-WWUBYQGX-DbxNhHiO.js} +1 -1
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DbxNhHiO.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DbxNhHiO.js.gz +0 -0
- package/dist/client/assets/{infoDiagram-27XIBGKW-a_A60wu0.js → infoDiagram-27XIBGKW-DRcGAFqT.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-5VMMS53U-zp9iSkhD.js → ishikawaDiagram-5VMMS53U-BPbgDJUg.js} +1 -1
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-BPbgDJUg.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-BPbgDJUg.js.gz +0 -0
- package/dist/client/assets/{journeyDiagram-3NMN7TZE-CWIWv2zw.js → journeyDiagram-3NMN7TZE-D1nSzyjD.js} +1 -1
- package/dist/client/assets/journeyDiagram-3NMN7TZE-D1nSzyjD.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-D1nSzyjD.js.gz +0 -0
- package/dist/client/assets/{kanban-definition-UXKFOSKX-JzGKFo57.js → kanban-definition-UXKFOSKX-CSCXZnir.js} +1 -1
- package/dist/client/assets/kanban-definition-UXKFOSKX-CSCXZnir.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-CSCXZnir.js.gz +0 -0
- package/dist/client/assets/{layout-7Cq6z6dO.js → layout-DTNe7C08.js} +1 -1
- package/dist/client/assets/layout-DTNe7C08.js.br +0 -0
- package/dist/client/assets/layout-DTNe7C08.js.gz +0 -0
- package/dist/client/assets/{linear-CuFZW946.js → linear-DELStaU_.js} +1 -1
- package/dist/client/assets/linear-DELStaU_.js.br +0 -0
- package/dist/client/assets/linear-DELStaU_.js.gz +0 -0
- package/dist/client/assets/{mermaid.core-DbR5q1bj.js → mermaid.core-D7uvx0E2.js} +5 -5
- package/dist/client/assets/mermaid.core-D7uvx0E2.js.br +0 -0
- package/dist/client/assets/mermaid.core-D7uvx0E2.js.gz +0 -0
- package/dist/client/assets/{mindmap-definition-YA3MSWOX-DdzejTGB.js → mindmap-definition-YA3MSWOX-C_fF6Gnh.js} +1 -1
- package/dist/client/assets/mindmap-definition-YA3MSWOX-C_fF6Gnh.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-C_fF6Gnh.js.gz +0 -0
- package/dist/client/assets/{passwordBootstrap-lisz9s1P.js → passwordBootstrap-Co17Xh3M.js} +1 -1
- package/dist/client/assets/passwordBootstrap-Co17Xh3M.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-Co17Xh3M.js.gz +0 -0
- package/dist/client/assets/{pegDiagram-XKGWAZYB-D720_LqX.js → pegDiagram-XKGWAZYB-BFOfbHg1.js} +1 -1
- package/dist/client/assets/pegDiagram-XKGWAZYB-BFOfbHg1.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-BFOfbHg1.js.gz +0 -0
- package/dist/client/assets/{pieDiagram-E7YTZNPT-zEDQIxrq.js → pieDiagram-E7YTZNPT-BkLXgY2Y.js} +1 -1
- package/dist/client/assets/pieDiagram-E7YTZNPT-BkLXgY2Y.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-BkLXgY2Y.js.gz +0 -0
- package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Cp0CVTM2.js → quadrantDiagram-AXDQQJYC-DIF7ynjD.js} +1 -1
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DIF7ynjD.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-DIF7ynjD.js.gz +0 -0
- package/dist/client/assets/{railroadDiagram-O6MQD6OU-DmEhvOdy.js → railroadDiagram-O6MQD6OU-DGeuv8o1.js} +1 -1
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DGeuv8o1.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DGeuv8o1.js.gz +0 -0
- package/dist/client/assets/{rdpSession-DQon3e98.js → rdpSession-DZCrSxpu.js} +1 -1
- package/dist/client/assets/rdpSession-DZCrSxpu.js.br +0 -0
- package/dist/client/assets/rdpSession-DZCrSxpu.js.gz +0 -0
- package/dist/client/assets/{referenceLongPress-DTjCnJH8.js → referenceLongPress-DrY73BHe.js} +1 -1
- package/dist/client/assets/referenceLongPress-DrY73BHe.js.br +0 -0
- package/dist/client/assets/referenceLongPress-DrY73BHe.js.gz +0 -0
- package/dist/client/assets/{requirementDiagram-BXWQKSXE-BnMPYUjE.js → requirementDiagram-BXWQKSXE-CoVdyMn3.js} +1 -1
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CoVdyMn3.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-CoVdyMn3.js.gz +0 -0
- package/dist/client/assets/{sankeyDiagram-P5KCCOFB-AvSI5iFI.js → sankeyDiagram-P5KCCOFB-BF-YvoEZ.js} +1 -1
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-BF-YvoEZ.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-BF-YvoEZ.js.gz +0 -0
- package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-DPXyiIKd.js → sequenceDiagram-WJ2MYXX4-CMkePZOj.js} +1 -1
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-CMkePZOj.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-CMkePZOj.js.gz +0 -0
- package/dist/client/assets/{sizeCapture-INFHLROL-CER_XOvb.js → sizeCapture-INFHLROL-C9N9vqvo.js} +1 -1
- package/dist/client/assets/sizeCapture-INFHLROL-C9N9vqvo.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-C9N9vqvo.js.gz +0 -0
- package/dist/client/assets/{sparkles-CgwSF-UK.js → sparkles-DQ-Y24Kv.js} +1 -1
- package/dist/client/assets/{stateDiagram-D77RDMKH-BdWVez-f.js → stateDiagram-D77RDMKH-DFk62G9u.js} +1 -1
- package/dist/client/assets/stateDiagram-D77RDMKH-DFk62G9u.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-DFk62G9u.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-Bnyl10vy.js +1 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-BJyO3_8y.js → swimlanes-42K2YHIH-CNpYAR3d.js} +1 -1
- package/dist/client/assets/swimlanes-42K2YHIH-CNpYAR3d.js.br +0 -0
- package/dist/client/assets/{swimlanes-42K2YHIH-BJyO3_8y.js.gz → swimlanes-42K2YHIH-CNpYAR3d.js.gz} +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BwjcVbFS.js +8 -0
- package/dist/client/assets/{timeline-definition-24CTP7MA-ocqFrNBu.js → timeline-definition-24CTP7MA-BVEhKc3h.js} +1 -1
- package/dist/client/assets/timeline-definition-24CTP7MA-BVEhKc3h.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-BVEhKc3h.js.gz +0 -0
- package/dist/client/assets/{triangle-alert-CNoodlX6.js → triangle-alert-BIwj1bIH.js} +1 -1
- package/dist/client/assets/{vennDiagram-4TSXK5OY-DOaftoeV.js → vennDiagram-4TSXK5OY-DqKMbCx0.js} +1 -1
- package/dist/client/assets/vennDiagram-4TSXK5OY-DqKMbCx0.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DqKMbCx0.js.gz +0 -0
- package/dist/client/assets/{videoCompression-Cu21usMU.js → videoCompression-DhppheEu.js} +1 -1
- package/dist/client/assets/videoCompression-DhppheEu.js.br +0 -0
- package/dist/client/assets/videoCompression-DhppheEu.js.gz +0 -0
- package/dist/client/assets/{wardleyDiagram-VM6X3IG4-D__Jujiv.js → wardleyDiagram-VM6X3IG4-Bnhg0vB7.js} +1 -1
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Bnhg0vB7.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-Bnhg0vB7.js.gz +0 -0
- package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DU86_bqa.js → xychartDiagram-S5SC5T6Z-BBRqvRXj.js} +1 -1
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BBRqvRXj.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-BBRqvRXj.js.gz +0 -0
- package/dist/client/index.html +1 -1
- 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/android/adb.js +6 -0
- package/dist/server/android/liveBitrate.js +40 -4
- package/dist/server/android/scrcpy.js +71 -19
- package/dist/server/android/scrcpyForward.js +83 -0
- package/dist/server/routes/android.js +5 -2
- package/package.json +1 -1
- package/runtime-manifest.json +3 -3
- package/scripts/android-bitrate/CaptureReset.java +29 -15
- package/scripts/android-bitrate/README.md +26 -5
- package/scripts/android-bitrate/bitrate.jar +0 -0
- package/dist/client/assets/App-CA8oXFgS.js.br +0 -0
- package/dist/client/assets/App-CA8oXFgS.js.gz +0 -0
- package/dist/client/assets/ArchitecturePanel-BkB57agj.js.br +0 -0
- package/dist/client/assets/ArchitecturePanel-BkB57agj.js.gz +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-vh6Z641M.js.br +0 -0
- package/dist/client/assets/ChangeWalkthroughPanel-vh6Z641M.js.gz +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-dTXq04jE.js.br +0 -0
- package/dist/client/assets/CollaborationMainWorkspace-dTXq04jE.js.gz +0 -0
- package/dist/client/assets/CollaborationTaskContent-vtFFtPjY.js +0 -2
- package/dist/client/assets/ComputerControlView-Cmar8PMd.js.br +0 -0
- package/dist/client/assets/ComputerControlView-Cmar8PMd.js.gz +0 -0
- package/dist/client/assets/DagPlayground-C-JZfG9-.js.br +0 -0
- package/dist/client/assets/DagPlayground-C-JZfG9-.js.gz +0 -0
- package/dist/client/assets/DiffLab-rOEPk8iI.js.br +0 -0
- package/dist/client/assets/DiffLab-rOEPk8iI.js.gz +0 -0
- package/dist/client/assets/DiffReview-aIj4WHDS.js.br +0 -0
- package/dist/client/assets/DiffReview-aIj4WHDS.js.gz +0 -0
- package/dist/client/assets/DiffReviewLab-CU4vENL5.js.br +0 -0
- package/dist/client/assets/DiffReviewLab-CU4vENL5.js.gz +0 -0
- package/dist/client/assets/DiffViewer-SKlbS7b4.js.br +0 -0
- package/dist/client/assets/DiffViewer-SKlbS7b4.js.gz +0 -0
- package/dist/client/assets/ModelPreview-mGhBeBla.js.br +0 -0
- package/dist/client/assets/ModelPreview-mGhBeBla.js.gz +0 -0
- package/dist/client/assets/RightSidebar-BtHbt-XD.js.br +0 -0
- package/dist/client/assets/RightSidebar-BtHbt-XD.js.gz +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BazK9AUo.js.br +0 -0
- package/dist/client/assets/abnfDiagram-VCTEODGH-BazK9AUo.js.gz +0 -0
- package/dist/client/assets/app-1SAb4dhI.js.br +0 -0
- package/dist/client/assets/app-1SAb4dhI.js.gz +0 -0
- package/dist/client/assets/arc-DW2qA73J.js.br +0 -0
- package/dist/client/assets/arc-DW2qA73J.js.gz +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CVkFu36h.js.br +0 -0
- package/dist/client/assets/architectureDiagram-5GKGNRK7-CVkFu36h.js.gz +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-Cw0LbdUV.js.br +0 -0
- package/dist/client/assets/blockDiagram-I7D4REHJ-Cw0LbdUV.js.gz +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-D-7cVLVY.js.br +0 -0
- package/dist/client/assets/c4Diagram-7LVT6UL2-D-7cVLVY.js.gz +0 -0
- package/dist/client/assets/channel-B0ZO96Vf.js +0 -1
- package/dist/client/assets/chunk-F27PBJKO-BPQlePZ0.js.br +0 -0
- package/dist/client/assets/chunk-F27PBJKO-BPQlePZ0.js.gz +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CYpkOg4N.js.br +0 -0
- package/dist/client/assets/chunk-IMKFNOWR-CYpkOg4N.js.gz +0 -0
- package/dist/client/assets/chunk-SVP7TREG-TridS3zl.js.br +0 -0
- package/dist/client/assets/chunk-SVP7TREG-TridS3zl.js.gz +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CrSU9J1Y.js.br +0 -0
- package/dist/client/assets/chunk-TICWLB2K-CrSU9J1Y.js.gz +0 -0
- package/dist/client/assets/classDiagram-ZZMXUADV-DNgoON1D.js +0 -1
- package/dist/client/assets/classDiagram-v2-VYDZK3BY-DNgoON1D.js +0 -1
- package/dist/client/assets/cose-bilkent-JH36ORCC-BPspdiZq.js.br +0 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-BPspdiZq.js.gz +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CdZ2Ij-1.js.br +0 -0
- package/dist/client/assets/cynefin-OW5HDTMX-CdZ2Ij-1.js.gz +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CS4dSANt.js.br +0 -0
- package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CS4dSANt.js.gz +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-jz406NVd.js.br +0 -0
- package/dist/client/assets/dagre-GXQ25YYZ-jz406NVd.js.gz +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-BXz7D6hW.js.br +0 -0
- package/dist/client/assets/diagram-S7CK7UJ4-BXz7D6hW.js.gz +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BtSwQGmR.js.br +0 -0
- package/dist/client/assets/diagram-UQ7AKVKN-BtSwQGmR.js.gz +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-B2lDfe93.js.br +0 -0
- package/dist/client/assets/diagram-VSXAHHWV-B2lDfe93.js.gz +0 -0
- package/dist/client/assets/diagram-VX7I27RA-QDrY0hNk.js.br +0 -0
- package/dist/client/assets/diagram-VX7I27RA-QDrY0hNk.js.gz +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-D1AFu390.js.br +0 -0
- package/dist/client/assets/diagram-Z3DM3KII-D1AFu390.js.gz +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-L5aoZUCG.js.br +0 -0
- package/dist/client/assets/ebnfDiagram-PWID7BFC-L5aoZUCG.js.gz +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CFUfoWVL.js.br +0 -0
- package/dist/client/assets/erDiagram-RLTQ6QDP-CFUfoWVL.js.gz +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-A-hvg2q9.js.br +0 -0
- package/dist/client/assets/flowDiagram-HODETNUW-A-hvg2q9.js.gz +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-DSMsjMS7.js.br +0 -0
- package/dist/client/assets/ganttDiagram-EL5Y4UJY-DSMsjMS7.js.gz +0 -0
- package/dist/client/assets/gestureArbiter-BvkspAa2.js.br +0 -0
- package/dist/client/assets/gestureArbiter-BvkspAa2.js.gz +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BhpWzivx.js.br +0 -0
- package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BhpWzivx.js.gz +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-zp9iSkhD.js.br +0 -0
- package/dist/client/assets/ishikawaDiagram-5VMMS53U-zp9iSkhD.js.gz +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CWIWv2zw.js.br +0 -0
- package/dist/client/assets/journeyDiagram-3NMN7TZE-CWIWv2zw.js.gz +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-JzGKFo57.js.br +0 -0
- package/dist/client/assets/kanban-definition-UXKFOSKX-JzGKFo57.js.gz +0 -0
- package/dist/client/assets/layout-7Cq6z6dO.js.br +0 -0
- package/dist/client/assets/layout-7Cq6z6dO.js.gz +0 -0
- package/dist/client/assets/linear-CuFZW946.js.br +0 -0
- package/dist/client/assets/linear-CuFZW946.js.gz +0 -0
- package/dist/client/assets/mermaid.core-DbR5q1bj.js.br +0 -0
- package/dist/client/assets/mermaid.core-DbR5q1bj.js.gz +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DdzejTGB.js.br +0 -0
- package/dist/client/assets/mindmap-definition-YA3MSWOX-DdzejTGB.js.gz +0 -0
- package/dist/client/assets/passwordBootstrap-lisz9s1P.js.br +0 -0
- package/dist/client/assets/passwordBootstrap-lisz9s1P.js.gz +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-D720_LqX.js.br +0 -0
- package/dist/client/assets/pegDiagram-XKGWAZYB-D720_LqX.js.gz +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-zEDQIxrq.js.br +0 -0
- package/dist/client/assets/pieDiagram-E7YTZNPT-zEDQIxrq.js.gz +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Cp0CVTM2.js.br +0 -0
- package/dist/client/assets/quadrantDiagram-AXDQQJYC-Cp0CVTM2.js.gz +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DmEhvOdy.js.br +0 -0
- package/dist/client/assets/railroadDiagram-O6MQD6OU-DmEhvOdy.js.gz +0 -0
- package/dist/client/assets/rdpSession-DQon3e98.js.br +0 -0
- package/dist/client/assets/rdpSession-DQon3e98.js.gz +0 -0
- package/dist/client/assets/referenceLongPress-DTjCnJH8.js.br +0 -0
- package/dist/client/assets/referenceLongPress-DTjCnJH8.js.gz +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BnMPYUjE.js.br +0 -0
- package/dist/client/assets/requirementDiagram-BXWQKSXE-BnMPYUjE.js.gz +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-AvSI5iFI.js.br +0 -0
- package/dist/client/assets/sankeyDiagram-P5KCCOFB-AvSI5iFI.js.gz +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DPXyiIKd.js.br +0 -0
- package/dist/client/assets/sequenceDiagram-WJ2MYXX4-DPXyiIKd.js.gz +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CER_XOvb.js.br +0 -0
- package/dist/client/assets/sizeCapture-INFHLROL-CER_XOvb.js.gz +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BdWVez-f.js.br +0 -0
- package/dist/client/assets/stateDiagram-D77RDMKH-BdWVez-f.js.gz +0 -0
- package/dist/client/assets/stateDiagram-v2-MP3YSRHH-Bm_Va34_.js +0 -1
- package/dist/client/assets/swimlanes-42K2YHIH-BJyO3_8y.js.br +0 -0
- package/dist/client/assets/swimlanesDiagram-VR7AAH4N-C2fV7GHc.js +0 -8
- package/dist/client/assets/timeline-definition-24CTP7MA-ocqFrNBu.js.br +0 -0
- package/dist/client/assets/timeline-definition-24CTP7MA-ocqFrNBu.js.gz +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DOaftoeV.js.br +0 -0
- package/dist/client/assets/vennDiagram-4TSXK5OY-DOaftoeV.js.gz +0 -0
- package/dist/client/assets/videoCompression-Cu21usMU.js.br +0 -0
- package/dist/client/assets/videoCompression-Cu21usMU.js.gz +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-D__Jujiv.js.br +0 -0
- package/dist/client/assets/wardleyDiagram-VM6X3IG4-D__Jujiv.js.gz +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DU86_bqa.js.br +0 -0
- package/dist/client/assets/xychartDiagram-S5SC5T6Z-DU86_bqa.js.gz +0 -0
|
@@ -4,6 +4,7 @@ import net from 'node:net';
|
|
|
4
4
|
import { delimiter, dirname, join } from 'node:path';
|
|
5
5
|
import { randomInt } from 'node:crypto';
|
|
6
6
|
import { adbSearchPath, resolveAdbBinary } from './adb.js';
|
|
7
|
+
import { connectScrcpyForward } from './scrcpyForward.js';
|
|
7
8
|
import { LiveBitrateChannel, inspectLiveBitrate, resolveBundledPreviewServer, bitrateOverlayPath, bitrateOverlayRemote } from './liveBitrate.js';
|
|
8
9
|
const DEVICE_NAME_LENGTH = 64;
|
|
9
10
|
const VIDEO_HEADER_LENGTH = 12;
|
|
@@ -126,11 +127,16 @@ function runAdbCapture(args, timeout = 30_000) {
|
|
|
126
127
|
function scidHex(scid) {
|
|
127
128
|
return scid.toString(16).padStart(8, '0');
|
|
128
129
|
}
|
|
129
|
-
/** 单设备的一条 scrcpy 会话:推送 server →
|
|
130
|
+
/** 单设备的一条 scrcpy 会话:推送 server → ADB 隧道 → 启动 server → 解析视频流。 */
|
|
130
131
|
export class ScrcpySession {
|
|
131
132
|
serial;
|
|
132
133
|
events;
|
|
133
134
|
options;
|
|
135
|
+
// Network ADB can acknowledge reverse rules without carrying their data.
|
|
136
|
+
tunnelForward;
|
|
137
|
+
forwardPort = 0;
|
|
138
|
+
bitrateForwardPort = 0;
|
|
139
|
+
connectionAbort = new AbortController();
|
|
134
140
|
scid = randomInt(1, 0x7fffffff);
|
|
135
141
|
bitrateChannel = null;
|
|
136
142
|
child = null;
|
|
@@ -148,11 +154,13 @@ export class ScrcpySession {
|
|
|
148
154
|
started = false;
|
|
149
155
|
deviceName = '';
|
|
150
156
|
resolveHeader = null;
|
|
157
|
+
rejectHeader = null;
|
|
151
158
|
logLines = [];
|
|
152
159
|
constructor(serial, events, options = {}) {
|
|
153
160
|
this.serial = serial;
|
|
154
161
|
this.events = events;
|
|
155
162
|
this.options = options;
|
|
163
|
+
this.tunnelForward = /[:.]/.test(serial);
|
|
156
164
|
}
|
|
157
165
|
get running() { return this.started && !this.stopped; }
|
|
158
166
|
log(line) {
|
|
@@ -166,6 +174,7 @@ export class ScrcpySession {
|
|
|
166
174
|
fail(error) {
|
|
167
175
|
if (this.stopped)
|
|
168
176
|
return;
|
|
177
|
+
this.rejectHeader?.(error);
|
|
169
178
|
this.events.onError(error);
|
|
170
179
|
void this.stop();
|
|
171
180
|
}
|
|
@@ -178,14 +187,23 @@ export class ScrcpySession {
|
|
|
178
187
|
this.protocol = Number.parseInt(version.split('.')[0] ?? '0', 10) >= 4 ? 'session' : 'legacy';
|
|
179
188
|
const remoteJar = remoteJarPath(version);
|
|
180
189
|
await runAdbCapture(['-s', this.serial, 'push', serverJar, remoteJar], 60_000);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
190
|
+
if (this.tunnelForward) {
|
|
191
|
+
const assigned = await runAdbCapture(['-s', this.serial, 'forward', 'tcp:0', `localabstract:scrcpy_${scidHex(this.scid)}`], 15_000);
|
|
192
|
+
const port = Number(assigned);
|
|
193
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
194
|
+
throw new Error('SCRCPY_FORWARD_INVALID_PORT');
|
|
195
|
+
this.forwardPort = port;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
const server = net.createServer();
|
|
199
|
+
this.server = server;
|
|
200
|
+
server.on('connection', socket => this.acceptSocket(socket));
|
|
201
|
+
await new Promise((resolve, reject) => {
|
|
202
|
+
server.once('error', reject);
|
|
203
|
+
server.listen(0, '127.0.0.1', () => { this.port = server.address().port; resolve(); });
|
|
204
|
+
});
|
|
205
|
+
await runAdbCapture(['-s', this.serial, 'reverse', `localabstract:scrcpy_${scidHex(this.scid)}`, `tcp:${this.port}`], 15_000);
|
|
206
|
+
}
|
|
189
207
|
let liveBitrate = false;
|
|
190
208
|
let bitrateFailure = await inspectLiveBitrate(serverJar, version);
|
|
191
209
|
let bitrateStage = 'BITRATE_LISTEN_FAILED';
|
|
@@ -200,11 +218,19 @@ export class ScrcpySession {
|
|
|
200
218
|
if (!bitrateFailure) {
|
|
201
219
|
try {
|
|
202
220
|
this.bitrateChannel = new LiveBitrateChannel(reportBitrate);
|
|
203
|
-
const port = await this.bitrateChannel.listen();
|
|
221
|
+
const port = this.tunnelForward ? 0 : await this.bitrateChannel.listen();
|
|
204
222
|
bitrateStage = 'BITRATE_PUSH_FAILED';
|
|
205
223
|
await runAdbCapture(['-s', this.serial, 'push', bitrateOverlayPath, bitrateOverlayRemote]);
|
|
206
224
|
bitrateStage = 'BITRATE_TUNNEL_FAILED';
|
|
207
|
-
|
|
225
|
+
if (this.tunnelForward) {
|
|
226
|
+
const assigned = Number(await runAdbCapture(['-s', this.serial, 'forward', 'tcp:0', `localabstract:termdock_bitrate_${scidHex(this.scid)}`]));
|
|
227
|
+
if (!Number.isInteger(assigned) || assigned < 1 || assigned > 65535)
|
|
228
|
+
throw new Error('BITRATE_FORWARD_INVALID_PORT');
|
|
229
|
+
this.bitrateForwardPort = assigned;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
await runAdbCapture(['-s', this.serial, 'reverse', `localabstract:termdock_bitrate_${scidHex(this.scid)}`, `tcp:${port}`]);
|
|
233
|
+
}
|
|
208
234
|
liveBitrate = true;
|
|
209
235
|
}
|
|
210
236
|
catch (error) {
|
|
@@ -218,19 +244,20 @@ export class ScrcpySession {
|
|
|
218
244
|
if (this.stopped) {
|
|
219
245
|
this.bitrateChannel?.close();
|
|
220
246
|
this.server?.close();
|
|
247
|
+
await this.removeForward();
|
|
221
248
|
await Promise.allSettled(['scrcpy_', 'termdock_bitrate_'].map(prefix => runAdbCapture(['-s', this.serial, 'reverse', '--remove', `localabstract:${prefix}${scidHex(this.scid)}`], 8000)));
|
|
222
249
|
return;
|
|
223
250
|
}
|
|
224
251
|
const args = [
|
|
225
252
|
'-s', this.serial, 'shell',
|
|
226
253
|
`CLASSPATH=${liveBitrate ? bitrateOverlayRemote + ":" : ""}${remoteJar}`,
|
|
227
|
-
'app_process', ...(liveBitrate ? [`-Dtermdock.bitrate=termdock_bitrate_${scidHex(this.scid)}
|
|
254
|
+
'app_process', ...(liveBitrate ? [`-Dtermdock.bitrate=termdock_bitrate_${scidHex(this.scid)}`, ...(this.tunnelForward ? ['-Dtermdock.bitrateForward=true'] : [])] : []), '/',
|
|
228
255
|
'com.genymobile.scrcpy.Server', version,
|
|
229
256
|
`scid=${this.scid.toString(16)}`,
|
|
230
257
|
'log_level=info',
|
|
231
258
|
'audio=false',
|
|
232
259
|
'control=true',
|
|
233
|
-
|
|
260
|
+
`tunnel_forward=${this.tunnelForward}`,
|
|
234
261
|
'power_on=true',
|
|
235
262
|
'stay_awake=true',
|
|
236
263
|
'clipboard_autosync=false',
|
|
@@ -239,14 +266,23 @@ export class ScrcpySession {
|
|
|
239
266
|
];
|
|
240
267
|
if (this.options.maxFps && this.options.maxFps > 0)
|
|
241
268
|
args.push(`max_fps=${this.options.maxFps}`);
|
|
269
|
+
const headerReady = this.waitForHeader();
|
|
270
|
+
// Handle early process exit even while forward is establishing its sockets.
|
|
271
|
+
void headerReady.catch(() => { });
|
|
242
272
|
const child = spawn(adbBinary(), args, { stdio: ['ignore', 'pipe', 'pipe'], env: { ...process.env, PATH: adbSearchPath() } });
|
|
243
273
|
this.child = child;
|
|
274
|
+
if (liveBitrate && this.tunnelForward)
|
|
275
|
+
this.bitrateChannel?.connectForward(this.bitrateForwardPort);
|
|
244
276
|
child.stdout?.on('data', chunk => this.log(String(chunk).replace(/^\[server\]\s*/, '')));
|
|
245
277
|
child.stderr?.on('data', chunk => this.log(String(chunk)));
|
|
246
278
|
child.on('error', error => this.fail(error instanceof Error ? error : new Error('SCRCPY_SPAWN_FAILED')));
|
|
247
|
-
child.on('close', () => {
|
|
248
|
-
|
|
249
|
-
|
|
279
|
+
child.on('close', (code, signal) => {
|
|
280
|
+
if (!this.stopped)
|
|
281
|
+
this.fail(new Error(`SCRCPY_SERVER_EXITED: code=${code ?? 'null'} signal=${signal ?? 'none'}; tunnel=${this.tunnelForward ? 'forward' : 'reverse'}; video=${this.videoSocket ? 'connected' : 'not_connected'}\n${this.logLines.slice(-8).join('\n')}`));
|
|
282
|
+
});
|
|
283
|
+
await Promise.all([headerReady, this.tunnelForward
|
|
284
|
+
? connectScrcpyForward(this.forwardPort, this.connectionAbort.signal, socket => this.acceptSocket(socket))
|
|
285
|
+
: Promise.resolve()]);
|
|
250
286
|
}
|
|
251
287
|
catch (error) {
|
|
252
288
|
const normalized = error instanceof Error ? error : new Error('SCRCPY_START_FAILED');
|
|
@@ -257,8 +293,10 @@ export class ScrcpySession {
|
|
|
257
293
|
}
|
|
258
294
|
waitForHeader() {
|
|
259
295
|
return new Promise((resolve, reject) => {
|
|
260
|
-
const
|
|
261
|
-
|
|
296
|
+
const clear = () => { clearTimeout(timer); this.resolveHeader = null; this.rejectHeader = null; };
|
|
297
|
+
const timer = setTimeout(() => { clear(); reject(new Error('SCRCPY_CONNECT_TIMEOUT')); }, CONNECT_TIMEOUT_MS);
|
|
298
|
+
this.resolveHeader = () => { clear(); resolve(); };
|
|
299
|
+
this.rejectHeader = error => { clear(); reject(error); };
|
|
262
300
|
});
|
|
263
301
|
}
|
|
264
302
|
acceptSocket(socket) {
|
|
@@ -268,7 +306,7 @@ export class ScrcpySession {
|
|
|
268
306
|
socket.on('data', chunk => this.readVideo(chunk));
|
|
269
307
|
socket.on('error', error => this.fail(error instanceof Error ? error : new Error('VIDEO_SOCKET_ERROR')));
|
|
270
308
|
socket.on('close', () => { if (!this.stopped)
|
|
271
|
-
this.fail(new Error(this.logLines.
|
|
309
|
+
this.fail(new Error(`VIDEO_SOCKET_CLOSED: tunnel=${this.tunnelForward ? 'forward' : 'reverse'}\n${this.logLines.slice(-8).join('\n')}`)); });
|
|
272
310
|
return;
|
|
273
311
|
}
|
|
274
312
|
if (!this.controlSocket) {
|
|
@@ -416,10 +454,23 @@ export class ScrcpySession {
|
|
|
416
454
|
setBitrate(value) {
|
|
417
455
|
return this.bitrateChannel?.setBitrate(value) ?? Promise.resolve(false);
|
|
418
456
|
}
|
|
457
|
+
async removeForward() {
|
|
458
|
+
const ports = [this.forwardPort, this.bitrateForwardPort].filter(port => port > 0);
|
|
459
|
+
this.forwardPort = 0;
|
|
460
|
+
this.bitrateForwardPort = 0;
|
|
461
|
+
for (const port of ports) {
|
|
462
|
+
try {
|
|
463
|
+
await runAdbCapture(['-s', this.serial, 'forward', '--remove', `tcp:${port}`], 8000);
|
|
464
|
+
}
|
|
465
|
+
catch { /* The device or ADB may already have removed this exact rule. */ }
|
|
466
|
+
}
|
|
467
|
+
}
|
|
419
468
|
async stop() {
|
|
420
469
|
if (this.stopped)
|
|
421
470
|
return;
|
|
422
471
|
this.stopped = true;
|
|
472
|
+
this.connectionAbort.abort();
|
|
473
|
+
this.rejectHeader?.(new Error('SCRCPY_SESSION_STOPPED'));
|
|
423
474
|
activeSessions.delete(this);
|
|
424
475
|
this.bitrateChannel?.close();
|
|
425
476
|
const child = this.child;
|
|
@@ -445,6 +496,7 @@ export class ScrcpySession {
|
|
|
445
496
|
}
|
|
446
497
|
catch { /* ignore */ }
|
|
447
498
|
}
|
|
499
|
+
await this.removeForward();
|
|
448
500
|
try {
|
|
449
501
|
await runAdbCapture(['-s', this.serial, 'reverse', '--remove', `localabstract:scrcpy_${scidHex(this.scid)}`], 8000);
|
|
450
502
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
/** Wait for scrcpy's dummy byte: an ADB forward TCP accept alone does not
|
|
3
|
+
* prove the device-side localabstract listener has started yet. */
|
|
4
|
+
export async function connectScrcpyForward(port, signal, accept, timeoutMs = 12_000) {
|
|
5
|
+
const deadline = Date.now() + timeoutMs;
|
|
6
|
+
const open = (dummy) => new Promise((resolve, reject) => {
|
|
7
|
+
if (signal.aborted) {
|
|
8
|
+
reject(new Error('SCRCPY_SESSION_STOPPED'));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const socket = net.connect({ host: '127.0.0.1', port });
|
|
12
|
+
const timer = setTimeout(() => fail(new Error('SCRCPY_FORWARD_CONNECT_TIMEOUT')), Math.min(500, Math.max(1, deadline - Date.now())));
|
|
13
|
+
const cleanup = () => {
|
|
14
|
+
clearTimeout(timer);
|
|
15
|
+
signal.removeEventListener('abort', abort);
|
|
16
|
+
socket.removeListener('error', fail);
|
|
17
|
+
socket.removeListener('close', closed);
|
|
18
|
+
socket.removeListener('data', data);
|
|
19
|
+
socket.removeListener('connect', connected);
|
|
20
|
+
};
|
|
21
|
+
const fail = (error) => { cleanup(); socket.destroy(); reject(error); };
|
|
22
|
+
const closed = () => fail(new Error('SCRCPY_FORWARD_CONNECTION_CLOSED'));
|
|
23
|
+
const abort = () => fail(new Error('SCRCPY_SESSION_STOPPED'));
|
|
24
|
+
const ready = () => { socket.pause(); cleanup(); resolve(socket); };
|
|
25
|
+
const connected = () => { if (!dummy)
|
|
26
|
+
ready(); };
|
|
27
|
+
const data = (chunk) => {
|
|
28
|
+
if (!chunk.length)
|
|
29
|
+
return;
|
|
30
|
+
if (chunk[0] !== 0) {
|
|
31
|
+
fail(new Error('SCRCPY_FORWARD_HANDSHAKE_INVALID'));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
socket.pause();
|
|
35
|
+
if (chunk.length > 1)
|
|
36
|
+
socket.unshift(chunk.subarray(1));
|
|
37
|
+
ready();
|
|
38
|
+
};
|
|
39
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
40
|
+
socket.on('error', fail);
|
|
41
|
+
socket.on('close', closed);
|
|
42
|
+
socket.on('connect', connected);
|
|
43
|
+
if (dummy)
|
|
44
|
+
socket.on('data', data);
|
|
45
|
+
});
|
|
46
|
+
let video;
|
|
47
|
+
let control;
|
|
48
|
+
try {
|
|
49
|
+
while (!signal.aborted && Date.now() < deadline) {
|
|
50
|
+
try {
|
|
51
|
+
video = await open(true);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (signal.aborted || Date.now() >= deadline)
|
|
56
|
+
throw error;
|
|
57
|
+
await new Promise(resolve => {
|
|
58
|
+
const done = () => { clearTimeout(timer); signal.removeEventListener('abort', done); resolve(); };
|
|
59
|
+
const timer = setTimeout(done, 100);
|
|
60
|
+
signal.addEventListener('abort', done, { once: true });
|
|
61
|
+
if (signal.aborted)
|
|
62
|
+
done();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!video || signal.aborted)
|
|
67
|
+
throw new Error(signal.aborted ? 'SCRCPY_SESSION_STOPPED' : 'SCRCPY_FORWARD_CONNECT_TIMEOUT');
|
|
68
|
+
// Install video error/close listeners before waiting for control.
|
|
69
|
+
accept(video);
|
|
70
|
+
control = await open(false);
|
|
71
|
+
if (signal.aborted)
|
|
72
|
+
throw new Error('SCRCPY_SESSION_STOPPED');
|
|
73
|
+
// Keep video paused until both sockets have listeners and definite roles.
|
|
74
|
+
accept(control);
|
|
75
|
+
video.resume();
|
|
76
|
+
control.resume();
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
video?.destroy();
|
|
80
|
+
control?.destroy();
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -162,14 +162,17 @@ export function handleAndroidWebSocket(socket, serial, _clientId, requested = {}
|
|
|
162
162
|
const shutdown = (reason) => {
|
|
163
163
|
if (closed)
|
|
164
164
|
return;
|
|
165
|
+
// send() rejects closed sessions: deliver the cause before marking it closed.
|
|
166
|
+
if (reason) {
|
|
167
|
+
console.warn(`[android] session failed serial=${serial}: ${reason}`);
|
|
168
|
+
send({ type: 'error', message: reason });
|
|
169
|
+
}
|
|
165
170
|
closed = true;
|
|
166
171
|
clearInterval(flowTimer);
|
|
167
172
|
if (statsTimer)
|
|
168
173
|
clearInterval(statsTimer);
|
|
169
174
|
if (DEBUG_ANDROID)
|
|
170
175
|
console.log(`[android] session end serial=${serial} sent=${sent} acked=${acked} reason=${reason ?? 'ok'}`);
|
|
171
|
-
if (reason)
|
|
172
|
-
send({ type: 'error', message: reason });
|
|
173
176
|
try {
|
|
174
177
|
session?.stop();
|
|
175
178
|
}
|
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.336",
|
|
5
5
|
"runtimeProtocolVersion": 1,
|
|
6
6
|
"minimumDesktopVersion": "1.4.46",
|
|
7
7
|
"nodeMajor": 22,
|
|
8
8
|
"dependencyHash": "sha256-oaGYi/P5ob8sd6VnNBOwshKozjhdV+hYiCmLAsn5x00=",
|
|
9
|
-
"serverBundleHash": "sha256-
|
|
10
|
-
"clientBundleHash": "sha256-
|
|
9
|
+
"serverBundleHash": "sha256-KvJEGINN1M45Zs/oNpJTb+vlpFCr0C8rKqS2Flp7+tI=",
|
|
10
|
+
"clientBundleHash": "sha256-5AO8soGCDDxFlZjr8zTeNxVLFL4bw+MXYLTu2kdyLs0=",
|
|
11
11
|
"entrypoint": "dist/server/cli.js",
|
|
12
12
|
"clientEntrypoint": "dist/client/index.html"
|
|
13
13
|
}
|
|
@@ -5,6 +5,7 @@ package com.genymobile.scrcpy.video;
|
|
|
5
5
|
|
|
6
6
|
import android.media.MediaCodec;
|
|
7
7
|
import android.net.LocalSocket;
|
|
8
|
+
import android.net.LocalServerSocket;
|
|
8
9
|
import android.net.LocalSocketAddress;
|
|
9
10
|
import android.os.Bundle;
|
|
10
11
|
import java.io.DataInputStream;
|
|
@@ -59,28 +60,41 @@ public class CaptureReset implements SurfaceCapture.CaptureListener {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
private void serve(String name) {
|
|
62
|
-
try
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (failure != null) {
|
|
73
|
-
byte[] detail = failure.substring(0, Math.min(512, failure.length())).getBytes(StandardCharsets.UTF_8);
|
|
74
|
-
output.writeInt(detail.length);
|
|
75
|
-
output.write(detail);
|
|
63
|
+
try {
|
|
64
|
+
if (Boolean.getBoolean("termdock.bitrateForward")) {
|
|
65
|
+
try (LocalServerSocket server = new LocalServerSocket(name);
|
|
66
|
+
LocalSocket socket = server.accept()) {
|
|
67
|
+
exchange(socket);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
try (LocalSocket socket = new LocalSocket()) {
|
|
71
|
+
socket.connect(new LocalSocketAddress(name));
|
|
72
|
+
exchange(socket);
|
|
76
73
|
}
|
|
77
|
-
output.flush();
|
|
78
74
|
}
|
|
79
75
|
} catch (IOException ignored) {
|
|
80
76
|
// A bitrate-channel failure must never tear down video/control.
|
|
81
77
|
}
|
|
82
78
|
}
|
|
83
79
|
|
|
80
|
+
private void exchange(LocalSocket socket) throws IOException {
|
|
81
|
+
DataInputStream input = new DataInputStream(socket.getInputStream());
|
|
82
|
+
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
|
|
83
|
+
output.writeInt(0x54444232); // TDB2: rejection includes length-prefixed UTF-8 diagnostic
|
|
84
|
+
output.flush();
|
|
85
|
+
while (true) {
|
|
86
|
+
int requested = input.readInt();
|
|
87
|
+
String failure = applyBitrate(requested);
|
|
88
|
+
output.writeInt(failure == null ? requested : 0);
|
|
89
|
+
if (failure != null) {
|
|
90
|
+
byte[] detail = failure.substring(0, Math.min(512, failure.length())).getBytes(StandardCharsets.UTF_8);
|
|
91
|
+
output.writeInt(detail.length);
|
|
92
|
+
output.write(detail);
|
|
93
|
+
}
|
|
94
|
+
output.flush();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
84
98
|
@Override
|
|
85
99
|
public void onInvalidated() { reset(); }
|
|
86
100
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# scrcpy live bitrate extension
|
|
2
2
|
|
|
3
|
-
Termdock loads this
|
|
3
|
+
Termdock loads this small Android DEX overlay before the bundled, verified scrcpy 3.3.4 server
|
|
4
4
|
for preview sessions only. The host scrcpy version no longer gates automatic quality. Recording uses the unmodified scrcpy executable/server.
|
|
5
5
|
|
|
6
6
|
CaptureReset.java preserves scrcpy 3.3.4's existing ABI and reset behavior,
|
|
7
|
-
adding a session-scoped ADB
|
|
7
|
+
adding a session-scoped ADB socket. The running hardware encoder receives
|
|
8
8
|
MediaCodec.PARAMETER_KEY_VIDEO_BITRATE via setParameters, under the same lock
|
|
9
9
|
used to clear the codec before stop/reset. There is no transcoding, frame polling,
|
|
10
10
|
forced keyframe, video reset, resolution change or new video connection.
|
|
@@ -26,6 +26,16 @@ checksum before writing). Its source is https://github.com/Genymobile/scrcpy/tre
|
|
|
26
26
|
An explicit TERMDOCK_SCRCPY_SERVER override is honored. Missing/invalid bundled
|
|
27
27
|
assets fall back to the host server; unverified host builds then retain current
|
|
28
28
|
quality with a diagnostic. Rejections and channel failures also preserve video.
|
|
29
|
+
|
|
30
|
+
Network ADB preview sessions use `adb forward` for video and control; USB
|
|
31
|
+
sessions retain `adb reverse`. The forward connector waits for the scrcpy dummy
|
|
32
|
+
byte before opening control and removes only its own allocated TCP rule on stop.
|
|
33
|
+
The optional bitrate channel uses its own forward rule for network devices; its
|
|
34
|
+
device-side listener accepts the host connection after the encoder starts. USB
|
|
35
|
+
retains its separate reverse rule. Early forward TCP accepts are retried until
|
|
36
|
+
the TDB handshake arrives, within the existing 15-second limit. Bitrate failures
|
|
37
|
+
remain isolated from video/control, and stop removes both session-owned rules.
|
|
38
|
+
|
|
29
39
|
Extend the allowlist only after verifying the CaptureReset ABI and real-device
|
|
30
40
|
behavior. No global scrcpy installation is modified.
|
|
31
41
|
|
|
@@ -40,10 +50,21 @@ desktop runtime packager. Apache-2.0 license is included.
|
|
|
40
50
|
|
|
41
51
|
Validation: Mi MIX 2S / Android 13 accepted 1.8 → 6 → 0.9 → 4 Mbps within
|
|
42
52
|
one session, continuously producing frames, with one video header and one codec
|
|
43
|
-
configuration packet.
|
|
44
|
-
|
|
53
|
+
configuration packet.
|
|
54
|
+
|
|
55
|
+
Mac server and iPhone preview rendering were also verified with network
|
|
56
|
+
PTP-AN00 / Android 16 and Pixel 9 / Android 15 using forward video. On those cloud
|
|
57
|
+
routes, reverse registration succeeded without carrying data; this motivated
|
|
58
|
+
using forward for both video and the separate bitrate channel. Physical identity properties matched across
|
|
59
|
+
the PTP IPv4/IPv6 routes; option grouping and selected-route preservation are
|
|
60
|
+
covered by tests. Full native input/recording acceptance remains outside these observations.
|
|
61
|
+
The Pixel 9 forward bitrate channel was verified on the Mac server: all four
|
|
62
|
+
1.8 → 6 → 0.9 → 4 Mbps requests received matching ACKs in 35–37 ms, with one
|
|
63
|
+
video header and the same scrcpy process throughout a 20-second session. Both
|
|
64
|
+
forward rules were removed on stop. API acceptance does not establish exact
|
|
65
|
+
vendor output bandwidth.
|
|
45
66
|
|
|
46
|
-
Diagnostics distinguish version/build, missing/corrupt extension, ADB push/
|
|
67
|
+
Diagnostics distinguish version/build, missing/corrupt extension, ADB push/tunnel,
|
|
47
68
|
15s handshake timeout, 2.5s device ACK timeout, 4s client confirmation timeout,
|
|
48
69
|
channel/protocol failure and device codec rejection. Detailed reasons travel over
|
|
49
70
|
the existing encrypted stream and appear in an expandable warning. Intentional
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{bA as r}from"./app-1SAb4dhI.js";import{b as m}from"./dnd-BCFAPC0L.js";import{b as n}from"./RightSidebar-BtHbt-XD.js";import"./react-XDCjal2T.js";import"./terminal-C7X98Amf.js";import"./App-CA8oXFgS.js";import"./gestureArbiter-BvkspAa2.js";import"./triangle-alert-CNoodlX6.js";import"./referenceLongPress-DTjCnJH8.js";import"./DiffReview-aIj4WHDS.js";import"./sparkles-CgwSF-UK.js";import"./DiffViewer-SKlbS7b4.js";import"./ChangeWalkthroughPanel-vh6Z641M.js";function g({content:o}){const e=m.useMemo(()=>n(o.split(`
|
|
2
|
-
`),null,null),[o]);return r.jsx("div",{className:"min-w-0 space-y-3 break-words text-sm leading-6 text-foreground [&_h1]:text-lg [&_h2]:text-base [&_h3]:text-sm [&_pre]:max-w-full [&_table]:text-xs",children:e.map((t,i)=>r.jsx("div",{className:"min-w-0",children:typeof t.content=="function"?t.content(null):t.content},i))})}export{g as default};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{c as a,C as n}from"./mermaid.core-DbR5q1bj.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as t,C as e}from"./chunk-TICWLB2K-CrSU9J1Y.js";import{d as i}from"./mermaid.core-DbR5q1bj.js";import"./chunk-5VM5RSS4-DT9NVgVz.js";import"./chunk-XXDRQBXY-DvrlcFpp.js";import"./chunk-POPQ4Y6H-CHVqavTY.js";import"./chunk-F27PBJKO-BPQlePZ0.js";import"./purify.es-4eNOHKSq.js";import"./app-1SAb4dhI.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as t,C as e}from"./chunk-TICWLB2K-CrSU9J1Y.js";import{d as i}from"./mermaid.core-DbR5q1bj.js";import"./chunk-5VM5RSS4-DT9NVgVz.js";import"./chunk-XXDRQBXY-DvrlcFpp.js";import"./chunk-POPQ4Y6H-CHVqavTY.js";import"./chunk-F27PBJKO-BPQlePZ0.js";import"./purify.es-4eNOHKSq.js";import"./app-1SAb4dhI.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|