termdock 1.4.341 → 1.4.342

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 (352) hide show
  1. package/THIRD_PARTY_NOTICES.md +79 -0
  2. package/dist/client/assets/App-DuWNc_Sd.js +187 -0
  3. package/dist/client/assets/App-DuWNc_Sd.js.br +0 -0
  4. package/dist/client/assets/App-DuWNc_Sd.js.gz +0 -0
  5. package/dist/client/assets/{ArchitecturePanel-Dz0hgSdw.js → ArchitecturePanel-Bjhd5uMf.js} +2 -2
  6. package/dist/client/assets/ArchitecturePanel-Bjhd5uMf.js.br +0 -0
  7. package/dist/client/assets/ArchitecturePanel-Bjhd5uMf.js.gz +0 -0
  8. package/dist/client/assets/{ChangeWalkthroughPanel-3PpmA31G.js → ChangeWalkthroughPanel-DKDNcKro.js} +1 -1
  9. package/dist/client/assets/ChangeWalkthroughPanel-DKDNcKro.js.br +0 -0
  10. package/dist/client/assets/ChangeWalkthroughPanel-DKDNcKro.js.gz +0 -0
  11. package/dist/client/assets/{CollaborationMainWorkspace-QA7cyrcg.js → CollaborationMainWorkspace-C11Rr6yD.js} +1 -1
  12. package/dist/client/assets/CollaborationMainWorkspace-C11Rr6yD.js.br +0 -0
  13. package/dist/client/assets/CollaborationMainWorkspace-C11Rr6yD.js.gz +0 -0
  14. package/dist/client/assets/CollaborationTaskContent-DNRyAkOX.js +2 -0
  15. package/dist/client/assets/{ComputerControlView-DfKdSvrs.js → ComputerControlView-B5C6ETMh.js} +3 -3
  16. package/dist/client/assets/ComputerControlView-B5C6ETMh.js.br +0 -0
  17. package/dist/client/assets/ComputerControlView-B5C6ETMh.js.gz +0 -0
  18. package/dist/client/assets/{DagPlayground-IFr1ujrl.js → DagPlayground-BrrzhUzm.js} +1 -1
  19. package/dist/client/assets/DagPlayground-BrrzhUzm.js.br +0 -0
  20. package/dist/client/assets/DagPlayground-BrrzhUzm.js.gz +0 -0
  21. package/dist/client/assets/{DiffLab-BSQmv0td.js → DiffLab-DdFwfYKr.js} +1 -1
  22. package/dist/client/assets/DiffLab-DdFwfYKr.js.br +0 -0
  23. package/dist/client/assets/DiffLab-DdFwfYKr.js.gz +0 -0
  24. package/dist/client/assets/{DiffReview-CfHl0jeF.js → DiffReview-GloQdQAq.js} +1 -1
  25. package/dist/client/assets/DiffReview-GloQdQAq.js.br +0 -0
  26. package/dist/client/assets/DiffReview-GloQdQAq.js.gz +0 -0
  27. package/dist/client/assets/{DiffReviewLab-B_zSSqde.js → DiffReviewLab-C5_nDmPj.js} +1 -1
  28. package/dist/client/assets/DiffReviewLab-C5_nDmPj.js.br +0 -0
  29. package/dist/client/assets/DiffReviewLab-C5_nDmPj.js.gz +0 -0
  30. package/dist/client/assets/{DiffViewer-DORR0BUb.js → DiffViewer-lsURzN_a.js} +1 -1
  31. package/dist/client/assets/DiffViewer-lsURzN_a.js.br +0 -0
  32. package/dist/client/assets/DiffViewer-lsURzN_a.js.gz +0 -0
  33. package/dist/client/assets/{ModelPreview-QdScJljR.js → ModelPreview-Dha8K529.js} +1 -1
  34. package/dist/client/assets/ModelPreview-Dha8K529.js.br +0 -0
  35. package/dist/client/assets/ModelPreview-Dha8K529.js.gz +0 -0
  36. package/dist/client/assets/{RightSidebar-nUsJCrB9.js → RightSidebar-DFWCFBCy.js} +3 -3
  37. package/dist/client/assets/RightSidebar-DFWCFBCy.js.br +0 -0
  38. package/dist/client/assets/RightSidebar-DFWCFBCy.js.gz +0 -0
  39. package/dist/client/assets/{abnfDiagram-VCTEODGH-B51uxXBg.js → abnfDiagram-VCTEODGH-3R9vxuaa.js} +1 -1
  40. package/dist/client/assets/abnfDiagram-VCTEODGH-3R9vxuaa.js.br +0 -0
  41. package/dist/client/assets/abnfDiagram-VCTEODGH-3R9vxuaa.js.gz +0 -0
  42. package/dist/client/assets/app-By1Q_guu.js +35 -0
  43. package/dist/client/assets/app-By1Q_guu.js.br +0 -0
  44. package/dist/client/assets/app-By1Q_guu.js.gz +0 -0
  45. package/dist/client/assets/{arc-Bkn10vSK.js → arc-BRSYFA6a.js} +1 -1
  46. package/dist/client/assets/arc-BRSYFA6a.js.br +0 -0
  47. package/dist/client/assets/arc-BRSYFA6a.js.gz +0 -0
  48. package/dist/client/assets/{architectureDiagram-5GKGNRK7-CK-cIr48.js → architectureDiagram-5GKGNRK7-DU21Xuxy.js} +1 -1
  49. package/dist/client/assets/architectureDiagram-5GKGNRK7-DU21Xuxy.js.br +0 -0
  50. package/dist/client/assets/architectureDiagram-5GKGNRK7-DU21Xuxy.js.gz +0 -0
  51. package/dist/client/assets/{blockDiagram-I7D4REHJ-DzbWXcDy.js → blockDiagram-I7D4REHJ-B8aQKSok.js} +1 -1
  52. package/dist/client/assets/blockDiagram-I7D4REHJ-B8aQKSok.js.br +0 -0
  53. package/dist/client/assets/blockDiagram-I7D4REHJ-B8aQKSok.js.gz +0 -0
  54. package/dist/client/assets/{c4Diagram-7LVT6UL2-rbi8aUz6.js → c4Diagram-7LVT6UL2-CSoL6w1j.js} +1 -1
  55. package/dist/client/assets/c4Diagram-7LVT6UL2-CSoL6w1j.js.br +0 -0
  56. package/dist/client/assets/c4Diagram-7LVT6UL2-CSoL6w1j.js.gz +0 -0
  57. package/dist/client/assets/channel-CQrgntwz.js +1 -0
  58. package/dist/client/assets/{chunk-2Q5K7J3B-CopzhZr-.js → chunk-2Q5K7J3B-BdEnYHBX.js} +1 -1
  59. package/dist/client/assets/{chunk-5VM5RSS4-ClLaQzHk.js → chunk-5VM5RSS4-p7idUc56.js} +1 -1
  60. package/dist/client/assets/{chunk-F27PBJKO-BSC7rK0l.js → chunk-F27PBJKO-C-jRH04G.js} +1 -1
  61. package/dist/client/assets/chunk-F27PBJKO-C-jRH04G.js.br +0 -0
  62. package/dist/client/assets/chunk-F27PBJKO-C-jRH04G.js.gz +0 -0
  63. package/dist/client/assets/{chunk-IMKFNOWR-B2VXoEhN.js → chunk-IMKFNOWR-D_GfyMqI.js} +1 -1
  64. package/dist/client/assets/chunk-IMKFNOWR-D_GfyMqI.js.br +0 -0
  65. package/dist/client/assets/chunk-IMKFNOWR-D_GfyMqI.js.gz +0 -0
  66. package/dist/client/assets/{chunk-JWPE2WC7-BqOinZdA.js → chunk-JWPE2WC7-C_tTJeyp.js} +1 -1
  67. package/dist/client/assets/{chunk-POPQ4Y6H-CNE45B-7.js → chunk-POPQ4Y6H-B7jDpCMg.js} +1 -1
  68. package/dist/client/assets/{chunk-SVP7TREG-f0h2wclt.js → chunk-SVP7TREG-D2bP2OpS.js} +1 -1
  69. package/dist/client/assets/chunk-SVP7TREG-D2bP2OpS.js.br +0 -0
  70. package/dist/client/assets/chunk-SVP7TREG-D2bP2OpS.js.gz +0 -0
  71. package/dist/client/assets/{chunk-TICWLB2K-BLYE27kR.js → chunk-TICWLB2K-BCmzEINw.js} +1 -1
  72. package/dist/client/assets/chunk-TICWLB2K-BCmzEINw.js.br +0 -0
  73. package/dist/client/assets/chunk-TICWLB2K-BCmzEINw.js.gz +0 -0
  74. package/dist/client/assets/{chunk-XXDRQBXY-CVDDfXPc.js → chunk-XXDRQBXY-CU7zj0sD.js} +1 -1
  75. package/dist/client/assets/classDiagram-ZZMXUADV-S0RVBlYQ.js +1 -0
  76. package/dist/client/assets/classDiagram-v2-VYDZK3BY-S0RVBlYQ.js +1 -0
  77. package/dist/client/assets/{cose-bilkent-JH36ORCC-64n9-rjs.js → cose-bilkent-JH36ORCC-Cc6zJb8W.js} +1 -1
  78. package/dist/client/assets/cose-bilkent-JH36ORCC-Cc6zJb8W.js.br +0 -0
  79. package/dist/client/assets/cose-bilkent-JH36ORCC-Cc6zJb8W.js.gz +0 -0
  80. package/dist/client/assets/{cynefin-OW5HDTMX-BQu4qBBj.js → cynefin-OW5HDTMX-Dx8-oZ-5.js} +1 -1
  81. package/dist/client/assets/cynefin-OW5HDTMX-Dx8-oZ-5.js.br +0 -0
  82. package/dist/client/assets/{cynefin-OW5HDTMX-BQu4qBBj.js.gz → cynefin-OW5HDTMX-Dx8-oZ-5.js.gz} +0 -0
  83. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-BnwaLoUi.js → cynefinDiagram-5FMLGOSQ-D8w9AR9E.js} +1 -1
  84. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-D8w9AR9E.js.br +0 -0
  85. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-D8w9AR9E.js.gz +0 -0
  86. package/dist/client/assets/{dagre-GXQ25YYZ-CqFJh0CI.js → dagre-GXQ25YYZ-DWu5zqlw.js} +1 -1
  87. package/dist/client/assets/dagre-GXQ25YYZ-DWu5zqlw.js.br +0 -0
  88. package/dist/client/assets/dagre-GXQ25YYZ-DWu5zqlw.js.gz +0 -0
  89. package/dist/client/assets/{diagram-S7CK7UJ4-CbPoBysM.js → diagram-S7CK7UJ4-C8P4HVUJ.js} +1 -1
  90. package/dist/client/assets/diagram-S7CK7UJ4-C8P4HVUJ.js.br +0 -0
  91. package/dist/client/assets/diagram-S7CK7UJ4-C8P4HVUJ.js.gz +0 -0
  92. package/dist/client/assets/{diagram-UQ7AKVKN-BhBN4F33.js → diagram-UQ7AKVKN-B_7uz1pF.js} +1 -1
  93. package/dist/client/assets/diagram-UQ7AKVKN-B_7uz1pF.js.br +0 -0
  94. package/dist/client/assets/diagram-UQ7AKVKN-B_7uz1pF.js.gz +0 -0
  95. package/dist/client/assets/{diagram-VSXAHHWV-eYeeGcK9.js → diagram-VSXAHHWV-CtUxXdZO.js} +1 -1
  96. package/dist/client/assets/diagram-VSXAHHWV-CtUxXdZO.js.br +0 -0
  97. package/dist/client/assets/diagram-VSXAHHWV-CtUxXdZO.js.gz +0 -0
  98. package/dist/client/assets/{diagram-VX7I27RA-BJzhPV4h.js → diagram-VX7I27RA-qu13Uscy.js} +1 -1
  99. package/dist/client/assets/diagram-VX7I27RA-qu13Uscy.js.br +0 -0
  100. package/dist/client/assets/diagram-VX7I27RA-qu13Uscy.js.gz +0 -0
  101. package/dist/client/assets/{diagram-Z3DM3KII-CnjpNAJH.js → diagram-Z3DM3KII-CBK_SCwI.js} +1 -1
  102. package/dist/client/assets/diagram-Z3DM3KII-CBK_SCwI.js.br +0 -0
  103. package/dist/client/assets/diagram-Z3DM3KII-CBK_SCwI.js.gz +0 -0
  104. package/dist/client/assets/{ebnfDiagram-PWID7BFC-BSJQBTtu.js → ebnfDiagram-PWID7BFC-WO-4_pvg.js} +1 -1
  105. package/dist/client/assets/ebnfDiagram-PWID7BFC-WO-4_pvg.js.br +0 -0
  106. package/dist/client/assets/ebnfDiagram-PWID7BFC-WO-4_pvg.js.gz +0 -0
  107. package/dist/client/assets/{erDiagram-RLTQ6QDP-DJ-J9MxE.js → erDiagram-RLTQ6QDP-CJBTe-Vf.js} +1 -1
  108. package/dist/client/assets/erDiagram-RLTQ6QDP-CJBTe-Vf.js.br +0 -0
  109. package/dist/client/assets/erDiagram-RLTQ6QDP-CJBTe-Vf.js.gz +0 -0
  110. package/dist/client/assets/{flowDiagram-HODETNUW-BoQNTthC.js → flowDiagram-HODETNUW-BMB8WufZ.js} +1 -1
  111. package/dist/client/assets/flowDiagram-HODETNUW-BMB8WufZ.js.br +0 -0
  112. package/dist/client/assets/flowDiagram-HODETNUW-BMB8WufZ.js.gz +0 -0
  113. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-CFE98nzY.js → ganttDiagram-EL5Y4UJY-UU86YYND.js} +1 -1
  114. package/dist/client/assets/ganttDiagram-EL5Y4UJY-UU86YYND.js.br +0 -0
  115. package/dist/client/assets/ganttDiagram-EL5Y4UJY-UU86YYND.js.gz +0 -0
  116. package/dist/client/assets/{gestureArbiter-C_3fpCXt.js → gestureArbiter-B1YQAqce.js} +1 -1
  117. package/dist/client/assets/gestureArbiter-B1YQAqce.js.br +0 -0
  118. package/dist/client/assets/gestureArbiter-B1YQAqce.js.gz +0 -0
  119. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-DxJzGDIE.js → gitGraphDiagram-WWUBYQGX-C_bQTzYa.js} +1 -1
  120. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C_bQTzYa.js.br +0 -0
  121. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-C_bQTzYa.js.gz +0 -0
  122. package/dist/client/assets/{infoDiagram-27XIBGKW-BZk87iJj.js → infoDiagram-27XIBGKW-D-UPLFB4.js} +1 -1
  123. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-DVsj1R9s.js → ishikawaDiagram-5VMMS53U-BoXlttHi.js} +1 -1
  124. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BoXlttHi.js.br +0 -0
  125. package/dist/client/assets/ishikawaDiagram-5VMMS53U-BoXlttHi.js.gz +0 -0
  126. package/dist/client/assets/{journeyDiagram-3NMN7TZE-BAB2AWNl.js → journeyDiagram-3NMN7TZE-CFFrNcIl.js} +1 -1
  127. package/dist/client/assets/journeyDiagram-3NMN7TZE-CFFrNcIl.js.br +0 -0
  128. package/dist/client/assets/journeyDiagram-3NMN7TZE-CFFrNcIl.js.gz +0 -0
  129. package/dist/client/assets/{kanban-definition-UXKFOSKX-HPNzrFVI.js → kanban-definition-UXKFOSKX-CVGuqvHc.js} +1 -1
  130. package/dist/client/assets/kanban-definition-UXKFOSKX-CVGuqvHc.js.br +0 -0
  131. package/dist/client/assets/kanban-definition-UXKFOSKX-CVGuqvHc.js.gz +0 -0
  132. package/dist/client/assets/{layout-bA7IPCWx.js → layout-3D_JBmoW.js} +1 -1
  133. package/dist/client/assets/layout-3D_JBmoW.js.br +0 -0
  134. package/dist/client/assets/layout-3D_JBmoW.js.gz +0 -0
  135. package/dist/client/assets/{linear-Cd102271.js → linear-DSCyDRIV.js} +1 -1
  136. package/dist/client/assets/linear-DSCyDRIV.js.br +0 -0
  137. package/dist/client/assets/linear-DSCyDRIV.js.gz +0 -0
  138. package/dist/client/assets/{mermaid.core-C4wd6qUT.js → mermaid.core-DmLvRjSp.js} +5 -5
  139. package/dist/client/assets/mermaid.core-DmLvRjSp.js.br +0 -0
  140. package/dist/client/assets/mermaid.core-DmLvRjSp.js.gz +0 -0
  141. package/dist/client/assets/{mindmap-definition-YA3MSWOX-DMxZDI3z.js → mindmap-definition-YA3MSWOX-D-Doz5kr.js} +1 -1
  142. package/dist/client/assets/mindmap-definition-YA3MSWOX-D-Doz5kr.js.br +0 -0
  143. package/dist/client/assets/mindmap-definition-YA3MSWOX-D-Doz5kr.js.gz +0 -0
  144. package/dist/client/assets/{passwordBootstrap-aU8HdPsL.js → passwordBootstrap-DzqP6851.js} +1 -1
  145. package/dist/client/assets/passwordBootstrap-DzqP6851.js.br +0 -0
  146. package/dist/client/assets/passwordBootstrap-DzqP6851.js.gz +0 -0
  147. package/dist/client/assets/{pegDiagram-XKGWAZYB-BliPfrj_.js → pegDiagram-XKGWAZYB-jqnn8PjR.js} +1 -1
  148. package/dist/client/assets/pegDiagram-XKGWAZYB-jqnn8PjR.js.br +0 -0
  149. package/dist/client/assets/pegDiagram-XKGWAZYB-jqnn8PjR.js.gz +0 -0
  150. package/dist/client/assets/{pieDiagram-E7YTZNPT-esWyI6AY.js → pieDiagram-E7YTZNPT-D4MedGxH.js} +1 -1
  151. package/dist/client/assets/pieDiagram-E7YTZNPT-D4MedGxH.js.br +0 -0
  152. package/dist/client/assets/pieDiagram-E7YTZNPT-D4MedGxH.js.gz +0 -0
  153. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-CBoaEIHy.js → quadrantDiagram-AXDQQJYC-C4lTdb_9.js} +1 -1
  154. package/dist/client/assets/quadrantDiagram-AXDQQJYC-C4lTdb_9.js.br +0 -0
  155. package/dist/client/assets/quadrantDiagram-AXDQQJYC-C4lTdb_9.js.gz +0 -0
  156. package/dist/client/assets/{railroadDiagram-O6MQD6OU-FB5bPmYm.js → railroadDiagram-O6MQD6OU-KLdIDLQO.js} +1 -1
  157. package/dist/client/assets/railroadDiagram-O6MQD6OU-KLdIDLQO.js.br +0 -0
  158. package/dist/client/assets/railroadDiagram-O6MQD6OU-KLdIDLQO.js.gz +0 -0
  159. package/dist/client/assets/{rdpSession-DnBdxkm1.js → rdpSession-QckpThDq.js} +1 -1
  160. package/dist/client/assets/rdpSession-QckpThDq.js.br +0 -0
  161. package/dist/client/assets/rdpSession-QckpThDq.js.gz +0 -0
  162. package/dist/client/assets/{referenceLongPress-DDmic9E5.js → referenceLongPress-ErqUYlIw.js} +1 -1
  163. package/dist/client/assets/referenceLongPress-ErqUYlIw.js.br +0 -0
  164. package/dist/client/assets/referenceLongPress-ErqUYlIw.js.gz +0 -0
  165. package/dist/client/assets/{requirementDiagram-BXWQKSXE-CpokwhJY.js → requirementDiagram-BXWQKSXE-BEeCbvLt.js} +1 -1
  166. package/dist/client/assets/requirementDiagram-BXWQKSXE-BEeCbvLt.js.br +0 -0
  167. package/dist/client/assets/requirementDiagram-BXWQKSXE-BEeCbvLt.js.gz +0 -0
  168. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DXQDOMAh.js → sankeyDiagram-P5KCCOFB-DD7In9QJ.js} +1 -1
  169. package/dist/client/assets/sankeyDiagram-P5KCCOFB-DD7In9QJ.js.br +0 -0
  170. package/dist/client/assets/sankeyDiagram-P5KCCOFB-DD7In9QJ.js.gz +0 -0
  171. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-Dn3ZooAM.js → sequenceDiagram-WJ2MYXX4-BCeJR1Wm.js} +1 -1
  172. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BCeJR1Wm.js.br +0 -0
  173. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-BCeJR1Wm.js.gz +0 -0
  174. package/dist/client/assets/{sizeCapture-INFHLROL-PItE9Y1o.js → sizeCapture-INFHLROL-DO250O3y.js} +1 -1
  175. package/dist/client/assets/sizeCapture-INFHLROL-DO250O3y.js.br +0 -0
  176. package/dist/client/assets/sizeCapture-INFHLROL-DO250O3y.js.gz +0 -0
  177. package/dist/client/assets/{sparkles-BwY5qEOv.js → sparkles-DiUUcfQp.js} +1 -1
  178. package/dist/client/assets/{stateDiagram-D77RDMKH-BBZ01SXU.js → stateDiagram-D77RDMKH-j-Rx3MIu.js} +1 -1
  179. package/dist/client/assets/stateDiagram-D77RDMKH-j-Rx3MIu.js.br +0 -0
  180. package/dist/client/assets/stateDiagram-D77RDMKH-j-Rx3MIu.js.gz +0 -0
  181. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-80TmHBA3.js +1 -0
  182. package/dist/client/assets/{swimlanes-42K2YHIH-BY8IlbkR.js → swimlanes-42K2YHIH-D8BxfTs0.js} +1 -1
  183. package/dist/client/assets/swimlanes-42K2YHIH-D8BxfTs0.js.br +0 -0
  184. package/dist/client/assets/{swimlanes-42K2YHIH-BY8IlbkR.js.gz → swimlanes-42K2YHIH-D8BxfTs0.js.gz} +0 -0
  185. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-CDwZ9Ews.js +8 -0
  186. package/dist/client/assets/{timeline-definition-24CTP7MA-DyY9g2Hx.js → timeline-definition-24CTP7MA-Q26Gi8XT.js} +1 -1
  187. package/dist/client/assets/timeline-definition-24CTP7MA-Q26Gi8XT.js.br +0 -0
  188. package/dist/client/assets/timeline-definition-24CTP7MA-Q26Gi8XT.js.gz +0 -0
  189. package/dist/client/assets/{triangle-alert-qb3d0Svx.js → triangle-alert-B3htKRDS.js} +1 -1
  190. package/dist/client/assets/{vennDiagram-4TSXK5OY-Dy0PQ4-U.js → vennDiagram-4TSXK5OY-QCEPdOun.js} +1 -1
  191. package/dist/client/assets/vennDiagram-4TSXK5OY-QCEPdOun.js.br +0 -0
  192. package/dist/client/assets/vennDiagram-4TSXK5OY-QCEPdOun.js.gz +0 -0
  193. package/dist/client/assets/{videoCompression-BDNHhfKS.js → videoCompression-DomMr6dv.js} +1 -1
  194. package/dist/client/assets/videoCompression-DomMr6dv.js.br +0 -0
  195. package/dist/client/assets/videoCompression-DomMr6dv.js.gz +0 -0
  196. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-DtBEPD3N.js → wardleyDiagram-VM6X3IG4-B6J6Og35.js} +1 -1
  197. package/dist/client/assets/wardleyDiagram-VM6X3IG4-B6J6Og35.js.br +0 -0
  198. package/dist/client/assets/wardleyDiagram-VM6X3IG4-B6J6Og35.js.gz +0 -0
  199. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-B2K1XjDQ.js → xychartDiagram-S5SC5T6Z-pdImapP4.js} +1 -1
  200. package/dist/client/assets/xychartDiagram-S5SC5T6Z-pdImapP4.js.br +0 -0
  201. package/dist/client/assets/xychartDiagram-S5SC5T6Z-pdImapP4.js.gz +0 -0
  202. package/dist/client/index.html +1 -1
  203. package/dist/client/index.html.br +0 -0
  204. package/dist/client/index.html.gz +0 -0
  205. package/dist/client/sw-encrypted-background.js +1 -1
  206. package/dist/client/sw-encrypted-background.js.br +0 -0
  207. package/dist/client/sw-encrypted-background.js.gz +0 -0
  208. package/dist/client/sw.js +1 -1
  209. package/dist/client/sw.js.br +0 -0
  210. package/dist/client/sw.js.gz +0 -0
  211. package/dist/server/entry.js +29 -20
  212. package/dist/server/federation/binaryPacket.js +28 -0
  213. package/dist/server/federation/packets.js +53 -7
  214. package/dist/server/federation/recordCompression.js +59 -0
  215. package/dist/server/federation/runtime.js +35 -37
  216. package/dist/server/federation/streamDuplex.js +62 -0
  217. package/dist/server/federation/transferWindow.js +50 -0
  218. package/dist/server/federation/webTransportCertificate.js +52 -0
  219. package/dist/server/federation/webTransportProtocol.js +25 -0
  220. package/dist/server/federation/webTransportServer.js +142 -0
  221. package/package.json +7 -1
  222. package/runtime-manifest.json +4 -4
  223. package/dist/client/assets/App-Bs90VDwF.js +0 -187
  224. package/dist/client/assets/App-Bs90VDwF.js.br +0 -0
  225. package/dist/client/assets/App-Bs90VDwF.js.gz +0 -0
  226. package/dist/client/assets/ArchitecturePanel-Dz0hgSdw.js.br +0 -0
  227. package/dist/client/assets/ArchitecturePanel-Dz0hgSdw.js.gz +0 -0
  228. package/dist/client/assets/ChangeWalkthroughPanel-3PpmA31G.js.br +0 -0
  229. package/dist/client/assets/ChangeWalkthroughPanel-3PpmA31G.js.gz +0 -0
  230. package/dist/client/assets/CollaborationMainWorkspace-QA7cyrcg.js.br +0 -0
  231. package/dist/client/assets/CollaborationMainWorkspace-QA7cyrcg.js.gz +0 -0
  232. package/dist/client/assets/CollaborationTaskContent-Bjkxb7UF.js +0 -2
  233. package/dist/client/assets/ComputerControlView-DfKdSvrs.js.br +0 -0
  234. package/dist/client/assets/ComputerControlView-DfKdSvrs.js.gz +0 -0
  235. package/dist/client/assets/DagPlayground-IFr1ujrl.js.br +0 -0
  236. package/dist/client/assets/DagPlayground-IFr1ujrl.js.gz +0 -0
  237. package/dist/client/assets/DiffLab-BSQmv0td.js.br +0 -0
  238. package/dist/client/assets/DiffLab-BSQmv0td.js.gz +0 -0
  239. package/dist/client/assets/DiffReview-CfHl0jeF.js.br +0 -0
  240. package/dist/client/assets/DiffReview-CfHl0jeF.js.gz +0 -0
  241. package/dist/client/assets/DiffReviewLab-B_zSSqde.js.br +0 -0
  242. package/dist/client/assets/DiffReviewLab-B_zSSqde.js.gz +0 -0
  243. package/dist/client/assets/DiffViewer-DORR0BUb.js.br +0 -0
  244. package/dist/client/assets/DiffViewer-DORR0BUb.js.gz +0 -0
  245. package/dist/client/assets/ModelPreview-QdScJljR.js.br +0 -0
  246. package/dist/client/assets/ModelPreview-QdScJljR.js.gz +0 -0
  247. package/dist/client/assets/RightSidebar-nUsJCrB9.js.br +0 -0
  248. package/dist/client/assets/RightSidebar-nUsJCrB9.js.gz +0 -0
  249. package/dist/client/assets/abnfDiagram-VCTEODGH-B51uxXBg.js.br +0 -0
  250. package/dist/client/assets/abnfDiagram-VCTEODGH-B51uxXBg.js.gz +0 -0
  251. package/dist/client/assets/app-DIurxlSe.js +0 -35
  252. package/dist/client/assets/app-DIurxlSe.js.br +0 -0
  253. package/dist/client/assets/app-DIurxlSe.js.gz +0 -0
  254. package/dist/client/assets/arc-Bkn10vSK.js.br +0 -0
  255. package/dist/client/assets/arc-Bkn10vSK.js.gz +0 -0
  256. package/dist/client/assets/architectureDiagram-5GKGNRK7-CK-cIr48.js.br +0 -0
  257. package/dist/client/assets/architectureDiagram-5GKGNRK7-CK-cIr48.js.gz +0 -0
  258. package/dist/client/assets/blockDiagram-I7D4REHJ-DzbWXcDy.js.br +0 -0
  259. package/dist/client/assets/blockDiagram-I7D4REHJ-DzbWXcDy.js.gz +0 -0
  260. package/dist/client/assets/c4Diagram-7LVT6UL2-rbi8aUz6.js.br +0 -0
  261. package/dist/client/assets/c4Diagram-7LVT6UL2-rbi8aUz6.js.gz +0 -0
  262. package/dist/client/assets/channel-DWD77N0J.js +0 -1
  263. package/dist/client/assets/chunk-F27PBJKO-BSC7rK0l.js.br +0 -0
  264. package/dist/client/assets/chunk-F27PBJKO-BSC7rK0l.js.gz +0 -0
  265. package/dist/client/assets/chunk-IMKFNOWR-B2VXoEhN.js.br +0 -0
  266. package/dist/client/assets/chunk-IMKFNOWR-B2VXoEhN.js.gz +0 -0
  267. package/dist/client/assets/chunk-SVP7TREG-f0h2wclt.js.br +0 -0
  268. package/dist/client/assets/chunk-SVP7TREG-f0h2wclt.js.gz +0 -0
  269. package/dist/client/assets/chunk-TICWLB2K-BLYE27kR.js.br +0 -0
  270. package/dist/client/assets/chunk-TICWLB2K-BLYE27kR.js.gz +0 -0
  271. package/dist/client/assets/classDiagram-ZZMXUADV-BPUOP6TD.js +0 -1
  272. package/dist/client/assets/classDiagram-v2-VYDZK3BY-BPUOP6TD.js +0 -1
  273. package/dist/client/assets/cose-bilkent-JH36ORCC-64n9-rjs.js.br +0 -0
  274. package/dist/client/assets/cose-bilkent-JH36ORCC-64n9-rjs.js.gz +0 -0
  275. package/dist/client/assets/cynefin-OW5HDTMX-BQu4qBBj.js.br +0 -0
  276. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BnwaLoUi.js.br +0 -0
  277. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BnwaLoUi.js.gz +0 -0
  278. package/dist/client/assets/dagre-GXQ25YYZ-CqFJh0CI.js.br +0 -0
  279. package/dist/client/assets/dagre-GXQ25YYZ-CqFJh0CI.js.gz +0 -0
  280. package/dist/client/assets/diagram-S7CK7UJ4-CbPoBysM.js.br +0 -0
  281. package/dist/client/assets/diagram-S7CK7UJ4-CbPoBysM.js.gz +0 -0
  282. package/dist/client/assets/diagram-UQ7AKVKN-BhBN4F33.js.br +0 -0
  283. package/dist/client/assets/diagram-UQ7AKVKN-BhBN4F33.js.gz +0 -0
  284. package/dist/client/assets/diagram-VSXAHHWV-eYeeGcK9.js.br +0 -0
  285. package/dist/client/assets/diagram-VSXAHHWV-eYeeGcK9.js.gz +0 -0
  286. package/dist/client/assets/diagram-VX7I27RA-BJzhPV4h.js.br +0 -0
  287. package/dist/client/assets/diagram-VX7I27RA-BJzhPV4h.js.gz +0 -0
  288. package/dist/client/assets/diagram-Z3DM3KII-CnjpNAJH.js.br +0 -0
  289. package/dist/client/assets/diagram-Z3DM3KII-CnjpNAJH.js.gz +0 -0
  290. package/dist/client/assets/ebnfDiagram-PWID7BFC-BSJQBTtu.js.br +0 -0
  291. package/dist/client/assets/ebnfDiagram-PWID7BFC-BSJQBTtu.js.gz +0 -0
  292. package/dist/client/assets/erDiagram-RLTQ6QDP-DJ-J9MxE.js.br +0 -0
  293. package/dist/client/assets/erDiagram-RLTQ6QDP-DJ-J9MxE.js.gz +0 -0
  294. package/dist/client/assets/flowDiagram-HODETNUW-BoQNTthC.js.br +0 -0
  295. package/dist/client/assets/flowDiagram-HODETNUW-BoQNTthC.js.gz +0 -0
  296. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CFE98nzY.js.br +0 -0
  297. package/dist/client/assets/ganttDiagram-EL5Y4UJY-CFE98nzY.js.gz +0 -0
  298. package/dist/client/assets/gestureArbiter-C_3fpCXt.js.br +0 -0
  299. package/dist/client/assets/gestureArbiter-C_3fpCXt.js.gz +0 -0
  300. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DxJzGDIE.js.br +0 -0
  301. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DxJzGDIE.js.gz +0 -0
  302. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DVsj1R9s.js.br +0 -0
  303. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DVsj1R9s.js.gz +0 -0
  304. package/dist/client/assets/journeyDiagram-3NMN7TZE-BAB2AWNl.js.br +0 -0
  305. package/dist/client/assets/journeyDiagram-3NMN7TZE-BAB2AWNl.js.gz +0 -0
  306. package/dist/client/assets/kanban-definition-UXKFOSKX-HPNzrFVI.js.br +0 -0
  307. package/dist/client/assets/kanban-definition-UXKFOSKX-HPNzrFVI.js.gz +0 -0
  308. package/dist/client/assets/layout-bA7IPCWx.js.br +0 -0
  309. package/dist/client/assets/layout-bA7IPCWx.js.gz +0 -0
  310. package/dist/client/assets/linear-Cd102271.js.br +0 -0
  311. package/dist/client/assets/linear-Cd102271.js.gz +0 -0
  312. package/dist/client/assets/mermaid.core-C4wd6qUT.js.br +0 -0
  313. package/dist/client/assets/mermaid.core-C4wd6qUT.js.gz +0 -0
  314. package/dist/client/assets/mindmap-definition-YA3MSWOX-DMxZDI3z.js.br +0 -0
  315. package/dist/client/assets/mindmap-definition-YA3MSWOX-DMxZDI3z.js.gz +0 -0
  316. package/dist/client/assets/passwordBootstrap-aU8HdPsL.js.br +0 -0
  317. package/dist/client/assets/passwordBootstrap-aU8HdPsL.js.gz +0 -0
  318. package/dist/client/assets/pegDiagram-XKGWAZYB-BliPfrj_.js.br +0 -0
  319. package/dist/client/assets/pegDiagram-XKGWAZYB-BliPfrj_.js.gz +0 -0
  320. package/dist/client/assets/pieDiagram-E7YTZNPT-esWyI6AY.js.br +0 -0
  321. package/dist/client/assets/pieDiagram-E7YTZNPT-esWyI6AY.js.gz +0 -0
  322. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CBoaEIHy.js.br +0 -0
  323. package/dist/client/assets/quadrantDiagram-AXDQQJYC-CBoaEIHy.js.gz +0 -0
  324. package/dist/client/assets/railroadDiagram-O6MQD6OU-FB5bPmYm.js.br +0 -0
  325. package/dist/client/assets/railroadDiagram-O6MQD6OU-FB5bPmYm.js.gz +0 -0
  326. package/dist/client/assets/rdpSession-DnBdxkm1.js.br +0 -0
  327. package/dist/client/assets/rdpSession-DnBdxkm1.js.gz +0 -0
  328. package/dist/client/assets/referenceLongPress-DDmic9E5.js.br +0 -0
  329. package/dist/client/assets/referenceLongPress-DDmic9E5.js.gz +0 -0
  330. package/dist/client/assets/requirementDiagram-BXWQKSXE-CpokwhJY.js.br +0 -0
  331. package/dist/client/assets/requirementDiagram-BXWQKSXE-CpokwhJY.js.gz +0 -0
  332. package/dist/client/assets/sankeyDiagram-P5KCCOFB-DXQDOMAh.js.br +0 -0
  333. package/dist/client/assets/sankeyDiagram-P5KCCOFB-DXQDOMAh.js.gz +0 -0
  334. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Dn3ZooAM.js.br +0 -0
  335. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-Dn3ZooAM.js.gz +0 -0
  336. package/dist/client/assets/sizeCapture-INFHLROL-PItE9Y1o.js.br +0 -0
  337. package/dist/client/assets/sizeCapture-INFHLROL-PItE9Y1o.js.gz +0 -0
  338. package/dist/client/assets/stateDiagram-D77RDMKH-BBZ01SXU.js.br +0 -0
  339. package/dist/client/assets/stateDiagram-D77RDMKH-BBZ01SXU.js.gz +0 -0
  340. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-BHm-8VYK.js +0 -1
  341. package/dist/client/assets/swimlanes-42K2YHIH-BY8IlbkR.js.br +0 -0
  342. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-BuCvfzGX.js +0 -8
  343. package/dist/client/assets/timeline-definition-24CTP7MA-DyY9g2Hx.js.br +0 -0
  344. package/dist/client/assets/timeline-definition-24CTP7MA-DyY9g2Hx.js.gz +0 -0
  345. package/dist/client/assets/vennDiagram-4TSXK5OY-Dy0PQ4-U.js.br +0 -0
  346. package/dist/client/assets/vennDiagram-4TSXK5OY-Dy0PQ4-U.js.gz +0 -0
  347. package/dist/client/assets/videoCompression-BDNHhfKS.js.br +0 -0
  348. package/dist/client/assets/videoCompression-BDNHhfKS.js.gz +0 -0
  349. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DtBEPD3N.js.br +0 -0
  350. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DtBEPD3N.js.gz +0 -0
  351. package/dist/client/assets/xychartDiagram-S5SC5T6Z-B2K1XjDQ.js.br +0 -0
  352. package/dist/client/assets/xychartDiagram-S5SC5T6Z-B2K1XjDQ.js.gz +0 -0
package/dist/client/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let e,s={};const n=(n,i)=>(n=new URL(n+".js",i).href,s[n]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()}).then(()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(i,a)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let r={};const c=e=>n(e,o),d={module:{uri:o},exports:r,require:c};s[o]=Promise.all(i.map(e=>d[e]||c(e))).then(e=>(a(...e),r))}}define(["./workbox-9845bf53"],function(e){"use strict";importScripts("sw-encrypted-background.js","sw-notifications.js","sw-secure-api.js","sw-downloads.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"index.html",revision:"e34a208e8afdf5687993c6320422767a"},{url:"assets/app-DIurxlSe.js",revision:null},{url:"assets/react-XDCjal2T.js",revision:null},{url:"assets/dnd-BCFAPC0L.js",revision:null},{url:"assets/terminal-C7X98Amf.js",revision:null},{url:"assets/index-A-ZC9mbr.css",revision:null},{url:"icons/agents/opencode.svg",revision:"851c2931d95821ba2b39b68587b48976"},{url:"icons/agents/kimi.svg",revision:"5366c710f4f763022fe159a69cf17409"},{url:"icons/agents/grok.svg",revision:"cd745b0b964545bc7a6b4f36021c3298"},{url:"icons/agents/goose.svg",revision:"c79b927278983c19098d77b4b0c11ab3"},{url:"icons/agents/gemini.svg",revision:"7a64f6d6f80a908255e9c0256903882e"},{url:"icons/agents/droid.svg",revision:"f28723b8c5c115e0908ba3c72613e256"},{url:"icons/agents/cursor.svg",revision:"a1528f3d3cda497f75a5db28defb19de"},{url:"icons/agents/copilot.svg",revision:"dd52e96c1eac0b6ec4bedcd0ddd3b52d"},{url:"icons/agents/codex.svg",revision:"608e55babb0b217e1f2da287342b46d3"},{url:"icons/agents/claude.svg",revision:"08af0225b7acdd8e8f573f3247e5e1c3"},{url:"icons/agents/amp.svg",revision:"af12f8b33faa81e4d46ea7b93c7e43f3"},{url:"apple-touch-icon-180x180.png",revision:"628c2e2f28a9b545aa57be1352025643"},{url:"boot-logo.png",revision:"2e3a25efd9b0b8ca1eab53b5f2284556"},{url:"favicon.ico",revision:"2994debfa6f59a0898e24eb0c54d64b5"},{url:"ipad-status-bar.js",revision:"3a8080edb8a5cc658a7908f6ad69537f"},{url:"maskable-icon-512x512.png",revision:"4d489331fd81f0713c400b26426442b9"},{url:"pwa-192x192.png",revision:"4d6f899888cfb8ccd7a1fd3c9e583ad2"},{url:"pwa-512x512.png",revision:"0885dd7ec8932e7f878b013d51a380a4"},{url:"robots.txt",revision:"d9339907142917dee4aac78494ac9cfe"},{url:"sw-downloads.js",revision:"48dab2e78bd93b4eee27fca487eccfde"},{url:"sw-notifications.js",revision:"fde578590ea8b0540d488ef448b48f45"},{url:"sw-secure-api.js",revision:"cf2bdbd03d41d66d60344c0b5a1075de"},{url:"manifest.webmanifest",revision:"83f9a43b74c236012adafb077fb6d774"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html"),{denylist:[/^\/api\//,/^\/__termdock-download\//,/^\/health$/]})),e.registerRoute(/\/assets\/.*\.(?:js|css)$/,new e.CacheFirst({cacheName:"termdock-lazy-assets-v1",plugins:[new e.CacheableResponsePlugin({statuses:[0,200]}),new e.ExpirationPlugin({maxEntries:96,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/fonts\/terminal\/[^/]+-[a-f0-9]{12}\.woff2$/,new e.CacheFirst({cacheName:"termdock-fonts-v2",plugins:[new e.CacheableResponsePlugin({statuses:[0,200]}),new e.ExpirationPlugin({maxEntries:384,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/fonts\/.*\.(?:woff2|ttf)$/,new e.StaleWhileRevalidate({cacheName:"termdock-fonts-v1",plugins:[new e.ExpirationPlugin({maxEntries:24,maxAgeSeconds:2592e3})]}),"GET")});
1
+ if(!self.define){let e,s={};const n=(n,i)=>(n=new URL(n+".js",i).href,s[n]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()}).then(()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(i,a)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let r={};const c=e=>n(e,o),d={module:{uri:o},exports:r,require:c};s[o]=Promise.all(i.map(e=>d[e]||c(e))).then(e=>(a(...e),r))}}define(["./workbox-9845bf53"],function(e){"use strict";importScripts("sw-encrypted-background.js","sw-notifications.js","sw-secure-api.js","sw-downloads.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"index.html",revision:"3a82afb4a898c5c563748bbe9a5f4920"},{url:"assets/app-By1Q_guu.js",revision:null},{url:"assets/react-XDCjal2T.js",revision:null},{url:"assets/dnd-BCFAPC0L.js",revision:null},{url:"assets/terminal-C7X98Amf.js",revision:null},{url:"assets/index-A-ZC9mbr.css",revision:null},{url:"icons/agents/opencode.svg",revision:"851c2931d95821ba2b39b68587b48976"},{url:"icons/agents/kimi.svg",revision:"5366c710f4f763022fe159a69cf17409"},{url:"icons/agents/grok.svg",revision:"cd745b0b964545bc7a6b4f36021c3298"},{url:"icons/agents/goose.svg",revision:"c79b927278983c19098d77b4b0c11ab3"},{url:"icons/agents/gemini.svg",revision:"7a64f6d6f80a908255e9c0256903882e"},{url:"icons/agents/droid.svg",revision:"f28723b8c5c115e0908ba3c72613e256"},{url:"icons/agents/cursor.svg",revision:"a1528f3d3cda497f75a5db28defb19de"},{url:"icons/agents/copilot.svg",revision:"dd52e96c1eac0b6ec4bedcd0ddd3b52d"},{url:"icons/agents/codex.svg",revision:"608e55babb0b217e1f2da287342b46d3"},{url:"icons/agents/claude.svg",revision:"08af0225b7acdd8e8f573f3247e5e1c3"},{url:"icons/agents/amp.svg",revision:"af12f8b33faa81e4d46ea7b93c7e43f3"},{url:"apple-touch-icon-180x180.png",revision:"628c2e2f28a9b545aa57be1352025643"},{url:"boot-logo.png",revision:"2e3a25efd9b0b8ca1eab53b5f2284556"},{url:"favicon.ico",revision:"2994debfa6f59a0898e24eb0c54d64b5"},{url:"ipad-status-bar.js",revision:"3a8080edb8a5cc658a7908f6ad69537f"},{url:"maskable-icon-512x512.png",revision:"4d489331fd81f0713c400b26426442b9"},{url:"pwa-192x192.png",revision:"4d6f899888cfb8ccd7a1fd3c9e583ad2"},{url:"pwa-512x512.png",revision:"0885dd7ec8932e7f878b013d51a380a4"},{url:"robots.txt",revision:"d9339907142917dee4aac78494ac9cfe"},{url:"sw-downloads.js",revision:"48dab2e78bd93b4eee27fca487eccfde"},{url:"sw-notifications.js",revision:"fde578590ea8b0540d488ef448b48f45"},{url:"sw-secure-api.js",revision:"cf2bdbd03d41d66d60344c0b5a1075de"},{url:"manifest.webmanifest",revision:"83f9a43b74c236012adafb077fb6d774"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html"),{denylist:[/^\/api\//,/^\/__termdock-download\//,/^\/health$/]})),e.registerRoute(/\/assets\/.*\.(?:js|css)$/,new e.CacheFirst({cacheName:"termdock-lazy-assets-v1",plugins:[new e.CacheableResponsePlugin({statuses:[0,200]}),new e.ExpirationPlugin({maxEntries:96,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/fonts\/terminal\/[^/]+-[a-f0-9]{12}\.woff2$/,new e.CacheFirst({cacheName:"termdock-fonts-v2",plugins:[new e.CacheableResponsePlugin({statuses:[0,200]}),new e.ExpirationPlugin({maxEntries:384,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/fonts\/.*\.(?:woff2|ttf)$/,new e.StaleWhileRevalidate({cacheName:"termdock-fonts-v1",plugins:[new e.ExpirationPlugin({maxEntries:24,maxAgeSeconds:2592e3})]}),"GET")});
Binary file
Binary file
@@ -11,6 +11,7 @@ import { createPasswordLoginRouter } from './federation/passwordLoginRoutes.js';
11
11
  import { apiAccessGate, isTrustedLocalRequest } from './utils/apiAccess.js';
12
12
  import { isEncryptedRequest } from './federation/requestContext.js';
13
13
  import { createFederationRuntime } from './federation/runtime.js';
14
+ import { startWebTransportServer } from './federation/webTransportServer.js';
14
15
  import { RouteAccess } from './federation/routeAccess.js';
15
16
  import { RouteInvitationStore } from './federation/routeInvitations.js';
16
17
  import { attachRegisteredDirectTargets, verifyDirectTarget } from './federation/directRoutes.js';
@@ -470,6 +471,9 @@ export function startServer(options = {}) {
470
471
  runtimeMonitor,
471
472
  });
472
473
  const { server, scheme } = createServerForApp(app, options);
474
+ let webTransport;
475
+ const webTransportDescriptor = () => webTransport?.descriptor();
476
+ server.once('close', () => webTransport?.close());
473
477
  const collaborationChannels = new Map();
474
478
  const reverseCollaboration = (id) => [...(collaborationChannels.get(id) ?? [])].find(rpc => !rpc.closed);
475
479
  let collaborationService;
@@ -515,6 +519,7 @@ export function startServer(options = {}) {
515
519
  const federation = createFederationRuntime(app, path.join(homedir(), '.termdock', 'federation'), {
516
520
  terminal: handleTerminalWebSocket, control: handleControlWebSocket, android: handleAndroidWebSocket, computer: handleComputerWebSocket,
517
521
  }, {
522
+ webTransport: webTransportDescriptor,
518
523
  resolveSessionId: resolveStableFederationSessionId,
519
524
  collaborationConnected: (subjectId, rpc) => {
520
525
  const channels = collaborationChannels.get(subjectId) ?? new Set();
@@ -727,29 +732,13 @@ export function startServer(options = {}) {
727
732
  certWatcher.start();
728
733
  let latestLocalAccessState = localAccessManager.getState();
729
734
  let latestOnboardingUrl = null;
730
- // WebSocket for bidirectional terminal communication.
731
- // Replaces SSE (server→client) + HTTP POST (client→server) with a single
732
- // persistent connection per terminal session.
733
- //
734
- // perMessageDeflate: 终端输出是纯文本,压缩比通常 5-10x。弱网/跨城(高 RTT、
735
- // 低带宽)下,刷新页面时 N 个终端各自一次性回放全量 scrollback(每个可达
736
- // 100KB),未压缩会同时挤满链路、肉眼可见地卡几秒。开启压缩后带宽需求直接
737
- // 降到 1/5~1/10。参数:
738
- // - threshold 1024:小于 1KB 的小包(按键回显等)不压缩,避免 CPU 浪费。
739
- // - concurrencyLimit:限制并发压缩任务,防止突发回放打满 CPU。
740
- // - zlib memLevel 7 + level 6:在压缩比和内存/CPU 间取均衡,避免每连接
741
- // 分配过大 zlib 上下文(默认 memLevel 8 内存更高)。
742
- // - serverNoContextTakeover:每条消息独立压缩上下文,降低长连接常驻内存。
735
+ // Both public WebSocket endpoints carry Noise ciphertext. Compress eligible
736
+ // terminal records before encryption instead of spending CPU deflating random
737
+ // ciphertext (including at relay hops).
743
738
  const wss = new WebSocketServer({
744
739
  noServer: true,
745
740
  maxPayload: 1024 * 1024,
746
- perMessageDeflate: {
747
- threshold: 1024,
748
- concurrencyLimit: 10,
749
- serverNoContextTakeover: true,
750
- clientNoContextTakeover: true,
751
- zlibDeflateOptions: { level: 6, memLevel: 7 },
752
- },
741
+ perMessageDeflate: false,
753
742
  });
754
743
  server.on('upgrade', (request, socket, head) => {
755
744
  if (wss.clients.size >= 256) {
@@ -815,6 +804,26 @@ export function startServer(options = {}) {
815
804
  const displayHost = host === '0.0.0.0' ? 'localhost' : host;
816
805
  console.log(`Termdock server running at ${scheme}://${displayHost}:${listeningPort}`);
817
806
  console.log(`Health check: ${scheme}://${displayHost}:${listeningPort}/health`);
807
+ if ((options.quic ?? process.env.TERMDOCK_QUIC !== '0') && (scheme === 'https' || process.env.TERMDOCK_PUBLIC_ORIGIN?.startsWith('https://'))) {
808
+ const quicPort = process.env.TERMDOCK_QUIC_PORT === undefined ? listeningPort : Number(process.env.TERMDOCK_QUIC_PORT);
809
+ void federation.then(async (runtime) => {
810
+ if (!Number.isSafeInteger(quicPort) || quicPort < 1 || quicPort > 65535)
811
+ throw new Error('Invalid TERMDOCK_QUIC_PORT');
812
+ const transport = await startWebTransportServer({
813
+ directory: path.join(homedir(), '.termdock', 'federation'), host: listeningHost, port: quicPort,
814
+ hostAllowed: isAllowedHost,
815
+ originAllowed: (origin, authority) => secureChannelOriginAllowed(origin, () => isUpgradeOriginAllowed(origin, authority)),
816
+ openAccessAllowed: (origin, authority) => !!origin && isUpgradeOriginAllowed(origin, authority),
817
+ accept: (duplex, context) => runtime.acceptDuplex(duplex, context),
818
+ });
819
+ if (!server.listening) {
820
+ transport.close();
821
+ return;
822
+ }
823
+ webTransport = transport;
824
+ console.log(`QUIC/WebTransport listening on UDP ${quicPort}; independent encrypted streams enabled`);
825
+ }).catch(error => console.warn('[quic] Encrypted WebSocket remains available:', error instanceof Error ? error.message : 'Transport unavailable'));
826
+ }
818
827
  const onboardingServerState = scheme === 'https'
819
828
  ? startOnboardingServer({ httpsPort: listeningPort, caCertPath: options.httpsCaPath })
820
829
  : { server: null, url: null };
@@ -0,0 +1,28 @@
1
+ import { TRANSFER_CHUNK_BYTES } from './transferWindow.js';
2
+ export const BINARY_RECORD_FLAG = 0x80000000;
3
+ const encoder = new TextEncoder();
4
+ const decoder = new TextDecoder('utf-8', { fatal: true });
5
+ /** Negotiated file chunks avoid JSON/base64 expansion; the entire record,
6
+ * including its stream id and kind, is still encrypted by Noise. */
7
+ export function binaryPacketBody(packet) {
8
+ if (!(packet.bytes instanceof Uint8Array))
9
+ return;
10
+ if (!['upload', 'chunk'].includes(packet.type))
11
+ throw new Error('Invalid binary record type');
12
+ const id = encoder.encode(packet.id);
13
+ if (!id.length || id.length > 128 || packet.bytes.length > TRANSFER_CHUNK_BYTES)
14
+ throw new Error('Invalid binary record size');
15
+ const result = new Uint8Array(2 + id.length + packet.bytes.length);
16
+ result[0] = packet.type === 'upload' ? 1 : 2;
17
+ result[1] = id.length;
18
+ result.set(id, 2);
19
+ result.set(packet.bytes, 2 + id.length);
20
+ return result;
21
+ }
22
+ export function readBinaryPacket(body) {
23
+ const kind = body[0], idLength = body[1];
24
+ if (![1, 2].includes(kind) || !idLength || idLength > 128 || body.length < 2 + idLength
25
+ || body.length - 2 - idLength > TRANSFER_CHUNK_BYTES)
26
+ throw new Error('Invalid binary record');
27
+ return { type: kind === 1 ? 'upload' : 'chunk', id: decoder.decode(body.subarray(2, 2 + idLength)), bytes: body.slice(2 + idLength) };
28
+ }
@@ -1,3 +1,5 @@
1
+ import { compressRecord } from './recordCompression.js';
2
+ import { BINARY_RECORD_FLAG, binaryPacketBody, readBinaryPacket } from './binaryPacket.js';
1
3
  /** Bounded queues are also used at the untrusted, pre-handshake boundary. */
2
4
  export class AsyncQueue {
3
5
  limit;
@@ -62,6 +64,7 @@ export class PacketChannel {
62
64
  outgoing = new AsyncQueue(256);
63
65
  outgoingBytes = 0;
64
66
  queuedBytesById = new Map();
67
+ writeWaiters = new Set();
65
68
  closed = false;
66
69
  get hasPendingWrites() { return this.outgoingBytes > 0; }
67
70
  queuedBytesFor(id) { return this.queuedBytesById.get(id) ?? 0; }
@@ -72,7 +75,7 @@ export class PacketChannel {
72
75
  this.done = duplex.sink((async function* () {
73
76
  for await (const packet of self.outgoing) {
74
77
  try {
75
- yield packet.bytes;
78
+ yield packet.compress ? await compressRecord(packet.bytes, packet.id) : packet.bytes;
76
79
  }
77
80
  finally {
78
81
  self.releaseQueuedPacket(packet);
@@ -81,27 +84,66 @@ export class PacketChannel {
81
84
  })());
82
85
  void this.done.then(() => this.discardPending(), error => this.discardPending(error instanceof Error ? error : new Error('Transport failed')));
83
86
  }
84
- send(packet) {
87
+ send(packet, compress = false) {
88
+ if (this.closed)
89
+ throw new Error('Channel closed');
85
90
  // The item-count cap protects against floods of tiny records. Check it
86
91
  // before encoding and keep this queue alive when it is temporarily full.
87
92
  if (this.outgoing.size >= 256)
88
93
  throw new PacketQueueBackpressureError('Record queue item limit exceeded');
89
- const body = encoder.encode(JSON.stringify(packet));
94
+ const binary = binaryPacketBody(packet);
95
+ const body = binary ?? encoder.encode(JSON.stringify(packet));
90
96
  if (body.length > MAX_PACKET)
91
97
  throw new Error('Record too large');
92
98
  const bytes = new Uint8Array(body.length + 4);
93
- new DataView(bytes.buffer).setUint32(0, body.length);
99
+ new DataView(bytes.buffer).setUint32(0, binary ? body.length + BINARY_RECORD_FLAG : body.length);
94
100
  bytes.set(body, 4);
95
101
  if (this.outgoingBytes + bytes.byteLength > 4 * 1024 * 1024)
96
102
  throw new PacketQueueBackpressureError('Record queue byte budget exceeded');
97
- const queued = { id: packet.id, bytes };
103
+ const queued = { id: packet.id, bytes, compress };
98
104
  if (!this.outgoing.tryPush(queued))
99
105
  throw new PacketQueueBackpressureError('Record queue item limit exceeded');
100
106
  this.outgoingBytes += bytes.byteLength;
101
107
  this.queuedBytesById.set(packet.id, this.queuedBytesFor(packet.id) + bytes.byteLength);
102
108
  }
109
+ /** Bulk producers wait below the hard cap, leaving room for input, ACKs and
110
+ * cancellation. A busy file stream must not tear down the shared connection. */
111
+ async sendBulk(packet, signal, beforeSend) {
112
+ const started = Date.now();
113
+ while (true) {
114
+ if (signal.aborted)
115
+ throw signal.reason ?? new Error('CANCELLED');
116
+ if (this.closed)
117
+ throw new Error('Channel closed');
118
+ if (this.outgoingBytes < 512 * 1024 && this.outgoing.size < 128) {
119
+ beforeSend?.();
120
+ try {
121
+ this.send(packet);
122
+ return;
123
+ }
124
+ catch (error) {
125
+ if (!(error instanceof PacketQueueBackpressureError))
126
+ throw error;
127
+ }
128
+ }
129
+ if (Date.now() - started >= 30_000)
130
+ throw new Error('Encrypted transport congested');
131
+ await new Promise((resolve, reject) => {
132
+ const cleanup = () => { clearTimeout(timer); signal.removeEventListener('abort', abort); this.writeWaiters.delete(wake); };
133
+ const abort = () => { cleanup(); reject(signal.reason ?? new Error('CANCELLED')); };
134
+ const wake = () => { cleanup(); resolve(); };
135
+ const timer = setTimeout(() => { cleanup(); reject(new Error('Encrypted transport congested')); }, Math.max(1, 30_000 - (Date.now() - started)));
136
+ this.writeWaiters.add(wake);
137
+ signal.addEventListener('abort', abort, { once: true });
138
+ if (signal.aborted)
139
+ abort();
140
+ });
141
+ }
142
+ }
103
143
  releaseQueuedPacket(packet) {
104
144
  this.outgoingBytes = Math.max(0, this.outgoingBytes - packet.bytes.byteLength);
145
+ for (const wake of this.writeWaiters)
146
+ wake();
105
147
  const current = this.queuedBytesById.get(packet.id);
106
148
  if (current === undefined)
107
149
  return;
@@ -127,6 +169,8 @@ export class PacketChannel {
127
169
  this.outgoing.end(error);
128
170
  this.outgoingBytes = 0;
129
171
  this.queuedBytesById.clear();
172
+ for (const wake of this.writeWaiters)
173
+ wake();
130
174
  this.duplex.close?.(error);
131
175
  }
132
176
  async *read() {
@@ -135,6 +179,8 @@ export class PacketChannel {
135
179
  let bufferedBytes = 0;
136
180
  let spareBlock;
137
181
  const parseFrame = (frame) => {
182
+ if (frame[0] & 0x80)
183
+ return readBinaryPacket(frame.subarray(4));
138
184
  const packet = JSON.parse(decoder.decode(frame.subarray(4)));
139
185
  if (!packet || typeof packet !== 'object' || typeof packet.id !== 'string' || typeof packet.type !== 'string')
140
186
  throw new Error('Invalid record');
@@ -232,7 +278,7 @@ export class PacketChannel {
232
278
  if (bufferedBytes + chunk.byteLength > MAX_BUFFERED_PACKET_BYTES)
233
279
  throw new Error('Record buffer exceeded');
234
280
  if (bufferedBytes === 0 && chunk.byteLength >= 5) {
235
- const size = ((chunk[0] * 0x1000000) + (chunk[1] << 16) + (chunk[2] << 8) + chunk[3]) >>> 0;
281
+ const size = (((chunk[0] & 0x7f) * 0x1000000) + (chunk[1] << 16) + (chunk[2] << 8) + chunk[3]) >>> 0;
236
282
  if (size > MAX_PACKET || size === 0)
237
283
  throw new Error('Invalid record size');
238
284
  if (chunk.byteLength === size + 4) {
@@ -243,7 +289,7 @@ export class PacketChannel {
243
289
  if (chunk.byteLength)
244
290
  append(chunk);
245
291
  while (bufferedBytes >= 4) {
246
- const size = ((byteAt(0) * 0x1000000) + (byteAt(1) << 16) + (byteAt(2) << 8) + byteAt(3)) >>> 0;
292
+ const size = (((byteAt(0) & 0x7f) * 0x1000000) + (byteAt(1) << 16) + (byteAt(2) << 8) + byteAt(3)) >>> 0;
247
293
  if (size > MAX_PACKET || size === 0)
248
294
  throw new Error('Invalid record size');
249
295
  if (bufferedBytes < size + 4)
@@ -0,0 +1,59 @@
1
+ const MAX_RECORD_BYTES = 2 * 1024 * 1024;
2
+ const encoder = new TextEncoder();
3
+ const decoder = new TextDecoder('utf-8', { fatal: true });
4
+ async function transform(bytes, stream) {
5
+ const source = new Blob([bytes]).stream();
6
+ const reader = source.pipeThrough(stream).getReader();
7
+ const chunks = [];
8
+ let size = 0;
9
+ try {
10
+ while (true) {
11
+ const { done, value } = await reader.read();
12
+ if (done)
13
+ break;
14
+ size += value.byteLength;
15
+ if (size > MAX_RECORD_BYTES)
16
+ throw new Error('Expanded record exceeds budget');
17
+ chunks.push(value);
18
+ }
19
+ }
20
+ catch (error) {
21
+ await reader.cancel(error).catch(() => { });
22
+ throw error;
23
+ }
24
+ finally {
25
+ reader.releaseLock();
26
+ }
27
+ const result = new Uint8Array(size);
28
+ let offset = 0;
29
+ for (const chunk of chunks) {
30
+ result.set(chunk, offset);
31
+ offset += chunk.byteLength;
32
+ }
33
+ return result;
34
+ }
35
+ /** Independent records avoid retaining compression dictionaries across messages.
36
+ * Only explicitly negotiated terminal output is eligible, before Noise encryption. */
37
+ export async function compressRecord(frame, id) {
38
+ if (frame.byteLength < 4096 || typeof CompressionStream === 'undefined')
39
+ return frame;
40
+ const compressed = await transform(frame.subarray(4), new CompressionStream('gzip'));
41
+ let binary = '';
42
+ for (let offset = 0; offset < compressed.length; offset += 8192)
43
+ binary += String.fromCharCode(...compressed.subarray(offset, offset + 8192));
44
+ const body = encoder.encode(JSON.stringify({ type: 'compressed', id, encoding: 'gzip', data: btoa(binary) }));
45
+ // Account for base64 and the envelope: already compressed content goes as-is.
46
+ if (body.byteLength + 4 >= frame.byteLength * 0.9)
47
+ return frame;
48
+ const result = new Uint8Array(body.byteLength + 4);
49
+ new DataView(result.buffer).setUint32(0, body.byteLength);
50
+ result.set(body, 4);
51
+ return result;
52
+ }
53
+ export async function expandRecord(data) {
54
+ if (typeof data !== 'string' || data.length > Math.ceil(MAX_RECORD_BYTES / 3) * 4)
55
+ throw new Error('Invalid compressed record');
56
+ const bytes = Uint8Array.from(atob(data), c => c.charCodeAt(0));
57
+ const expanded = await transform(bytes, new DecompressionStream('gzip'));
58
+ return JSON.parse(decoder.decode(expanded));
59
+ }
@@ -18,19 +18,22 @@ import { readTerminalHandshakeDimensions } from '../utils/terminalHandshakeDimen
18
18
  import { openAccessAllowed } from './openAccess.js';
19
19
  import { isAuthEnabled, getPasswordCredentialFingerprint, getPasswordVerifier, getLoginBlockMs, recordLoginFailure, recordLoginSuccess } from '../utils/authProtection.js';
20
20
  import { MAX_OPEN_SECURE_SOCKETS, MAX_SERVER_HTTP_REQUESTS } from './streamLimits.js';
21
+ import { MAX_TRANSFER_WINDOW, TRANSFER_CHUNK_BYTES, TransferWindow, transferWindow } from './transferWindow.js';
21
22
  class LogicalSocket extends EventEmitter {
22
23
  channel;
23
24
  id;
24
25
  canRead;
26
+ compress;
25
27
  OPEN = 1;
26
28
  readyState = 1;
27
29
  get bufferedAmount() { return this.channel.queuedBytesFor(this.id); }
28
30
  maxQueuedBytes;
29
- constructor(channel, id, canRead, maxQueuedBytes = 4 * 1024 * 1024) {
31
+ constructor(channel, id, canRead, maxQueuedBytes = 4 * 1024 * 1024, compress = false) {
30
32
  super();
31
33
  this.channel = channel;
32
34
  this.id = id;
33
35
  this.canRead = canRead;
36
+ this.compress = compress;
34
37
  this.maxQueuedBytes = maxQueuedBytes;
35
38
  }
36
39
  send(data) {
@@ -48,7 +51,7 @@ class LogicalSocket extends EventEmitter {
48
51
  return;
49
52
  }
50
53
  try {
51
- this.channel.send({ type: 'ws-data', id: this.id, data });
54
+ this.channel.send({ type: 'ws-data', id: this.id, data }, this.compress);
52
55
  }
53
56
  catch {
54
57
  this.close(1013, 'Output consumer is too slow');
@@ -113,6 +116,11 @@ export async function createFederationRuntime(app, directory, handlers, options
113
116
  markEncryptedRequest(request, typeof subject === 'string' ? subject : undefined, fullService);
114
117
  app(request, response);
115
118
  });
119
+ // The outer encrypted consumer can apply backpressure long after a local
120
+ // response was written. Expiring this private keepalive socket while Undici
121
+ // still drains it can truncate a slow download (UND_ERR_SOCKET / terminated).
122
+ // Let the local client expire idle connections after it finishes consuming.
123
+ internal.keepAliveTimeout = 0;
116
124
  await new Promise((resolve, reject) => { internal.once('error', reject); internal.listen(0, '127.0.0.1', resolve); });
117
125
  const address = internal.address();
118
126
  if (!address || typeof address === 'string')
@@ -132,7 +140,7 @@ export async function createFederationRuntime(app, directory, handlers, options
132
140
  const inventory = await response.json();
133
141
  return Array.isArray(inventory.clientSessions) ? inventory.clientSessions : [];
134
142
  }
135
- async function accept(socket, context = {}) {
143
+ async function acceptDuplex(duplex, context = {}) {
136
144
  let collaborationRpc;
137
145
  let unregisterCollaboration;
138
146
  const open = (action) => openAccessAllowed(context.allowOpenAccess === true, isAuthEnabled(), action);
@@ -161,7 +169,7 @@ export async function createFederationRuntime(app, directory, handlers, options
161
169
  const sockets = new Map();
162
170
  let revokeTimer;
163
171
  try {
164
- const secured = await secureConnection({ identity, duplex: socketDuplex(socket), initiator: false, signal: AbortSignal.timeout(15000) });
172
+ const secured = await secureConnection({ identity, duplex, initiator: false, signal: AbortSignal.timeout(15000) });
165
173
  const subjectId = secured.authenticatedPeerId;
166
174
  channel = new PacketChannel(secured.duplex);
167
175
  channels.add(channel);
@@ -225,28 +233,16 @@ export async function createFederationRuntime(app, directory, handlers, options
225
233
  const { done, value } = await reader.read();
226
234
  if (done)
227
235
  break;
228
- for (let offset = 0; offset < value.length; offset += 65536) {
236
+ for (let offset = 0; offset < value.length; offset += TRANSFER_CHUNK_BYTES) {
229
237
  httpAllowed(operation.head);
230
- await new Promise((resolve, reject) => {
231
- const cleanup = () => { clearTimeout(timeout); operation.abort.signal.removeEventListener('abort', abort); operation.ack = undefined; };
232
- const timeout = setTimeout(() => { cleanup(); reject(new Error('CONSUMER_TIMEOUT')); }, 30000);
233
- const abort = () => { cleanup(); reject(new Error('CANCELLED')); };
234
- operation.abort.signal.addEventListener('abort', abort, { once: true });
235
- operation.ack = () => { cleanup(); resolve(); };
236
- if (operation.abort.signal.aborted) {
237
- abort();
238
- return;
239
- }
240
- try {
241
- sendHttp({ type: 'chunk', id, data: toBase64(value.subarray(offset, offset + 65536)) });
242
- }
243
- catch (error) {
244
- cleanup();
245
- reject(error);
246
- }
247
- });
238
+ await operation.responseWindow.wait();
239
+ httpAllowed(operation.head);
240
+ operation.responseWindow.sent();
241
+ const chunk = value.subarray(offset, offset + TRANSFER_CHUNK_BYTES);
242
+ await channel.sendBulk({ type: 'chunk', id, ...(operation.head.binaryChunks === true ? { bytes: chunk } : { data: toBase64(chunk) }) }, operation.abort.signal, () => httpAllowed(operation.head));
248
243
  }
249
244
  }
245
+ await operation.responseWindow.wait(true);
250
246
  sendHttp({ type: 'end', id });
251
247
  }
252
248
  catch (error) {
@@ -393,7 +389,7 @@ export async function createFederationRuntime(app, directory, handlers, options
393
389
  }
394
390
  else if (packet.type === 'permissions') {
395
391
  const grants = store.listEffective({ subjectId, serviceId });
396
- send({ type: 'result', id: packet.id, subjectId, serviceId, fullService: full(subjectId), grants });
392
+ send({ type: 'result', id: packet.id, subjectId, serviceId, fullService: full(subjectId), grants, httpWindow: MAX_TRANSFER_WINDOW, binaryChunks: true, webTransport: options.webTransport?.() });
397
393
  }
398
394
  else if (packet.type === 'session-list') {
399
395
  const inventory = await sessionInventory();
@@ -515,13 +511,15 @@ export async function createFederationRuntime(app, directory, handlers, options
515
511
  send({ type: 'result', id: packet.id, grant });
516
512
  }
517
513
  else if (packet.type === 'http') {
518
- if (operations.size >= MAX_SERVER_HTTP_REQUESTS || operations.has(packet.id) || sockets.has(packet.id))
514
+ if ((context.singleOperation ? operations.size + sockets.size >= 1 : operations.size >= MAX_SERVER_HTTP_REQUESTS) || operations.has(packet.id) || sockets.has(packet.id))
519
515
  throw new Error('STREAM_LIMIT');
520
516
  httpAllowed(packet);
521
517
  const upload = !['GET', 'HEAD'].includes(String(packet.method));
522
518
  if (upload && uploadSlots >= 8)
523
519
  throw new Error('UPLOAD_CONCURRENCY_LIMIT');
524
- const operation = { head: packet, body: new AsyncQueue(2), size: 0, abort: new AbortController(), state: 'uploading', updatedAt: Date.now(), uploadSlot: upload };
520
+ const window = transferWindow(packet.window);
521
+ const abort = new AbortController();
522
+ const operation = { head: packet, body: new AsyncQueue(Math.max(2, window)), size: 0, abort, state: 'uploading', updatedAt: Date.now(), uploadSlot: upload, responseWindow: new TransferWindow(window, abort.signal) };
525
523
  if (upload)
526
524
  uploadSlots++;
527
525
  operations.set(packet.id, operation);
@@ -530,13 +528,14 @@ export async function createFederationRuntime(app, directory, handlers, options
530
528
  }
531
529
  else if (packet.type === 'upload') {
532
530
  const operation = operations.get(packet.id);
533
- if (!operation || operation.state !== 'uploading' || typeof packet.data !== 'string')
531
+ if (!operation || operation.state !== 'uploading'
532
+ || !(operation.head.binaryChunks === true && packet.bytes instanceof Uint8Array) && typeof packet.data !== 'string')
534
533
  throw new Error('INVALID_UPLOAD');
535
534
  httpAllowed(operation.head);
536
- const bytes = fromBase64(packet.data);
535
+ const bytes = operation.head.binaryChunks === true && packet.bytes instanceof Uint8Array ? packet.bytes : fromBase64(packet.data);
537
536
  operation.size += bytes.length;
538
537
  const limit = new URL(String(operation.head.path), 'http://inner').pathname === '/api/terminal/fs/upload' ? 110 * 1024 * 1024 : 5 * 1024 * 1024;
539
- if (['GET', 'HEAD'].includes(String(operation.head.method)) || bytes.length > 65536 || operation.size > limit) {
538
+ if (['GET', 'HEAD'].includes(String(operation.head.method)) || bytes.length > TRANSFER_CHUNK_BYTES || operation.size > limit) {
540
539
  cancelHttp(operation);
541
540
  operations.delete(packet.id);
542
541
  throw new Error('UPLOAD_LIMIT');
@@ -561,10 +560,7 @@ export async function createFederationRuntime(app, directory, handlers, options
561
560
  void runHttp(packet.id, operation);
562
561
  }
563
562
  else if (packet.type === 'ack') {
564
- const operation = operations.get(packet.id);
565
- operation?.ack?.();
566
- if (operation)
567
- operation.ack = undefined;
563
+ operations.get(packet.id)?.responseWindow.acknowledge();
568
564
  }
569
565
  else if (packet.type === 'cancel') {
570
566
  const operation = operations.get(packet.id);
@@ -573,7 +569,7 @@ export async function createFederationRuntime(app, directory, handlers, options
573
569
  operations.delete(packet.id);
574
570
  }
575
571
  else if (packet.type === 'ws-open') {
576
- if (sockets.size >= MAX_OPEN_SECURE_SOCKETS || operations.has(packet.id) || sockets.has(packet.id))
572
+ if ((context.singleOperation ? operations.size + sockets.size >= 1 : sockets.size >= MAX_OPEN_SECURE_SOCKETS) || operations.has(packet.id) || sockets.has(packet.id))
577
573
  throw new Error('STREAM_LIMIT');
578
574
  if (typeof packet.path !== 'string' || !isBusinessApiPath('GET', packet.path))
579
575
  throw new Error('API_NOT_ALLOWED');
@@ -591,7 +587,7 @@ export async function createFederationRuntime(app, directory, handlers, options
591
587
  }
592
588
  else
593
589
  throw new Error('API_NOT_ALLOWED');
594
- const logical = new LogicalSocket(channel, packet.id, () => (androidMatch || computer) ? full(subjectId) : allowed(subjectId, match ? 'session.view' : 'service.view', match?.[1]), match ? 1024 * 1024 : undefined);
590
+ const logical = new LogicalSocket(channel, packet.id, () => (androidMatch || computer) ? full(subjectId) : allowed(subjectId, match ? 'session.view' : 'service.view', match?.[1]), match ? 1024 * 1024 : undefined, !!match && packet.compression === 'gzip');
595
591
  sockets.set(packet.id, { socket: logical, sessionId: match?.[1], android: Boolean(androidMatch), computer,
596
592
  computerProtocol: computer ? url.searchParams.get('protocol') ?? 'vnc' : undefined });
597
593
  logical.once('close', () => sockets.delete(packet.id));
@@ -665,7 +661,7 @@ export async function createFederationRuntime(app, directory, handlers, options
665
661
  }
666
662
  }
667
663
  catch {
668
- socket.close(4003, 'Secure channel closed');
664
+ duplex.close?.(new Error('Secure channel closed'));
669
665
  }
670
666
  finally {
671
667
  unregisterCollaboration?.();
@@ -687,6 +683,8 @@ export async function createFederationRuntime(app, directory, handlers, options
687
683
  }
688
684
  }
689
685
  }
690
- return { serviceId, identity, store, accept, close() { for (const channel of channels)
686
+ return { serviceId, identity, store, acceptDuplex,
687
+ accept(socket, context = {}) { return acceptDuplex(socketDuplex(socket), context); },
688
+ close() { for (const channel of channels)
691
689
  channel.close(); internal.close(); } };
692
690
  }
@@ -0,0 +1,62 @@
1
+ /** One reliable QUIC stream carries one independently authenticated Noise
2
+ * channel. Closing it never closes unrelated streams in the QUIC session. */
3
+ export function streamDuplex(stream) {
4
+ const reader = stream.readable.getReader();
5
+ const writer = stream.writable.getWriter();
6
+ let closed = false;
7
+ let writingBytes = 0;
8
+ const close = (error) => {
9
+ if (closed)
10
+ return;
11
+ closed = true;
12
+ void reader.cancel(error).catch(() => { });
13
+ void (error ? writer.abort(error) : writer.close()).catch(() => { });
14
+ };
15
+ return {
16
+ close,
17
+ bufferedBytes: () => writingBytes,
18
+ source: {
19
+ async *[Symbol.asyncIterator]() {
20
+ try {
21
+ while (!closed) {
22
+ const { done, value } = await reader.read();
23
+ if (done)
24
+ return;
25
+ if (!(value instanceof Uint8Array))
26
+ throw new Error('Invalid transport stream bytes');
27
+ yield value;
28
+ }
29
+ }
30
+ finally {
31
+ reader.releaseLock();
32
+ }
33
+ },
34
+ },
35
+ async sink(source) {
36
+ try {
37
+ for await (const chunk of source) {
38
+ for (let offset = 0; offset < chunk.byteLength; offset += 64 * 1024) {
39
+ if (closed)
40
+ throw new Error('Transport stream closed');
41
+ const bytes = chunk.subarray(offset, offset + 64 * 1024);
42
+ writingBytes = bytes.byteLength;
43
+ try {
44
+ await writer.write(bytes);
45
+ }
46
+ finally {
47
+ writingBytes = 0;
48
+ }
49
+ }
50
+ }
51
+ await writer.close();
52
+ }
53
+ catch (error) {
54
+ close(error instanceof Error ? error : new Error('Transport stream failed'));
55
+ throw error;
56
+ }
57
+ finally {
58
+ writer.releaseLock();
59
+ }
60
+ },
61
+ };
62
+ }
@@ -0,0 +1,50 @@
1
+ /** Application flow control inside Noise. Old peers retain one chunk in flight. */
2
+ export const TRANSFER_CHUNK_BYTES = 64 * 1024;
3
+ export const MAX_TRANSFER_WINDOW = 8;
4
+ export function transferWindow(value) {
5
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1
6
+ ? Math.min(value, MAX_TRANSFER_WINDOW) : 1;
7
+ }
8
+ /** One producer and ordered acknowledgements; unsolicited ACKs grant no credit. */
9
+ export class TransferWindow {
10
+ limit;
11
+ signal;
12
+ outstanding = 0;
13
+ wake;
14
+ constructor(limit, signal) {
15
+ this.limit = limit;
16
+ this.signal = signal;
17
+ }
18
+ sent() {
19
+ if (this.outstanding >= this.limit)
20
+ throw new Error('Transfer window exceeded');
21
+ this.outstanding++;
22
+ }
23
+ acknowledge() {
24
+ if (this.outstanding === 0)
25
+ return;
26
+ this.outstanding--;
27
+ this.wake?.();
28
+ }
29
+ async wait(drained = false) {
30
+ while (true) {
31
+ if (this.signal.aborted)
32
+ throw this.signal.reason ?? new Error('CANCELLED');
33
+ if (this.outstanding < (drained ? 1 : this.limit))
34
+ return;
35
+ await new Promise((resolve, reject) => {
36
+ const cleanup = () => {
37
+ clearTimeout(timer);
38
+ this.signal.removeEventListener('abort', abort);
39
+ this.wake = undefined;
40
+ };
41
+ const abort = () => { cleanup(); reject(this.signal.reason ?? new Error('CANCELLED')); };
42
+ const timer = setTimeout(() => { cleanup(); reject(new Error('CONSUMER_TIMEOUT')); }, 30_000);
43
+ this.wake = () => { cleanup(); resolve(); };
44
+ this.signal.addEventListener('abort', abort, { once: true });
45
+ if (this.signal.aborted)
46
+ abort();
47
+ });
48
+ }
49
+ }
50
+ }