termdock 1.4.174 → 1.4.176

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/.desktop-dist/main.js +154 -7
  2. package/dist/client/assets/App-BXYZyI_k.js +150 -0
  3. package/dist/client/assets/App-BXYZyI_k.js.br +0 -0
  4. package/dist/client/assets/App-BXYZyI_k.js.gz +0 -0
  5. package/dist/client/assets/ChangeWalkthroughPanel-DeVtCf73.js +2 -0
  6. package/dist/client/assets/ChangeWalkthroughPanel-DeVtCf73.js.br +0 -0
  7. package/dist/client/assets/ChangeWalkthroughPanel-DeVtCf73.js.gz +0 -0
  8. package/dist/client/assets/DagPlayground-ZIqLZoMo.js +1 -0
  9. package/dist/client/assets/DagPlayground-ZIqLZoMo.js.br +0 -0
  10. package/dist/client/assets/DagPlayground-ZIqLZoMo.js.gz +0 -0
  11. package/dist/client/assets/{DiffLab-CdbPsjKS.js → DiffLab-CSMf8So2.js} +2 -2
  12. package/dist/client/assets/DiffLab-CSMf8So2.js.br +0 -0
  13. package/dist/client/assets/DiffLab-CSMf8So2.js.gz +0 -0
  14. package/dist/client/assets/DiffReview-CE5lW1zQ.js +1 -0
  15. package/dist/client/assets/DiffReview-CE5lW1zQ.js.br +0 -0
  16. package/dist/client/assets/DiffReview-CE5lW1zQ.js.gz +0 -0
  17. package/dist/client/assets/DiffReviewLab-CpUW75fZ.js +2 -0
  18. package/dist/client/assets/DiffReviewLab-CpUW75fZ.js.br +0 -0
  19. package/dist/client/assets/DiffReviewLab-CpUW75fZ.js.gz +0 -0
  20. package/dist/client/assets/{DiffViewer-hdxcM9yF.js → DiffViewer-BomvZ4kq.js} +5 -5
  21. package/dist/client/assets/DiffViewer-BomvZ4kq.js.br +0 -0
  22. package/dist/client/assets/DiffViewer-BomvZ4kq.js.gz +0 -0
  23. package/dist/client/assets/{ModelPreview-BZ454pgM.js → ModelPreview-BWdZFyhh.js} +3 -3
  24. package/dist/client/assets/ModelPreview-BWdZFyhh.js.br +0 -0
  25. package/dist/client/assets/ModelPreview-BWdZFyhh.js.gz +0 -0
  26. package/dist/client/assets/RightSidebar-CYVwFbOc.js +79 -0
  27. package/dist/client/assets/RightSidebar-CYVwFbOc.js.br +0 -0
  28. package/dist/client/assets/RightSidebar-CYVwFbOc.js.gz +0 -0
  29. package/dist/client/assets/{abnfDiagram-VCTEODGH-C185Omck.js → abnfDiagram-VCTEODGH-BIPsLStE.js} +1 -1
  30. package/dist/client/assets/abnfDiagram-VCTEODGH-BIPsLStE.js.br +0 -0
  31. package/dist/client/assets/abnfDiagram-VCTEODGH-BIPsLStE.js.gz +0 -0
  32. package/dist/client/assets/app-D6KzR8B3.js +34 -0
  33. package/dist/client/assets/app-D6KzR8B3.js.br +0 -0
  34. package/dist/client/assets/app-D6KzR8B3.js.gz +0 -0
  35. package/dist/client/assets/{arc-DNt-DTCl.js → arc-DzeT6hBj.js} +1 -1
  36. package/dist/client/assets/arc-DzeT6hBj.js.br +0 -0
  37. package/dist/client/assets/arc-DzeT6hBj.js.gz +0 -0
  38. package/dist/client/assets/{architectureDiagram-5GKGNRK7-C5Nwm_Qz.js → architectureDiagram-5GKGNRK7-B1qsxd_5.js} +1 -1
  39. package/dist/client/assets/architectureDiagram-5GKGNRK7-B1qsxd_5.js.br +0 -0
  40. package/dist/client/assets/architectureDiagram-5GKGNRK7-B1qsxd_5.js.gz +0 -0
  41. package/dist/client/assets/{blockDiagram-I7D4REHJ-C5aR_7V9.js → blockDiagram-I7D4REHJ-NLsa29Jp.js} +1 -1
  42. package/dist/client/assets/blockDiagram-I7D4REHJ-NLsa29Jp.js.br +0 -0
  43. package/dist/client/assets/blockDiagram-I7D4REHJ-NLsa29Jp.js.gz +0 -0
  44. package/dist/client/assets/{c4Diagram-7LVT6UL2-DjV6ZNwd.js → c4Diagram-7LVT6UL2-DBAUvou3.js} +1 -1
  45. package/dist/client/assets/c4Diagram-7LVT6UL2-DBAUvou3.js.br +0 -0
  46. package/dist/client/assets/c4Diagram-7LVT6UL2-DBAUvou3.js.gz +0 -0
  47. package/dist/client/assets/channel-BhwBAWhq.js +1 -0
  48. package/dist/client/assets/{chunk-2Q5K7J3B-Ct7nd4cL.js → chunk-2Q5K7J3B-BsVAXGLa.js} +1 -1
  49. package/dist/client/assets/{chunk-5VM5RSS4-CXem4UYP.js → chunk-5VM5RSS4-BKtILsst.js} +1 -1
  50. package/dist/client/assets/{chunk-F27PBJKO-DyMNEawE.js → chunk-F27PBJKO-Dn9zcQZG.js} +1 -1
  51. package/dist/client/assets/chunk-F27PBJKO-Dn9zcQZG.js.br +0 -0
  52. package/dist/client/assets/chunk-F27PBJKO-Dn9zcQZG.js.gz +0 -0
  53. package/dist/client/assets/{chunk-IMKFNOWR-BsW7iIrh.js → chunk-IMKFNOWR-MVtVQeTr.js} +1 -1
  54. package/dist/client/assets/chunk-IMKFNOWR-MVtVQeTr.js.br +0 -0
  55. package/dist/client/assets/{chunk-IMKFNOWR-BsW7iIrh.js.gz → chunk-IMKFNOWR-MVtVQeTr.js.gz} +0 -0
  56. package/dist/client/assets/{chunk-JWPE2WC7-EO8E1q1J.js → chunk-JWPE2WC7-DliIIMe7.js} +1 -1
  57. package/dist/client/assets/{chunk-POPQ4Y6H-0One8T9x.js → chunk-POPQ4Y6H-XBSus3IC.js} +1 -1
  58. package/dist/client/assets/{chunk-SVP7TREG-CDu41dkj.js → chunk-SVP7TREG-wleSQcJR.js} +1 -1
  59. package/dist/client/assets/chunk-SVP7TREG-wleSQcJR.js.br +0 -0
  60. package/dist/client/assets/chunk-SVP7TREG-wleSQcJR.js.gz +0 -0
  61. package/dist/client/assets/{chunk-TICWLB2K-BACjgX9v.js → chunk-TICWLB2K-Dq6LdswN.js} +1 -1
  62. package/dist/client/assets/chunk-TICWLB2K-Dq6LdswN.js.br +0 -0
  63. package/dist/client/assets/chunk-TICWLB2K-Dq6LdswN.js.gz +0 -0
  64. package/dist/client/assets/{chunk-XXDRQBXY-BJWowF6E.js → chunk-XXDRQBXY-xafyKlM-.js} +1 -1
  65. package/dist/client/assets/classDiagram-ZZMXUADV-slQB0ns2.js +1 -0
  66. package/dist/client/assets/classDiagram-v2-VYDZK3BY-slQB0ns2.js +1 -0
  67. package/dist/client/assets/{cose-bilkent-JH36ORCC-WTwHOCdm.js → cose-bilkent-JH36ORCC-BR7Ohnm_.js} +1 -1
  68. package/dist/client/assets/cose-bilkent-JH36ORCC-BR7Ohnm_.js.br +0 -0
  69. package/dist/client/assets/cose-bilkent-JH36ORCC-BR7Ohnm_.js.gz +0 -0
  70. package/dist/client/assets/{cynefin-OW5HDTMX-D4y8TkaO.js → cynefin-OW5HDTMX-CmPjQgER.js} +1 -1
  71. package/dist/client/assets/cynefin-OW5HDTMX-CmPjQgER.js.br +0 -0
  72. package/dist/client/assets/cynefin-OW5HDTMX-CmPjQgER.js.gz +0 -0
  73. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-BzN8Ggk_.js → cynefinDiagram-5FMLGOSQ-CFyR9RvM.js} +1 -1
  74. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CFyR9RvM.js.br +0 -0
  75. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-CFyR9RvM.js.gz +0 -0
  76. package/dist/client/assets/{dagre-GXQ25YYZ-CwMYtt5E.js → dagre-GXQ25YYZ-D_RVMRO1.js} +1 -1
  77. package/dist/client/assets/dagre-GXQ25YYZ-D_RVMRO1.js.br +0 -0
  78. package/dist/client/assets/dagre-GXQ25YYZ-D_RVMRO1.js.gz +0 -0
  79. package/dist/client/assets/{diagram-S7CK7UJ4-BnTeHiAb.js → diagram-S7CK7UJ4-6fr-ZoPj.js} +1 -1
  80. package/dist/client/assets/diagram-S7CK7UJ4-6fr-ZoPj.js.br +0 -0
  81. package/dist/client/assets/diagram-S7CK7UJ4-6fr-ZoPj.js.gz +0 -0
  82. package/dist/client/assets/{diagram-UQ7AKVKN-BNlh251g.js → diagram-UQ7AKVKN-CgwiUtz0.js} +1 -1
  83. package/dist/client/assets/diagram-UQ7AKVKN-CgwiUtz0.js.br +0 -0
  84. package/dist/client/assets/diagram-UQ7AKVKN-CgwiUtz0.js.gz +0 -0
  85. package/dist/client/assets/{diagram-VSXAHHWV-B5FftXkQ.js → diagram-VSXAHHWV-CLxzTB9k.js} +1 -1
  86. package/dist/client/assets/diagram-VSXAHHWV-CLxzTB9k.js.br +0 -0
  87. package/dist/client/assets/diagram-VSXAHHWV-CLxzTB9k.js.gz +0 -0
  88. package/dist/client/assets/{diagram-VX7I27RA-C51ZNXR2.js → diagram-VX7I27RA-DjxDAvdZ.js} +1 -1
  89. package/dist/client/assets/diagram-VX7I27RA-DjxDAvdZ.js.br +0 -0
  90. package/dist/client/assets/diagram-VX7I27RA-DjxDAvdZ.js.gz +0 -0
  91. package/dist/client/assets/{diagram-Z3DM3KII-CXoZH2qf.js → diagram-Z3DM3KII-CDPOjiz4.js} +1 -1
  92. package/dist/client/assets/diagram-Z3DM3KII-CDPOjiz4.js.br +0 -0
  93. package/dist/client/assets/diagram-Z3DM3KII-CDPOjiz4.js.gz +0 -0
  94. package/dist/client/assets/{ebnfDiagram-PWID7BFC-C7YFLlx4.js → ebnfDiagram-PWID7BFC-BLbwyF1O.js} +1 -1
  95. package/dist/client/assets/ebnfDiagram-PWID7BFC-BLbwyF1O.js.br +0 -0
  96. package/dist/client/assets/ebnfDiagram-PWID7BFC-BLbwyF1O.js.gz +0 -0
  97. package/dist/client/assets/{erDiagram-RLTQ6QDP-BNQlS7-g.js → erDiagram-RLTQ6QDP-DbjtZnJx.js} +1 -1
  98. package/dist/client/assets/erDiagram-RLTQ6QDP-DbjtZnJx.js.br +0 -0
  99. package/dist/client/assets/erDiagram-RLTQ6QDP-DbjtZnJx.js.gz +0 -0
  100. package/dist/client/assets/{flowDiagram-HODETNUW-DIQXZ06I.js → flowDiagram-HODETNUW-BirJInAN.js} +1 -1
  101. package/dist/client/assets/flowDiagram-HODETNUW-BirJInAN.js.br +0 -0
  102. package/dist/client/assets/flowDiagram-HODETNUW-BirJInAN.js.gz +0 -0
  103. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-BaJQfOqD.js → ganttDiagram-EL5Y4UJY-d6Q9vSbv.js} +1 -1
  104. package/dist/client/assets/ganttDiagram-EL5Y4UJY-d6Q9vSbv.js.br +0 -0
  105. package/dist/client/assets/ganttDiagram-EL5Y4UJY-d6Q9vSbv.js.gz +0 -0
  106. package/dist/client/assets/gestureArbiter-C2J0D0kV.css +1 -0
  107. package/dist/client/assets/gestureArbiter-C2J0D0kV.css.br +0 -0
  108. package/dist/client/assets/gestureArbiter-C2J0D0kV.css.gz +0 -0
  109. package/dist/client/assets/gestureArbiter-D1SNS_gK.js +1 -0
  110. package/dist/client/assets/gestureArbiter-D1SNS_gK.js.br +0 -0
  111. package/dist/client/assets/gestureArbiter-D1SNS_gK.js.gz +0 -0
  112. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-tQ4E6pwN.js → gitGraphDiagram-WWUBYQGX-BWBoIeS6.js} +1 -1
  113. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BWBoIeS6.js.br +0 -0
  114. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-BWBoIeS6.js.gz +0 -0
  115. package/dist/client/assets/{index-DlxiaPv1.css → index-DUI8KRf6.css} +1 -1
  116. package/dist/client/assets/index-DUI8KRf6.css.br +0 -0
  117. package/dist/client/assets/index-DUI8KRf6.css.gz +0 -0
  118. package/dist/client/assets/{infoDiagram-27XIBGKW-DTOUeQrN.js → infoDiagram-27XIBGKW-BH4AynkM.js} +1 -1
  119. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-8sBi-gla.js → ishikawaDiagram-5VMMS53U-BQw90AKR.js} +1 -1
  120. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-8sBi-gla.js.br → ishikawaDiagram-5VMMS53U-BQw90AKR.js.br} +0 -0
  121. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BQw90AKR.js.gz +0 -0
  122. package/dist/client/assets/{journeyDiagram-3NMN7TZE-ZwikziWh.js → journeyDiagram-3NMN7TZE-DISkQocf.js} +1 -1
  123. package/dist/client/assets/journeyDiagram-3NMN7TZE-DISkQocf.js.br +0 -0
  124. package/dist/client/assets/{journeyDiagram-3NMN7TZE-ZwikziWh.js.gz → journeyDiagram-3NMN7TZE-DISkQocf.js.gz} +0 -0
  125. package/dist/client/assets/{kanban-definition-UXKFOSKX-wjuw2jQ4.js → kanban-definition-UXKFOSKX-Qg2LyEVy.js} +1 -1
  126. package/dist/client/assets/kanban-definition-UXKFOSKX-Qg2LyEVy.js.br +0 -0
  127. package/dist/client/assets/kanban-definition-UXKFOSKX-Qg2LyEVy.js.gz +0 -0
  128. package/dist/client/assets/{layout-nASMIj-E.js → layout-Cd7-4_Vr.js} +1 -1
  129. package/dist/client/assets/layout-Cd7-4_Vr.js.br +0 -0
  130. package/dist/client/assets/layout-Cd7-4_Vr.js.gz +0 -0
  131. package/dist/client/assets/{linear-pGaQeqW5.js → linear-DFTi2fTn.js} +1 -1
  132. package/dist/client/assets/linear-DFTi2fTn.js.br +0 -0
  133. package/dist/client/assets/linear-DFTi2fTn.js.gz +0 -0
  134. package/dist/client/assets/{mermaid.core-CKEBWbQz.js → mermaid.core-2v726lUU.js} +5 -5
  135. package/dist/client/assets/mermaid.core-2v726lUU.js.br +0 -0
  136. package/dist/client/assets/mermaid.core-2v726lUU.js.gz +0 -0
  137. package/dist/client/assets/{mindmap-definition-YA3MSWOX-CBjYcnwd.js → mindmap-definition-YA3MSWOX-_FpwteCy.js} +4 -4
  138. package/dist/client/assets/mindmap-definition-YA3MSWOX-_FpwteCy.js.br +0 -0
  139. package/dist/client/assets/mindmap-definition-YA3MSWOX-_FpwteCy.js.gz +0 -0
  140. package/dist/client/assets/passwordBootstrap-D9Ffc7NY.js +2 -0
  141. package/dist/client/assets/passwordBootstrap-D9Ffc7NY.js.br +0 -0
  142. package/dist/client/assets/passwordBootstrap-D9Ffc7NY.js.gz +0 -0
  143. package/dist/client/assets/{pegDiagram-XKGWAZYB-DJqvclIp.js → pegDiagram-XKGWAZYB-DLFf-HmZ.js} +1 -1
  144. package/dist/client/assets/pegDiagram-XKGWAZYB-DLFf-HmZ.js.br +0 -0
  145. package/dist/client/assets/pegDiagram-XKGWAZYB-DLFf-HmZ.js.gz +0 -0
  146. package/dist/client/assets/{pieDiagram-E7YTZNPT-DLV4WPwc.js → pieDiagram-E7YTZNPT-DqTnfXHG.js} +1 -1
  147. package/dist/client/assets/pieDiagram-E7YTZNPT-DqTnfXHG.js.br +0 -0
  148. package/dist/client/assets/pieDiagram-E7YTZNPT-DqTnfXHG.js.gz +0 -0
  149. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-BN7Zpsb9.js → quadrantDiagram-AXDQQJYC-B_oBH52Q.js} +1 -1
  150. package/dist/client/assets/quadrantDiagram-AXDQQJYC-B_oBH52Q.js.br +0 -0
  151. package/dist/client/assets/quadrantDiagram-AXDQQJYC-B_oBH52Q.js.gz +0 -0
  152. package/dist/client/assets/{railroadDiagram-O6MQD6OU-DfHX6MUm.js → railroadDiagram-O6MQD6OU-HxFQ7Pce.js} +1 -1
  153. package/dist/client/assets/railroadDiagram-O6MQD6OU-HxFQ7Pce.js.br +0 -0
  154. package/dist/client/assets/railroadDiagram-O6MQD6OU-HxFQ7Pce.js.gz +0 -0
  155. package/dist/client/assets/referenceLongPress-B3NGIjvv.js +1 -0
  156. package/dist/client/assets/referenceLongPress-B3NGIjvv.js.br +0 -0
  157. package/dist/client/assets/referenceLongPress-B3NGIjvv.js.gz +0 -0
  158. package/dist/client/assets/{requirementDiagram-BXWQKSXE-tQVSFg_k.js → requirementDiagram-BXWQKSXE-NZdfaZFk.js} +1 -1
  159. package/dist/client/assets/requirementDiagram-BXWQKSXE-NZdfaZFk.js.br +0 -0
  160. package/dist/client/assets/requirementDiagram-BXWQKSXE-NZdfaZFk.js.gz +0 -0
  161. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-C7JW1-Wh.js → sankeyDiagram-P5KCCOFB-BgCctv6X.js} +1 -1
  162. package/dist/client/assets/sankeyDiagram-P5KCCOFB-BgCctv6X.js.br +0 -0
  163. package/dist/client/assets/sankeyDiagram-P5KCCOFB-BgCctv6X.js.gz +0 -0
  164. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-BVeDiFDI.js → sequenceDiagram-WJ2MYXX4-Br42Za1R.js} +1 -1
  165. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Br42Za1R.js.br +0 -0
  166. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Br42Za1R.js.gz +0 -0
  167. package/dist/client/assets/{sizeCapture-INFHLROL-CBRaCpeP.js → sizeCapture-INFHLROL-FT4z4S1b.js} +1 -1
  168. package/dist/client/assets/sizeCapture-INFHLROL-FT4z4S1b.js.br +0 -0
  169. package/dist/client/assets/sizeCapture-INFHLROL-FT4z4S1b.js.gz +0 -0
  170. package/dist/client/assets/sparkles-BaGaevME.js +1 -0
  171. package/dist/client/assets/{stateDiagram-D77RDMKH-CiLpGRuf.js → stateDiagram-D77RDMKH-DD0t9f84.js} +1 -1
  172. package/dist/client/assets/stateDiagram-D77RDMKH-DD0t9f84.js.br +0 -0
  173. package/dist/client/assets/stateDiagram-D77RDMKH-DD0t9f84.js.gz +0 -0
  174. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BhvVVB56.js +1 -0
  175. package/dist/client/assets/{swimlanes-42K2YHIH-BkzVtkVY.js → swimlanes-42K2YHIH-DcC8pGLx.js} +1 -1
  176. package/dist/client/assets/swimlanes-42K2YHIH-DcC8pGLx.js.br +0 -0
  177. package/dist/client/assets/swimlanes-42K2YHIH-DcC8pGLx.js.gz +0 -0
  178. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DSC5lz0i.js +8 -0
  179. package/dist/client/assets/{timeline-definition-24CTP7MA-DKyfGITP.js → timeline-definition-24CTP7MA-DnwO_Pxd.js} +1 -1
  180. package/dist/client/assets/timeline-definition-24CTP7MA-DnwO_Pxd.js.br +0 -0
  181. package/dist/client/assets/timeline-definition-24CTP7MA-DnwO_Pxd.js.gz +0 -0
  182. package/dist/client/assets/triangle-alert-BCQO9Ap9.js +1 -0
  183. package/dist/client/assets/{vennDiagram-4TSXK5OY-CRgkkrgx.js → vennDiagram-4TSXK5OY-IVNSrZDM.js} +1 -1
  184. package/dist/client/assets/vennDiagram-4TSXK5OY-IVNSrZDM.js.br +0 -0
  185. package/dist/client/assets/vennDiagram-4TSXK5OY-IVNSrZDM.js.gz +0 -0
  186. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-Cr7yS4CZ.js → wardleyDiagram-VM6X3IG4-BnGetaQL.js} +1 -1
  187. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BnGetaQL.js.br +0 -0
  188. package/dist/client/assets/wardleyDiagram-VM6X3IG4-BnGetaQL.js.gz +0 -0
  189. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DkPYl6E0.js → xychartDiagram-S5SC5T6Z-C01eBN-W.js} +1 -1
  190. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C01eBN-W.js.br +0 -0
  191. package/dist/client/assets/xychartDiagram-S5SC5T6Z-C01eBN-W.js.gz +0 -0
  192. package/dist/client/index.html +2 -2
  193. package/dist/client/index.html.br +0 -0
  194. package/dist/client/index.html.gz +0 -0
  195. package/dist/client/preview-shell.html +1 -0
  196. package/dist/client/preview-shell.js +20 -0
  197. package/dist/client/preview-shell.js.br +0 -0
  198. package/dist/client/preview-shell.js.gz +0 -0
  199. package/dist/client/sw-secure-api.js +132 -0
  200. package/dist/client/sw-secure-api.js.br +0 -0
  201. package/dist/client/sw-secure-api.js.gz +0 -0
  202. package/dist/client/sw.js +1 -1
  203. package/dist/client/sw.js.br +0 -0
  204. package/dist/client/sw.js.gz +0 -0
  205. package/dist/server/agent/collaborationCli.js +298 -0
  206. package/dist/server/agent/collaborationPrompt.js +10 -2
  207. package/dist/server/agent/collaborationProtocol.js +50 -0
  208. package/dist/server/agent/collaborationRoutes.js +86 -0
  209. package/dist/server/agent/collaborationStore.js +249 -21
  210. package/dist/server/cli.js +28 -168
  211. package/dist/server/entry.js +114 -51
  212. package/dist/server/federation/accessPolicy.js +122 -0
  213. package/dist/server/federation/authorization.js +226 -0
  214. package/dist/server/federation/bootstrapCors.js +23 -0
  215. package/dist/server/federation/cli.js +185 -0
  216. package/dist/server/federation/deviceNames.js +29 -0
  217. package/dist/server/federation/directRoutes.js +72 -0
  218. package/dist/server/federation/invitations.js +123 -0
  219. package/dist/server/federation/openAccess.js +25 -0
  220. package/dist/server/federation/originPolicy.js +19 -0
  221. package/dist/server/federation/packets.js +116 -0
  222. package/dist/server/federation/passwordBootstrap.js +86 -0
  223. package/dist/server/federation/passwordLoginRoutes.js +98 -0
  224. package/dist/server/federation/relay.js +346 -0
  225. package/dist/server/federation/requestContext.js +4 -0
  226. package/dist/server/federation/routeAccess.js +124 -0
  227. package/dist/server/federation/routeInvitations.js +160 -0
  228. package/dist/server/federation/runtime.js +537 -0
  229. package/dist/server/federation/secureProtocol.js +223 -0
  230. package/dist/server/federation/socketDuplex.js +42 -0
  231. package/dist/server/federation/streamLimits.js +5 -0
  232. package/dist/server/routes/filesystem.js +2 -1
  233. package/dist/server/routes/terminal.js +40 -72
  234. package/dist/server/utils/authProtection.js +13 -0
  235. package/dist/server/utils/csrfProtection.js +3 -0
  236. package/dist/server/utils/publicSecurity.js +8 -3
  237. package/package.json +10 -3
  238. package/runtime-manifest.json +4 -4
  239. package/dist/client/assets/ChangeWalkthroughPanel-hj8I8Cwy.js +0 -2
  240. package/dist/client/assets/ChangeWalkthroughPanel-hj8I8Cwy.js.br +0 -0
  241. package/dist/client/assets/ChangeWalkthroughPanel-hj8I8Cwy.js.gz +0 -0
  242. package/dist/client/assets/DagPlayground-BRoB8JX5.js +0 -1
  243. package/dist/client/assets/DagPlayground-BRoB8JX5.js.br +0 -0
  244. package/dist/client/assets/DagPlayground-BRoB8JX5.js.gz +0 -0
  245. package/dist/client/assets/DiffLab-CdbPsjKS.js.br +0 -0
  246. package/dist/client/assets/DiffLab-CdbPsjKS.js.gz +0 -0
  247. package/dist/client/assets/DiffReview-MQXjrRsW.js +0 -1
  248. package/dist/client/assets/DiffReview-MQXjrRsW.js.br +0 -0
  249. package/dist/client/assets/DiffReview-MQXjrRsW.js.gz +0 -0
  250. package/dist/client/assets/DiffReviewLab-C47CNvDM.js +0 -2
  251. package/dist/client/assets/DiffReviewLab-C47CNvDM.js.br +0 -0
  252. package/dist/client/assets/DiffReviewLab-C47CNvDM.js.gz +0 -0
  253. package/dist/client/assets/DiffViewer-hdxcM9yF.js.br +0 -0
  254. package/dist/client/assets/DiffViewer-hdxcM9yF.js.gz +0 -0
  255. package/dist/client/assets/ModelPreview-BZ454pgM.js.br +0 -0
  256. package/dist/client/assets/ModelPreview-BZ454pgM.js.gz +0 -0
  257. package/dist/client/assets/RightSidebar-i0Oq68YI.js +0 -55
  258. package/dist/client/assets/RightSidebar-i0Oq68YI.js.br +0 -0
  259. package/dist/client/assets/RightSidebar-i0Oq68YI.js.gz +0 -0
  260. package/dist/client/assets/abnfDiagram-VCTEODGH-C185Omck.js.br +0 -0
  261. package/dist/client/assets/abnfDiagram-VCTEODGH-C185Omck.js.gz +0 -0
  262. package/dist/client/assets/app-DAp8rVMc.js +0 -175
  263. package/dist/client/assets/app-DAp8rVMc.js.br +0 -0
  264. package/dist/client/assets/app-DAp8rVMc.js.gz +0 -0
  265. package/dist/client/assets/arc-DNt-DTCl.js.br +0 -0
  266. package/dist/client/assets/arc-DNt-DTCl.js.gz +0 -0
  267. package/dist/client/assets/architectureDiagram-5GKGNRK7-C5Nwm_Qz.js.br +0 -0
  268. package/dist/client/assets/architectureDiagram-5GKGNRK7-C5Nwm_Qz.js.gz +0 -0
  269. package/dist/client/assets/blockDiagram-I7D4REHJ-C5aR_7V9.js.br +0 -0
  270. package/dist/client/assets/blockDiagram-I7D4REHJ-C5aR_7V9.js.gz +0 -0
  271. package/dist/client/assets/c4Diagram-7LVT6UL2-DjV6ZNwd.js.br +0 -0
  272. package/dist/client/assets/c4Diagram-7LVT6UL2-DjV6ZNwd.js.gz +0 -0
  273. package/dist/client/assets/channel-uhLrATdy.js +0 -1
  274. package/dist/client/assets/chunk-F27PBJKO-DyMNEawE.js.br +0 -0
  275. package/dist/client/assets/chunk-F27PBJKO-DyMNEawE.js.gz +0 -0
  276. package/dist/client/assets/chunk-IMKFNOWR-BsW7iIrh.js.br +0 -0
  277. package/dist/client/assets/chunk-SVP7TREG-CDu41dkj.js.br +0 -0
  278. package/dist/client/assets/chunk-SVP7TREG-CDu41dkj.js.gz +0 -0
  279. package/dist/client/assets/chunk-TICWLB2K-BACjgX9v.js.br +0 -0
  280. package/dist/client/assets/chunk-TICWLB2K-BACjgX9v.js.gz +0 -0
  281. package/dist/client/assets/classDiagram-ZZMXUADV-CnxFfzm9.js +0 -1
  282. package/dist/client/assets/classDiagram-v2-VYDZK3BY-CnxFfzm9.js +0 -1
  283. package/dist/client/assets/cose-bilkent-JH36ORCC-WTwHOCdm.js.br +0 -0
  284. package/dist/client/assets/cose-bilkent-JH36ORCC-WTwHOCdm.js.gz +0 -0
  285. package/dist/client/assets/cynefin-OW5HDTMX-D4y8TkaO.js.br +0 -0
  286. package/dist/client/assets/cynefin-OW5HDTMX-D4y8TkaO.js.gz +0 -0
  287. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BzN8Ggk_.js.br +0 -0
  288. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BzN8Ggk_.js.gz +0 -0
  289. package/dist/client/assets/dagre-GXQ25YYZ-CwMYtt5E.js.br +0 -0
  290. package/dist/client/assets/dagre-GXQ25YYZ-CwMYtt5E.js.gz +0 -0
  291. package/dist/client/assets/diagram-S7CK7UJ4-BnTeHiAb.js.br +0 -0
  292. package/dist/client/assets/diagram-S7CK7UJ4-BnTeHiAb.js.gz +0 -0
  293. package/dist/client/assets/diagram-UQ7AKVKN-BNlh251g.js.br +0 -0
  294. package/dist/client/assets/diagram-UQ7AKVKN-BNlh251g.js.gz +0 -0
  295. package/dist/client/assets/diagram-VSXAHHWV-B5FftXkQ.js.br +0 -0
  296. package/dist/client/assets/diagram-VSXAHHWV-B5FftXkQ.js.gz +0 -0
  297. package/dist/client/assets/diagram-VX7I27RA-C51ZNXR2.js.br +0 -0
  298. package/dist/client/assets/diagram-VX7I27RA-C51ZNXR2.js.gz +0 -0
  299. package/dist/client/assets/diagram-Z3DM3KII-CXoZH2qf.js.br +0 -0
  300. package/dist/client/assets/diagram-Z3DM3KII-CXoZH2qf.js.gz +0 -0
  301. package/dist/client/assets/ebnfDiagram-PWID7BFC-C7YFLlx4.js.br +0 -0
  302. package/dist/client/assets/ebnfDiagram-PWID7BFC-C7YFLlx4.js.gz +0 -0
  303. package/dist/client/assets/erDiagram-RLTQ6QDP-BNQlS7-g.js.br +0 -0
  304. package/dist/client/assets/erDiagram-RLTQ6QDP-BNQlS7-g.js.gz +0 -0
  305. package/dist/client/assets/flowDiagram-HODETNUW-DIQXZ06I.js.br +0 -0
  306. package/dist/client/assets/flowDiagram-HODETNUW-DIQXZ06I.js.gz +0 -0
  307. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BaJQfOqD.js.br +0 -0
  308. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BaJQfOqD.js.gz +0 -0
  309. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-tQ4E6pwN.js.br +0 -0
  310. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-tQ4E6pwN.js.gz +0 -0
  311. package/dist/client/assets/index-DlxiaPv1.css.br +0 -0
  312. package/dist/client/assets/index-DlxiaPv1.css.gz +0 -0
  313. package/dist/client/assets/ishikawaDiagram-5VMMS53U-8sBi-gla.js.gz +0 -0
  314. package/dist/client/assets/journeyDiagram-3NMN7TZE-ZwikziWh.js.br +0 -0
  315. package/dist/client/assets/kanban-definition-UXKFOSKX-wjuw2jQ4.js.br +0 -0
  316. package/dist/client/assets/kanban-definition-UXKFOSKX-wjuw2jQ4.js.gz +0 -0
  317. package/dist/client/assets/layout-nASMIj-E.js.br +0 -0
  318. package/dist/client/assets/layout-nASMIj-E.js.gz +0 -0
  319. package/dist/client/assets/linear-pGaQeqW5.js.br +0 -0
  320. package/dist/client/assets/linear-pGaQeqW5.js.gz +0 -0
  321. package/dist/client/assets/mermaid.core-CKEBWbQz.js.br +0 -0
  322. package/dist/client/assets/mermaid.core-CKEBWbQz.js.gz +0 -0
  323. package/dist/client/assets/mindmap-definition-YA3MSWOX-CBjYcnwd.js.br +0 -0
  324. package/dist/client/assets/mindmap-definition-YA3MSWOX-CBjYcnwd.js.gz +0 -0
  325. package/dist/client/assets/pegDiagram-XKGWAZYB-DJqvclIp.js.br +0 -0
  326. package/dist/client/assets/pegDiagram-XKGWAZYB-DJqvclIp.js.gz +0 -0
  327. package/dist/client/assets/pieDiagram-E7YTZNPT-DLV4WPwc.js.br +0 -0
  328. package/dist/client/assets/pieDiagram-E7YTZNPT-DLV4WPwc.js.gz +0 -0
  329. package/dist/client/assets/quadrantDiagram-AXDQQJYC-BN7Zpsb9.js.br +0 -0
  330. package/dist/client/assets/quadrantDiagram-AXDQQJYC-BN7Zpsb9.js.gz +0 -0
  331. package/dist/client/assets/railroadDiagram-O6MQD6OU-DfHX6MUm.js.br +0 -0
  332. package/dist/client/assets/railroadDiagram-O6MQD6OU-DfHX6MUm.js.gz +0 -0
  333. package/dist/client/assets/requirementDiagram-BXWQKSXE-tQVSFg_k.js.br +0 -0
  334. package/dist/client/assets/requirementDiagram-BXWQKSXE-tQVSFg_k.js.gz +0 -0
  335. package/dist/client/assets/sankeyDiagram-P5KCCOFB-C7JW1-Wh.js.br +0 -0
  336. package/dist/client/assets/sankeyDiagram-P5KCCOFB-C7JW1-Wh.js.gz +0 -0
  337. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BVeDiFDI.js.br +0 -0
  338. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BVeDiFDI.js.gz +0 -0
  339. package/dist/client/assets/sizeCapture-INFHLROL-CBRaCpeP.js.br +0 -0
  340. package/dist/client/assets/sizeCapture-INFHLROL-CBRaCpeP.js.gz +0 -0
  341. package/dist/client/assets/sparkles-D0cwIvB0.js +0 -1
  342. package/dist/client/assets/stateDiagram-D77RDMKH-CiLpGRuf.js.br +0 -0
  343. package/dist/client/assets/stateDiagram-D77RDMKH-CiLpGRuf.js.gz +0 -0
  344. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BRbS0rv2.js +0 -1
  345. package/dist/client/assets/swimlanes-42K2YHIH-BkzVtkVY.js.br +0 -0
  346. package/dist/client/assets/swimlanes-42K2YHIH-BkzVtkVY.js.gz +0 -0
  347. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CeWFezkt.js +0 -8
  348. package/dist/client/assets/timeline-definition-24CTP7MA-DKyfGITP.js.br +0 -0
  349. package/dist/client/assets/timeline-definition-24CTP7MA-DKyfGITP.js.gz +0 -0
  350. package/dist/client/assets/vennDiagram-4TSXK5OY-CRgkkrgx.js.br +0 -0
  351. package/dist/client/assets/vennDiagram-4TSXK5OY-CRgkkrgx.js.gz +0 -0
  352. package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cr7yS4CZ.js.br +0 -0
  353. package/dist/client/assets/wardleyDiagram-VM6X3IG4-Cr7yS4CZ.js.gz +0 -0
  354. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DkPYl6E0.js.br +0 -0
  355. package/dist/client/assets/xychartDiagram-S5SC5T6Z-DkPYl6E0.js.gz +0 -0
@@ -0,0 +1,537 @@
1
+ import { PasswordBootstrapServer } from './passwordBootstrap.js';
2
+ import { DeviceNames } from './deviceNames.js';
3
+ import { createServer } from 'node:http';
4
+ import { randomBytes, timingSafeEqual, randomUUID } from 'node:crypto';
5
+ import { mkdirSync, readFileSync, writeFileSync, chmodSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { EventEmitter } from 'node:events';
8
+ import { createIdentity, importIdentity, exportIdentity, secureConnection } from './secureProtocol.js';
9
+ import { InvitationStore, validateInvitation } from './invitations.js';
10
+ import { AuthorizationStore } from './authorization.js';
11
+ import { resolveAccessRequest, isBusinessApiPath, terminalMessageAction } from './accessPolicy.js';
12
+ import { AsyncQueue, PacketChannel, toBase64, fromBase64 } from './packets.js';
13
+ import { socketDuplex } from './socketDuplex.js';
14
+ import { markEncryptedRequest } from './requestContext.js';
15
+ import { readTerminalHandshakeDimensions } from '../utils/terminalHandshakeDimensions.js';
16
+ import { openAccessAllowed } from './openAccess.js';
17
+ import { isAuthEnabled, getPasswordCredentialFingerprint, getPasswordVerifier, getLoginBlockMs, recordLoginFailure, recordLoginSuccess } from '../utils/authProtection.js';
18
+ import { MAX_OPEN_SECURE_SOCKETS, MAX_SERVER_HTTP_REQUESTS } from './streamLimits.js';
19
+ class LogicalSocket extends EventEmitter {
20
+ channel;
21
+ id;
22
+ canRead;
23
+ OPEN = 1;
24
+ readyState = 1;
25
+ bufferedAmount = 0;
26
+ constructor(channel, id, canRead) {
27
+ super();
28
+ this.channel = channel;
29
+ this.id = id;
30
+ this.canRead = canRead;
31
+ }
32
+ send(data) {
33
+ if (this.readyState !== 1)
34
+ return;
35
+ if (!this.canRead()) {
36
+ this.close(4003, 'Authorization revoked');
37
+ return;
38
+ }
39
+ try {
40
+ this.channel.send({ type: 'ws-data', id: this.id, data });
41
+ }
42
+ catch (error) {
43
+ this.channel.close(error instanceof Error ? error : new Error('Output transport failed'));
44
+ this.close();
45
+ }
46
+ }
47
+ close(code = 1000, reason = '') {
48
+ if (this.readyState !== 1)
49
+ return;
50
+ this.readyState = 3;
51
+ try {
52
+ this.channel.send({ type: 'ws-close', id: this.id, code, reason });
53
+ }
54
+ catch { /* Transport closure must still release backend observers and timers. */ }
55
+ finally {
56
+ this.emit('close');
57
+ }
58
+ }
59
+ }
60
+ /** The internal HTTP listener is private and carries only already-authorized requests.
61
+ * No outer Cookie or origin credential is forwarded across a service boundary. */
62
+ export async function createFederationRuntime(app, directory, handlers, options = {}) {
63
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
64
+ const identityFile = join(directory, 'identity.key');
65
+ let identity;
66
+ try {
67
+ identity = importIdentity(readFileSync(identityFile, 'utf8'));
68
+ chmodSync(identityFile, 0o600);
69
+ }
70
+ catch (error) {
71
+ if (error.code !== 'ENOENT')
72
+ throw error;
73
+ identity = await createIdentity();
74
+ writeFileSync(identityFile, exportIdentity(identity), { mode: 0o600, flag: 'wx' });
75
+ }
76
+ const serviceId = identity.peerId;
77
+ const passwordBootstrap = new PasswordBootstrapServer({ getPasswordHash: getPasswordVerifier, serverIdentity: serviceId });
78
+ let passwordComputing = 0;
79
+ const passwordStarts = [];
80
+ const passwordAttempts = new Map();
81
+ const store = new AuthorizationStore({ serviceId, filePath: join(directory, 'grants.json'), passwordCredential: getPasswordCredentialFingerprint });
82
+ const deviceNames = new DeviceNames(join(directory, 'device-names.json'));
83
+ const invitations = new InvitationStore({ serviceId, filePath: join(directory, 'invitations.json') });
84
+ let pairingCode = randomBytes(32).toString('base64url');
85
+ const savePairing = () => {
86
+ const path = join(directory, 'pairing.json');
87
+ writeFileSync(path, JSON.stringify({ serviceId, pairingCode }, null, 2), { mode: 0o600 });
88
+ chmodSync(path, 0o600);
89
+ };
90
+ savePairing();
91
+ const internalToken = randomBytes(32).toString('base64url');
92
+ const internal = createServer((request, response) => {
93
+ if (request.headers['x-termdock-inner'] !== internalToken) {
94
+ response.writeHead(403).end();
95
+ return;
96
+ }
97
+ delete request.headers['x-termdock-inner'];
98
+ markEncryptedRequest(request);
99
+ app(request, response);
100
+ });
101
+ await new Promise((resolve, reject) => { internal.once('error', reject); internal.listen(0, '127.0.0.1', resolve); });
102
+ const address = internal.address();
103
+ if (!address || typeof address === 'string')
104
+ throw new Error('Internal transport unavailable');
105
+ const baseUrl = `http://127.0.0.1:${address.port}`;
106
+ const channels = new Set();
107
+ let uploadSlots = 0;
108
+ const releaseUpload = (operation) => { if (operation.uploadSlot) {
109
+ operation.uploadSlot = false;
110
+ uploadSlots--;
111
+ } };
112
+ const cancelHttp = (operation) => { operation.abort.abort(); operation.body.end(new Error('CANCELLED')); releaseUpload(operation); };
113
+ async function sessionInventory() {
114
+ const response = await fetch(`${baseUrl}/api/terminal/session-inventory`, { headers: { 'x-termdock-inner': internalToken }, signal: AbortSignal.timeout(10_000) });
115
+ if (!response.ok)
116
+ throw new Error('SESSION_INVENTORY_UNAVAILABLE');
117
+ const inventory = await response.json();
118
+ return Array.isArray(inventory.clientSessions) ? inventory.clientSessions : [];
119
+ }
120
+ async function accept(socket, context = {}) {
121
+ const open = (action) => openAccessAllowed(context.allowOpenAccess === true, isAuthEnabled(), action);
122
+ const allowed = (subjectId, action, sessionId) => open(action) || store.authorize({ subjectId, serviceId, action, sessionId }).allowed;
123
+ const full = (subjectId) => open() || store.hasFullServiceAccess({ subjectId, serviceId });
124
+ let channel;
125
+ const operations = new Map();
126
+ const sockets = new Map();
127
+ let revokeTimer;
128
+ try {
129
+ const secured = await secureConnection({ identity, duplex: socketDuplex(socket), initiator: false, signal: AbortSignal.timeout(15000) });
130
+ const subjectId = secured.authenticatedPeerId;
131
+ channel = new PacketChannel(secured.duplex);
132
+ channels.add(channel);
133
+ const send = (packet) => channel.send(packet);
134
+ const check = (action, sessionId) => { if (!allowed(subjectId, action, sessionId))
135
+ throw new Error('AUTHORIZATION_DENIED'); };
136
+ const httpAllowed = (head) => {
137
+ if (typeof head.method !== 'string' || typeof head.path !== 'string' || !isBusinessApiPath(head.method, head.path))
138
+ throw new Error('API_NOT_ALLOWED');
139
+ const policy = resolveAccessRequest(head.method, head.path);
140
+ if (!full(subjectId)) {
141
+ if (!policy)
142
+ throw new Error('API_NOT_ALLOWED');
143
+ check(policy.action, policy.sessionId);
144
+ }
145
+ };
146
+ async function runHttp(id, operation) {
147
+ const sendHttp = (packet) => {
148
+ if (operations.get(id) !== operation || operation.abort.signal.aborted)
149
+ throw new Error('CANCELLED');
150
+ httpAllowed(operation.head);
151
+ send(packet);
152
+ };
153
+ try {
154
+ httpAllowed(operation.head);
155
+ const headers = new Headers({ 'x-termdock-inner': internalToken });
156
+ const supplied = operation.head.headers;
157
+ if (supplied && typeof supplied === 'object')
158
+ for (const [name, value] of Object.entries(supplied)) {
159
+ if (['content-type', 'accept', 'range', 'if-none-match', 'if-modified-since'].includes(name.toLowerCase()) && typeof value === 'string')
160
+ headers.set(name, value);
161
+ }
162
+ const method = String(operation.head.method);
163
+ async function* uploadBody() {
164
+ for await (const bytes of operation.body) {
165
+ if (operation.abort.signal.aborted)
166
+ throw new Error('CANCELLED');
167
+ httpAllowed(operation.head);
168
+ yield bytes;
169
+ // Undici requests the next chunk only after accepting the previous
170
+ // chunk into its bounded network stream. No whole-body accumulator.
171
+ sendHttp({ type: 'upload-ack', id });
172
+ }
173
+ releaseUpload(operation);
174
+ }
175
+ const request = { method, headers,
176
+ body: ['GET', 'HEAD'].includes(method) ? undefined : uploadBody(),
177
+ duplex: 'half', signal: operation.abort.signal, redirect: 'manual' };
178
+ const response = await fetch(baseUrl + operation.head.path, request);
179
+ if (operation.state !== 'running') {
180
+ await response.body?.cancel();
181
+ throw new Error(`UPLOAD_REJECTED_${response.status}`);
182
+ }
183
+ httpAllowed(operation.head);
184
+ sendHttp({ type: 'head', id, status: response.status, headers: Object.fromEntries([...response.headers].filter(([name]) => !['set-cookie', 'connection', 'transfer-encoding', 'content-encoding', 'content-length'].includes(name))) });
185
+ const reader = response.body?.getReader();
186
+ if (reader)
187
+ while (true) {
188
+ httpAllowed(operation.head);
189
+ const { done, value } = await reader.read();
190
+ if (done)
191
+ break;
192
+ for (let offset = 0; offset < value.length; offset += 65536) {
193
+ httpAllowed(operation.head);
194
+ await new Promise((resolve, reject) => {
195
+ const cleanup = () => { clearTimeout(timeout); operation.abort.signal.removeEventListener('abort', abort); operation.ack = undefined; };
196
+ const timeout = setTimeout(() => { cleanup(); reject(new Error('CONSUMER_TIMEOUT')); }, 30000);
197
+ const abort = () => { cleanup(); reject(new Error('CANCELLED')); };
198
+ operation.abort.signal.addEventListener('abort', abort, { once: true });
199
+ operation.ack = () => { cleanup(); resolve(); };
200
+ if (operation.abort.signal.aborted) {
201
+ abort();
202
+ return;
203
+ }
204
+ try {
205
+ sendHttp({ type: 'chunk', id, data: toBase64(value.subarray(offset, offset + 65536)) });
206
+ }
207
+ catch (error) {
208
+ cleanup();
209
+ reject(error);
210
+ }
211
+ });
212
+ }
213
+ }
214
+ sendHttp({ type: 'end', id });
215
+ }
216
+ catch (error) {
217
+ try {
218
+ if (operations.get(id) === operation)
219
+ send({ type: 'error', id, error: error instanceof Error ? error.message : 'REQUEST_FAILED' });
220
+ }
221
+ catch { /* The encrypted connection has closed. */ }
222
+ }
223
+ finally {
224
+ cancelHttp(operation);
225
+ if (operations.get(id) === operation)
226
+ operations.delete(id);
227
+ }
228
+ }
229
+ revokeTimer = setInterval(() => {
230
+ for (const { socket: logical, sessionId } of sockets.values()) {
231
+ if (!allowed(subjectId, sessionId ? 'session.view' : 'service.view', sessionId))
232
+ logical.close(4003, 'Authorization revoked');
233
+ }
234
+ for (const [id, operation] of operations)
235
+ try {
236
+ httpAllowed(operation.head);
237
+ if (operation.state === 'uploading' && Date.now() - operation.updatedAt > 30_000)
238
+ throw new Error('UPLOAD_TIMEOUT');
239
+ }
240
+ catch {
241
+ cancelHttp(operation);
242
+ if (operation.state === 'uploading')
243
+ operations.delete(id);
244
+ }
245
+ }, 1000);
246
+ for await (const packet of channel.read()) {
247
+ try {
248
+ if (packet.id.length > 128)
249
+ throw new Error('INVALID_ID');
250
+ if (packet.type === 'password-parameters') {
251
+ send({ type: 'result', id: packet.id, ...passwordBootstrap.parameters() });
252
+ }
253
+ else if (packet.type === 'password-start') {
254
+ const now = Date.now(), loginKey = `secure:${subjectId}`;
255
+ while (passwordStarts.length && passwordStarts[0] <= now - 60_000)
256
+ passwordStarts.shift();
257
+ if (getLoginBlockMs(loginKey) || passwordStarts.length >= 30 || passwordComputing >= 2)
258
+ throw new Error('LOGIN_RATE_LIMIT');
259
+ if (typeof packet.startLoginRequest !== 'string' || typeof packet.origin !== 'string')
260
+ throw new Error('INVALID_LOGIN');
261
+ passwordStarts.push(now);
262
+ passwordComputing++;
263
+ recordLoginFailure(loginKey);
264
+ try {
265
+ const result = await passwordBootstrap.start({ startLoginRequest: packet.startLoginRequest, clientIdentity: subjectId, origin: packet.origin });
266
+ if (passwordAttempts.size >= 64)
267
+ passwordAttempts.delete(passwordAttempts.keys().next().value);
268
+ passwordAttempts.set(result.attemptId, subjectId);
269
+ send({ type: 'result', id: packet.id, ...result });
270
+ }
271
+ finally {
272
+ passwordComputing--;
273
+ }
274
+ }
275
+ else if (packet.type === 'password-finish') {
276
+ if (typeof packet.attemptId !== 'string' || typeof packet.finishLoginRequest !== 'string' || passwordAttempts.get(packet.attemptId) !== subjectId)
277
+ throw new Error('INVALID_LOGIN');
278
+ passwordAttempts.delete(packet.attemptId);
279
+ const result = await passwordBootstrap.finish({ attemptId: packet.attemptId, finishLoginRequest: packet.finishLoginRequest });
280
+ if (result.clientIdentity !== subjectId)
281
+ throw new Error('INVALID_LOGIN');
282
+ store.grantPassword(subjectId);
283
+ recordLoginSuccess(`secure:${subjectId}`);
284
+ send({ type: 'result', id: packet.id, ok: true });
285
+ }
286
+ else if (packet.type === 'pair') {
287
+ const supplied = Buffer.from(typeof packet.code === 'string' ? packet.code : '');
288
+ const expected = Buffer.from(pairingCode);
289
+ if (supplied.length === expected.length && timingSafeEqual(supplied, expected)) {
290
+ // Rotate before granting: a persistence failure cannot reuse a bootstrap code.
291
+ pairingCode = randomBytes(32).toString('base64url');
292
+ savePairing();
293
+ store.grant({ subjectId, scope: { kind: 'service' }, actions: ['service:*'], canDelegate: true });
294
+ }
295
+ else {
296
+ const grant = invitations.consume(typeof packet.code === 'string' ? packet.code : '', subjectId, issuer => allowed(issuer, 'authorization.manage'));
297
+ store.grant(grant);
298
+ }
299
+ send({ type: 'result', id: packet.id, serviceId, subjectId });
300
+ }
301
+ else if (packet.type === 'logout') {
302
+ for (const grant of store.list())
303
+ if (grant.subjectId === subjectId)
304
+ store.revoke(grant.id);
305
+ send({ type: 'result', id: packet.id, ok: true });
306
+ }
307
+ else if (packet.type === 'permissions') {
308
+ const grants = store.listEffective({ subjectId, serviceId });
309
+ send({ type: 'result', id: packet.id, subjectId, serviceId, fullService: full(subjectId), grants });
310
+ }
311
+ else if (packet.type === 'session-list') {
312
+ const inventory = await sessionInventory();
313
+ const seen = new Set();
314
+ const items = inventory.flatMap(session => {
315
+ const sessionId = session.backendSessionId;
316
+ if (typeof sessionId !== 'string' || !sessionId || seen.has(sessionId) || !allowed(subjectId, 'session.view', sessionId))
317
+ return [];
318
+ seen.add(sessionId);
319
+ return [{ sessionId, ...(typeof session.sessionId === 'string' ? { sourceSessionId: session.sessionId } : {}),
320
+ name: typeof session.name === 'string' ? session.name : sessionId, live: session.live === true,
321
+ canWrite: allowed(subjectId, 'session.input', sessionId), canResize: allowed(subjectId, 'session.resize', sessionId) }];
322
+ });
323
+ send({ type: 'result', id: packet.id, items });
324
+ }
325
+ else if (packet.type === 'route-invite-create') {
326
+ check('authorization.manage');
327
+ if (!options.createRouteInvitation || typeof packet.serviceId !== 'string' || !packet.serviceId || packet.serviceId.length > 512)
328
+ throw new Error('ROUTE_NOT_AVAILABLE');
329
+ send({ type: 'result', id: packet.id, ...options.createRouteInvitation(subjectId, packet.serviceId) });
330
+ }
331
+ else if (packet.type === 'route-pair') {
332
+ if (!options.consumeRouteInvitation || typeof packet.code !== 'string')
333
+ throw new Error('PAIRING_DENIED');
334
+ send({ type: 'result', id: packet.id, ...options.consumeRouteInvitation(packet.code, subjectId) });
335
+ }
336
+ else if (packet.type === 'route-access') {
337
+ const all = options.listRouteAccess?.() || [];
338
+ const canManage = allowed(subjectId, 'authorization.manage');
339
+ send({ type: 'result', id: packet.id, canManage, grants: canManage ? all : all.filter(grant => grant.subjectId === subjectId) });
340
+ }
341
+ else if (packet.type === 'route-grant') {
342
+ check('authorization.manage');
343
+ if (!options.grantRouteAccess || typeof packet.serviceId !== 'string' || typeof packet.subjectId !== 'string')
344
+ throw new Error('ROUTE_NOT_AVAILABLE');
345
+ send({ type: 'result', id: packet.id, grant: await options.grantRouteAccess(subjectId, packet.serviceId, packet.subjectId, typeof packet.url === 'string' ? packet.url : undefined) });
346
+ }
347
+ else if (packet.type === 'route-revoke') {
348
+ const grant = options.listRouteAccess?.().find(item => item.id === packet.grantId);
349
+ if (!grant || (grant.subjectId !== subjectId && !allowed(subjectId, 'authorization.manage')))
350
+ throw new Error('AUTHORIZATION_DENIED');
351
+ if (!options.revokeRouteAccess || typeof packet.grantId !== 'string')
352
+ throw new Error('ROUTE_NOT_AVAILABLE');
353
+ send({ type: 'result', id: packet.id, revoked: options.revokeRouteAccess(packet.grantId) });
354
+ }
355
+ else if (packet.type === 'route-ticket') {
356
+ if (typeof packet.serviceId !== 'string' || !options.hasRouteGrant?.(subjectId, packet.serviceId))
357
+ throw new Error('AUTHORIZATION_DENIED');
358
+ if (!options.issueRouteTicket || typeof packet.serviceId !== 'string' || !packet.serviceId || packet.serviceId.length > 512)
359
+ throw new Error('ROUTE_NOT_AVAILABLE');
360
+ send({ type: 'result', id: packet.id, ...options.issueRouteTicket(subjectId, packet.serviceId) });
361
+ }
362
+ else if (packet.type === 'invite-create') {
363
+ check('authorization.manage');
364
+ const invitation = { scope: packet.scope, actions: packet.actions,
365
+ ...(packet.label === undefined ? {} : { label: packet.label }),
366
+ ...(packet.expiresAt === undefined ? {} : { expiresAt: packet.expiresAt }) };
367
+ validateInvitation(invitation);
368
+ if (invitation.scope.kind === 'sessions') {
369
+ const known = new Set((await sessionInventory()).filter(session => session.live === true).map(session => session.backendSessionId));
370
+ if (!invitation.scope.sessionIds.every(id => known.has(id)))
371
+ throw new Error('UNKNOWN_SESSION');
372
+ }
373
+ check('authorization.manage');
374
+ send({ type: 'result', id: packet.id, serviceId, ...invitations.create(subjectId, invitation) });
375
+ }
376
+ else if (packet.type === 'device-name') {
377
+ const target = typeof packet.subjectId === 'string' ? packet.subjectId : subjectId;
378
+ if (target !== subjectId)
379
+ check('authorization.manage');
380
+ if (!store.listEffective({ subjectId: target, serviceId }).length && !(target === subjectId && (full(subjectId) || options.listRouteAccess?.().some(grant => grant.subjectId === subjectId && grant.active))))
381
+ throw new Error('AUTHORIZATION_DENIED');
382
+ const existing = invitations.subjectLabels()[target];
383
+ const name = packet.onlyIfMissing === true && existing && !deviceNames.list()[target] ? existing : deviceNames.set(target, packet.name, packet.onlyIfMissing === true);
384
+ send({ type: 'result', id: packet.id, name });
385
+ }
386
+ else if (packet.type === 'grants-list') {
387
+ check('authorization.manage');
388
+ send({ type: 'result', id: packet.id, grants: store.list(), subjectLabels: { ...invitations.subjectLabels(), ...deviceNames.list() } });
389
+ }
390
+ else if (packet.type === 'grant') {
391
+ check('authorization.manage');
392
+ send({ type: 'result', id: packet.id, grant: store.grant(packet.grant) });
393
+ }
394
+ else if (packet.type === 'revoke') {
395
+ check('authorization.manage');
396
+ send({ type: 'result', id: packet.id, revoked: store.revoke(String(packet.grantId)) });
397
+ }
398
+ else if (packet.type === 'delegate') {
399
+ const grant = store.delegate(String(packet.parentGrantId), subjectId, packet.grant);
400
+ send({ type: 'result', id: packet.id, grant });
401
+ }
402
+ else if (packet.type === 'http') {
403
+ if (operations.size >= MAX_SERVER_HTTP_REQUESTS || operations.has(packet.id) || sockets.has(packet.id))
404
+ throw new Error('STREAM_LIMIT');
405
+ httpAllowed(packet);
406
+ const upload = !['GET', 'HEAD'].includes(String(packet.method));
407
+ if (upload && uploadSlots >= 8)
408
+ throw new Error('UPLOAD_CONCURRENCY_LIMIT');
409
+ const operation = { head: packet, body: new AsyncQueue(2), size: 0, abort: new AbortController(), state: 'uploading', updatedAt: Date.now(), uploadSlot: upload };
410
+ if (upload)
411
+ uploadSlots++;
412
+ operations.set(packet.id, operation);
413
+ if (upload)
414
+ void runHttp(packet.id, operation);
415
+ }
416
+ else if (packet.type === 'upload') {
417
+ const operation = operations.get(packet.id);
418
+ if (!operation || operation.state !== 'uploading' || typeof packet.data !== 'string')
419
+ throw new Error('INVALID_UPLOAD');
420
+ httpAllowed(operation.head);
421
+ const bytes = fromBase64(packet.data);
422
+ operation.size += bytes.length;
423
+ const limit = new URL(String(operation.head.path), 'http://inner').pathname === '/api/terminal/fs/upload' ? 110 * 1024 * 1024 : 5 * 1024 * 1024;
424
+ if (['GET', 'HEAD'].includes(String(operation.head.method)) || bytes.length > 65536 || operation.size > limit) {
425
+ cancelHttp(operation);
426
+ operations.delete(packet.id);
427
+ throw new Error('UPLOAD_LIMIT');
428
+ }
429
+ operation.updatedAt = Date.now();
430
+ try {
431
+ operation.body.push(bytes);
432
+ }
433
+ catch {
434
+ cancelHttp(operation);
435
+ operations.delete(packet.id);
436
+ throw new Error('UPLOAD_QUEUE_LIMIT');
437
+ }
438
+ }
439
+ else if (packet.type === 'upload-end') {
440
+ const operation = operations.get(packet.id);
441
+ if (!operation || operation.state !== 'uploading')
442
+ throw new Error('INVALID_STREAM');
443
+ operation.state = 'running';
444
+ operation.body.end();
445
+ if (['GET', 'HEAD'].includes(String(operation.head.method)))
446
+ void runHttp(packet.id, operation);
447
+ }
448
+ else if (packet.type === 'ack') {
449
+ const operation = operations.get(packet.id);
450
+ operation?.ack?.();
451
+ if (operation)
452
+ operation.ack = undefined;
453
+ }
454
+ else if (packet.type === 'cancel') {
455
+ const operation = operations.get(packet.id);
456
+ if (operation)
457
+ cancelHttp(operation);
458
+ operations.delete(packet.id);
459
+ }
460
+ else if (packet.type === 'ws-open') {
461
+ if (sockets.size >= MAX_OPEN_SECURE_SOCKETS || operations.has(packet.id) || sockets.has(packet.id))
462
+ throw new Error('STREAM_LIMIT');
463
+ if (typeof packet.path !== 'string' || !isBusinessApiPath('GET', packet.path))
464
+ throw new Error('API_NOT_ALLOWED');
465
+ const url = new URL(packet.path, 'http://inner');
466
+ const match = /^\/api\/terminal\/([^/%]+)\/ws$/.exec(url.pathname);
467
+ if (match)
468
+ check('session.view', match[1]);
469
+ else if (url.pathname === '/api/control/ws')
470
+ check('service.view');
471
+ else
472
+ throw new Error('API_NOT_ALLOWED');
473
+ const logical = new LogicalSocket(channel, packet.id, () => allowed(subjectId, match ? 'session.view' : 'service.view', match?.[1]));
474
+ sockets.set(packet.id, { socket: logical, sessionId: match?.[1] });
475
+ logical.once('close', () => sockets.delete(packet.id));
476
+ send({ type: 'ws-ready', id: packet.id });
477
+ if (match)
478
+ handlers.terminal(logical, match[1], randomUUID(), {
479
+ sinceSeq: Math.max(0, Number(url.searchParams.get('since')) || 0), streamEpoch: url.searchParams.get('epoch') ?? undefined,
480
+ flowControl: url.searchParams.get('flow') === '2', outputActive: url.searchParams.get('active') !== '0',
481
+ independentTmux: full(subjectId) && url.searchParams.get('transport') === 'tmux-client',
482
+ }, allowed(subjectId, 'session.resize', match[1]) ? readTerminalHandshakeDimensions(url.searchParams) : undefined);
483
+ else
484
+ handlers.control(logical, randomUUID());
485
+ }
486
+ else if (packet.type === 'ws-data') {
487
+ const item = sockets.get(packet.id);
488
+ if (!item || typeof packet.data !== 'string')
489
+ throw new Error('INVALID_STREAM');
490
+ const data = JSON.parse(packet.data);
491
+ if (item.sessionId) {
492
+ const action = terminalMessageAction(data.type);
493
+ if (!action)
494
+ throw new Error('ACTION_NOT_ALLOWED');
495
+ check(action, action.startsWith('session.') ? item.sessionId : undefined);
496
+ }
497
+ else {
498
+ check('service.view');
499
+ if (data?.type !== 'pong')
500
+ throw new Error('ACTION_NOT_ALLOWED');
501
+ }
502
+ item.socket.emit('message', Buffer.from(packet.data));
503
+ }
504
+ else if (packet.type === 'ws-close')
505
+ sockets.get(packet.id)?.socket.close();
506
+ else
507
+ throw new Error('UNKNOWN_PACKET');
508
+ }
509
+ catch (error) {
510
+ send({ type: 'error', id: packet.id, error: error instanceof Error ? error.message : 'REQUEST_FAILED' });
511
+ }
512
+ }
513
+ }
514
+ catch {
515
+ socket.close(4003, 'Secure channel closed');
516
+ }
517
+ finally {
518
+ clearInterval(revokeTimer);
519
+ for (const operation of operations.values())
520
+ cancelHttp(operation);
521
+ for (const { socket: logical } of sockets.values()) {
522
+ try {
523
+ logical.close();
524
+ }
525
+ catch {
526
+ logical.emit('close');
527
+ }
528
+ }
529
+ if (channel) {
530
+ channels.delete(channel);
531
+ channel.close();
532
+ }
533
+ }
534
+ }
535
+ return { serviceId, store, accept, close() { for (const channel of channels)
536
+ channel.close(); internal.close(); } };
537
+ }