@cc-monitoring/proxy-core 0.1.5 → 0.1.7

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 (445) hide show
  1. package/dist/docs/404.html +22 -0
  2. package/dist/docs/assets/app.BxFOH0P1.js +1 -0
  3. package/dist/docs/assets/chunks/@localSearchIndexroot.Cuu7C9vz.js +1 -0
  4. package/dist/docs/assets/chunks/VPLocalSearchBox.CYDhNgXW.js +9 -0
  5. package/dist/docs/assets/chunks/abnfDiagram-VRR7QNED.RG1C5NpS.js +1 -0
  6. package/dist/docs/assets/chunks/arc.C9NMazfV.js +1 -0
  7. package/dist/docs/assets/chunks/architectureDiagram-ZJ3FMSHR.u2IZtOa6.js +36 -0
  8. package/dist/docs/assets/chunks/blockDiagram-677ZJIJ3.DdHVir7t.js +132 -0
  9. package/dist/docs/assets/chunks/c4Diagram-LMCZKHZV.gSbgoaJo.js +10 -0
  10. package/dist/docs/assets/chunks/channel.Cc6zpfFP.js +1 -0
  11. package/dist/docs/assets/chunks/chunk-2Q5K7J3B.HRSdtksv.js +1 -0
  12. package/dist/docs/assets/chunks/chunk-32BRIVSS.BYzKapof.js +1 -0
  13. package/dist/docs/assets/chunks/chunk-5VM5RSS4.c3oeF0uS.js +15 -0
  14. package/dist/docs/assets/chunks/chunk-EX3LRPZG.Cz5AKl7t.js +231 -0
  15. package/dist/docs/assets/chunks/chunk-JWPE2WC7.DtJxsA7-.js +1 -0
  16. package/dist/docs/assets/chunks/chunk-MOJQB5TN.h5kO0Dtu.js +88 -0
  17. package/dist/docs/assets/chunks/chunk-RYQCIY6F.Ch_NfMTR.js +1 -0
  18. package/dist/docs/assets/chunks/chunk-V7JOEXUC.CHrHyPoW.js +206 -0
  19. package/dist/docs/assets/chunks/chunk-VR4S4FIN.DG8DIrH3.js +1 -0
  20. package/dist/docs/assets/chunks/chunk-XXDRQBXY.CSXBN12Y.js +1 -0
  21. package/dist/docs/assets/chunks/classDiagram-OUVF2IWQ.DV5B4KLJ.js +1 -0
  22. package/dist/docs/assets/chunks/classDiagram-v2-EOCWNBFH.DV5B4KLJ.js +1 -0
  23. package/dist/docs/assets/chunks/cose-bilkent-JH36ORCC.BeFuOTgi.js +1 -0
  24. package/dist/docs/assets/chunks/cynefin-VYW2F7L2.DaXIfh7Y.js +178 -0
  25. package/dist/docs/assets/chunks/cynefinDiagram-TSTJHNR4.BrJcHEEe.js +62 -0
  26. package/dist/docs/assets/chunks/cytoscape.esm.CUqq0XTU.js +331 -0
  27. package/dist/docs/assets/chunks/dagre-VKFMJZFB.D4vaA23X.js +4 -0
  28. package/dist/docs/assets/chunks/defaultLocale.DX6XiGOO.js +1 -0
  29. package/dist/docs/assets/chunks/diagram-FQU43EPY.uwRFLKRx.js +3 -0
  30. package/dist/docs/assets/chunks/diagram-G47NLZAW.Byfc9d0H.js +24 -0
  31. package/dist/docs/assets/chunks/diagram-NH7WQ7WH.CxjBEGZX.js +24 -0
  32. package/dist/docs/assets/chunks/diagram-OA4YK3LP.CU1jGXMi.js +30 -0
  33. package/dist/docs/assets/chunks/diagram-WEI45ONY.yXgVkURA.js +41 -0
  34. package/dist/docs/assets/chunks/ebnfDiagram-CCIWWBDH.UucqGQ_d.js +1 -0
  35. package/dist/docs/assets/chunks/erDiagram-Q63AITRT.C6qmOrvh.js +85 -0
  36. package/dist/docs/assets/chunks/flowDiagram-23GEKE2U.BZLu-WUl.js +156 -0
  37. package/dist/docs/assets/chunks/framework.D_Xv2a7c.js +19 -0
  38. package/dist/docs/assets/chunks/ganttDiagram-NO4QXBWP.DUzsw4Yr.js +292 -0
  39. package/dist/docs/assets/chunks/gitGraphDiagram-IHSO6WYX.BqLfYTI7.js +106 -0
  40. package/dist/docs/assets/chunks/graph.C2PyVmSI.js +1 -0
  41. package/dist/docs/assets/chunks/infoDiagram-FWYZ7A6U.CiKWveW9.js +2 -0
  42. package/dist/docs/assets/chunks/init.Gi6I4Gst.js +1 -0
  43. package/dist/docs/assets/chunks/ishikawaDiagram-FXEZZL3T.jerUXEXA.js +70 -0
  44. package/dist/docs/assets/chunks/journeyDiagram-5HDEW3XC.Cqzvo6I_.js +139 -0
  45. package/dist/docs/assets/chunks/kanban-definition-HUTT4EX6.BzJ4OPe5.js +89 -0
  46. package/dist/docs/assets/chunks/katex.C5jXJg4s.js +257 -0
  47. package/dist/docs/assets/chunks/layout.BG3qr61M.js +1 -0
  48. package/dist/docs/assets/chunks/linear.hFjgYGMN.js +1 -0
  49. package/dist/docs/assets/chunks/map.DwDi8XlU.js +1 -0
  50. package/dist/docs/assets/chunks/mermaid-client.D3gEaJ5e.js +2 -0
  51. package/dist/docs/assets/chunks/mermaid.core.CEHdFh45.js +314 -0
  52. package/dist/docs/assets/chunks/mindmap-definition-LN4V7U3C.ChC5FJW6.js +96 -0
  53. package/dist/docs/assets/chunks/ordinal.BYWQX77i.js +1 -0
  54. package/dist/docs/assets/chunks/pegDiagram-2B236MQR.ClnjsRYs.js +1 -0
  55. package/dist/docs/assets/chunks/pieDiagram-ENE6RG2P.Bb0MqerK.js +39 -0
  56. package/dist/docs/assets/chunks/quadrantDiagram-ABIIQ3AL.Do6HK_yb.js +7 -0
  57. package/dist/docs/assets/chunks/railroadDiagram-RFXS5EU6.D35m6hQn.js +1 -0
  58. package/dist/docs/assets/chunks/requirementDiagram-TGXJPOKE.DMtjRYUg.js +84 -0
  59. package/dist/docs/assets/chunks/sankeyDiagram-HTMAVEWB.dfXDu62B.js +40 -0
  60. package/dist/docs/assets/chunks/sequenceDiagram-DBY2YBRQ.CLZ0rZTY.js +162 -0
  61. package/dist/docs/assets/chunks/sizeCapture-X5ZJPWSS.DWvGYLUT.js +1 -0
  62. package/dist/docs/assets/chunks/stateDiagram-2N3HPSRC.DY8sDkI0.js +1 -0
  63. package/dist/docs/assets/chunks/stateDiagram-v2-6OUMAXLB.B9v-Vq5L.js +1 -0
  64. package/dist/docs/assets/chunks/swimlanes-5IMT3BWC.Dy9SffeT.js +2 -0
  65. package/dist/docs/assets/chunks/swimlanesDiagram-G3AALYLV.Kb9LnCTH.js +8 -0
  66. package/dist/docs/assets/chunks/theme.BLEczZWC.js +2 -0
  67. package/dist/docs/assets/chunks/timeline-definition-FHXFAJF6.CH6uzgIu.js +120 -0
  68. package/dist/docs/assets/chunks/vennDiagram-L72KCM5P.7EBCJmyP.js +34 -0
  69. package/dist/docs/assets/chunks/wardleyDiagram-EHGQE667.DPHAQssL.js +78 -0
  70. package/dist/docs/assets/chunks/xychartDiagram-FW5EYKEG.aKgxZVbK.js +7 -0
  71. package/dist/docs/assets/index.md.p9floL_p.js +1 -0
  72. package/dist/docs/assets/index.md.p9floL_p.lean.js +1 -0
  73. package/dist/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  74. package/dist/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  75. package/dist/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  76. package/dist/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  77. package/dist/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  78. package/dist/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  79. package/dist/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  80. package/dist/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  81. package/dist/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  82. package/dist/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  83. package/dist/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  84. package/dist/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  85. package/dist/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  86. package/dist/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  87. package/dist/docs/assets/overview.md.BKVdLT3o.js +70 -0
  88. package/dist/docs/assets/overview.md.BKVdLT3o.lean.js +1 -0
  89. package/dist/docs/assets/packages-utils.md.CvgYp5Ll.js +31 -0
  90. package/dist/docs/assets/packages-utils.md.CvgYp5Ll.lean.js +1 -0
  91. package/dist/docs/assets/proxy-admin_env-and-build.md.xkeQNYS3.js +40 -0
  92. package/dist/docs/assets/proxy-admin_env-and-build.md.xkeQNYS3.lean.js +1 -0
  93. package/dist/docs/assets/proxy-admin_index.md.DBLI0n0G.js +38 -0
  94. package/dist/docs/assets/proxy-admin_index.md.DBLI0n0G.lean.js +1 -0
  95. package/dist/docs/assets/proxy-admin_layout-and-menu.md.BKGcu49p.js +48 -0
  96. package/dist/docs/assets/proxy-admin_layout-and-menu.md.BKGcu49p.lean.js +1 -0
  97. package/dist/docs/assets/proxy-admin_pages.md.m_fGvvOH.js +51 -0
  98. package/dist/docs/assets/proxy-admin_pages.md.m_fGvvOH.lean.js +1 -0
  99. package/dist/docs/assets/proxy-admin_routing-and-auth.md.DZsdFese.js +106 -0
  100. package/dist/docs/assets/proxy-admin_routing-and-auth.md.DZsdFese.lean.js +1 -0
  101. package/dist/docs/assets/proxy-admin_services-and-mock.md.sdNPcf25.js +66 -0
  102. package/dist/docs/assets/proxy-admin_services-and-mock.md.sdNPcf25.lean.js +1 -0
  103. package/dist/docs/assets/proxy-cli_api-layer.md.GfdbtEUx.js +1 -0
  104. package/dist/docs/assets/proxy-cli_api-layer.md.GfdbtEUx.lean.js +1 -0
  105. package/dist/docs/assets/proxy-cli_app-shell.md.Do18CYhW.js +83 -0
  106. package/dist/docs/assets/proxy-cli_app-shell.md.Do18CYhW.lean.js +1 -0
  107. package/dist/docs/assets/proxy-cli_components-common.md.Dd6Yazvz.js +23 -0
  108. package/dist/docs/assets/proxy-cli_components-common.md.Dd6Yazvz.lean.js +1 -0
  109. package/dist/docs/assets/proxy-cli_components-config.md.B81Y3ta2.js +46 -0
  110. package/dist/docs/assets/proxy-cli_components-config.md.B81Y3ta2.lean.js +1 -0
  111. package/dist/docs/assets/proxy-cli_components-requests.md.vN8IrwL_.js +84 -0
  112. package/dist/docs/assets/proxy-cli_components-requests.md.vN8IrwL_.lean.js +1 -0
  113. package/dist/docs/assets/proxy-cli_components-stats.md.B90esaNa.js +14 -0
  114. package/dist/docs/assets/proxy-cli_components-stats.md.B90esaNa.lean.js +1 -0
  115. package/dist/docs/assets/proxy-cli_components-status.md.C5lAzS2c.js +42 -0
  116. package/dist/docs/assets/proxy-cli_components-status.md.C5lAzS2c.lean.js +1 -0
  117. package/dist/docs/assets/proxy-cli_data-hooks.md.w9Oe1OD3.js +87 -0
  118. package/dist/docs/assets/proxy-cli_data-hooks.md.w9Oe1OD3.lean.js +1 -0
  119. package/dist/docs/assets/proxy-cli_index.md.BA6g8QD-.js +34 -0
  120. package/dist/docs/assets/proxy-cli_index.md.BA6g8QD-.lean.js +1 -0
  121. package/dist/docs/assets/proxy-cli_utils-and-i18n.md.Ch_e-g_o.js +34 -0
  122. package/dist/docs/assets/proxy-cli_utils-and-i18n.md.Ch_e-g_o.lean.js +1 -0
  123. package/dist/docs/assets/proxy-core_chat-api.md.DHihiBxR.js +152 -0
  124. package/dist/docs/assets/proxy-core_chat-api.md.DHihiBxR.lean.js +1 -0
  125. package/dist/docs/assets/proxy-core_cli.md.DCFYX4Bd.js +37 -0
  126. package/dist/docs/assets/proxy-core_cli.md.DCFYX4Bd.lean.js +1 -0
  127. package/dist/docs/assets/proxy-core_config.md.BXSOyxYE.js +83 -0
  128. package/dist/docs/assets/proxy-core_config.md.BXSOyxYE.lean.js +1 -0
  129. package/dist/docs/assets/proxy-core_data-layer.md.Cdomb3Gz.js +85 -0
  130. package/dist/docs/assets/proxy-core_data-layer.md.Cdomb3Gz.lean.js +1 -0
  131. package/dist/docs/assets/proxy-core_entry.md.BZmIcCUM.js +90 -0
  132. package/dist/docs/assets/proxy-core_entry.md.BZmIcCUM.lean.js +1 -0
  133. package/dist/docs/assets/proxy-core_index.md.BM6VV5Qe.js +55 -0
  134. package/dist/docs/assets/proxy-core_index.md.BM6VV5Qe.lean.js +1 -0
  135. package/dist/docs/assets/proxy-core_pm2.md.DUhWEtgn.js +79 -0
  136. package/dist/docs/assets/proxy-core_pm2.md.DUhWEtgn.lean.js +1 -0
  137. package/dist/docs/assets/proxy-core_providers.md.CbDZ6b_7.js +1 -0
  138. package/dist/docs/assets/proxy-core_providers.md.CbDZ6b_7.lean.js +1 -0
  139. package/dist/docs/assets/proxy-core_proxy.md.CzQYmX6X.js +46 -0
  140. package/dist/docs/assets/proxy-core_proxy.md.CzQYmX6X.lean.js +1 -0
  141. package/dist/docs/assets/proxy-core_stats.md.BsM6wuK_.js +42 -0
  142. package/dist/docs/assets/proxy-core_stats.md.BsM6wuK_.lean.js +1 -0
  143. package/dist/docs/assets/proxy-core_tool.md.B6Le1nQr.js +100 -0
  144. package/dist/docs/assets/proxy-core_tool.md.B6Le1nQr.lean.js +1 -0
  145. package/dist/docs/assets/proxy-core_ui-routes.md.Dyqkeoiv.js +27 -0
  146. package/dist/docs/assets/proxy-core_ui-routes.md.Dyqkeoiv.lean.js +1 -0
  147. package/dist/docs/assets/proxy-core_utilities.md.C18pjnkz.js +63 -0
  148. package/dist/docs/assets/proxy-core_utilities.md.C18pjnkz.lean.js +1 -0
  149. package/dist/docs/assets/quickstart.md.Cy_FmXIY.js +38 -0
  150. package/dist/docs/assets/quickstart.md.Cy_FmXIY.lean.js +1 -0
  151. package/dist/docs/assets/request-flow.md.C1fyxdPE.js +146 -0
  152. package/dist/docs/assets/request-flow.md.C1fyxdPE.lean.js +1 -0
  153. package/dist/docs/assets/style.DU_kNMWy.css +1 -0
  154. package/dist/docs/hashmap.json +1 -0
  155. package/dist/docs/index.html +25 -0
  156. package/dist/docs/overview.html +94 -0
  157. package/dist/docs/packages-utils.html +55 -0
  158. package/dist/docs/proxy-admin/env-and-build.html +64 -0
  159. package/dist/docs/proxy-admin/index.html +62 -0
  160. package/dist/docs/proxy-admin/layout-and-menu.html +72 -0
  161. package/dist/docs/proxy-admin/pages.html +75 -0
  162. package/dist/docs/proxy-admin/routing-and-auth.html +130 -0
  163. package/dist/docs/proxy-admin/services-and-mock.html +90 -0
  164. package/dist/docs/proxy-cli/api-layer.html +38 -0
  165. package/dist/docs/proxy-cli/app-shell.html +107 -0
  166. package/dist/docs/proxy-cli/components-common.html +47 -0
  167. package/dist/docs/proxy-cli/components-config.html +70 -0
  168. package/dist/docs/proxy-cli/components-requests.html +108 -0
  169. package/dist/docs/proxy-cli/components-stats.html +38 -0
  170. package/dist/docs/proxy-cli/components-status.html +66 -0
  171. package/dist/docs/proxy-cli/data-hooks.html +111 -0
  172. package/dist/docs/proxy-cli/index.html +58 -0
  173. package/dist/docs/proxy-cli/utils-and-i18n.html +58 -0
  174. package/dist/docs/proxy-core/chat-api.html +176 -0
  175. package/dist/docs/proxy-core/cli.html +61 -0
  176. package/dist/docs/proxy-core/config.html +107 -0
  177. package/dist/docs/proxy-core/data-layer.html +109 -0
  178. package/dist/docs/proxy-core/entry.html +114 -0
  179. package/dist/docs/proxy-core/index.html +79 -0
  180. package/dist/docs/proxy-core/pm2.html +103 -0
  181. package/dist/docs/proxy-core/providers.html +39 -0
  182. package/dist/docs/proxy-core/proxy.html +70 -0
  183. package/dist/docs/proxy-core/stats.html +66 -0
  184. package/dist/docs/proxy-core/tool.html +124 -0
  185. package/dist/docs/proxy-core/ui-routes.html +51 -0
  186. package/dist/docs/proxy-core/utilities.html +87 -0
  187. package/dist/docs/quickstart.html +62 -0
  188. package/dist/docs/request-flow.html +170 -0
  189. package/dist/docs/vp-icons.css +0 -0
  190. package/dist/server/proxy.js +2 -1
  191. package/dist/ui/assets/{1c-KmWe8RWs.js → 1c-DPsrzNHI.js} +1 -1
  192. package/dist/ui/assets/{abnf-BKQ6qIuo.js → abnf-DNkBIQRO.js} +1 -1
  193. package/dist/ui/assets/{abnfDiagram-VRR7QNED-CkRuDPu1.js → abnfDiagram-VRR7QNED-BqvHvzR8.js} +1 -1
  194. package/dist/ui/assets/{accesslog-DD9H5Ktc.js → accesslog-D5NxQ43Q.js} +1 -1
  195. package/dist/ui/assets/{actionscript-CAjf2Qtd.js → actionscript-DLr-LB2m.js} +1 -1
  196. package/dist/ui/assets/{ada-BXkXW16O.js → ada-BRSz3tHX.js} +1 -1
  197. package/dist/ui/assets/{angelscript-BxT7o0Up.js → angelscript-DMtEGgIa.js} +1 -1
  198. package/dist/ui/assets/{apache-C5z_tmVm.js → apache-C4gn4cSd.js} +1 -1
  199. package/dist/ui/assets/{applescript-DdIxl8rr.js → applescript-DoodcTwg.js} +1 -1
  200. package/dist/ui/assets/{arc-hSdFaqKn.js → arc-HmnzaGf9.js} +1 -1
  201. package/dist/ui/assets/{arcade-D5m0roat.js → arcade-RJZZSHSl.js} +1 -1
  202. package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-DOSHSqzf.js → architectureDiagram-ZJ3FMSHR-BUfDpSIw.js} +1 -1
  203. package/dist/ui/assets/{arduino-FDap8kq-.js → arduino-n6Dpx6Ig.js} +1 -1
  204. package/dist/ui/assets/{armasm-Kzp-Jr1v.js → armasm-DzCVITGB.js} +1 -1
  205. package/dist/ui/assets/{asciidoc-DbGMW3EE.js → asciidoc-CaqMsApq.js} +1 -1
  206. package/dist/ui/assets/{aspectj-CVYMmBCO.js → aspectj-B0kIcV0v.js} +1 -1
  207. package/dist/ui/assets/{autohotkey-9PmBGTPd.js → autohotkey-xUEXewap.js} +1 -1
  208. package/dist/ui/assets/{autoit-B4F86jgh.js → autoit-D3OfN2VX.js} +1 -1
  209. package/dist/ui/assets/{avrasm-CSzv2eHX.js → avrasm-Cbf0F4Kf.js} +1 -1
  210. package/dist/ui/assets/{awk-CjsvYvZE.js → awk-Cc0rWEwe.js} +1 -1
  211. package/dist/ui/assets/{axapta-BVgMoNRY.js → axapta-BKEeoUEe.js} +1 -1
  212. package/dist/ui/assets/{bash-IeBjW3pt.js → bash-D6JH6L3m.js} +1 -1
  213. package/dist/ui/assets/{basic-BTFJfmV1.js → basic-ka6JXc9C.js} +1 -1
  214. package/dist/ui/assets/{blockDiagram-677ZJIJ3-DLw3Bbhf.js → blockDiagram-677ZJIJ3-BHXRSjnM.js} +1 -1
  215. package/dist/ui/assets/{bnf-rCkeRYk0.js → bnf-Bxclk5tZ.js} +1 -1
  216. package/dist/ui/assets/{brainfuck-DBHuB3uZ.js → brainfuck--s_Fd8b9.js} +1 -1
  217. package/dist/ui/assets/{coq-TwFFolHa.js → c-BsgdDna0.js} +1 -1
  218. package/dist/ui/assets/{c-like-CK1xGeX_.js → c-like-CNkOkbqh.js} +1 -1
  219. package/dist/ui/assets/{c4Diagram-LMCZKHZV-cqY51yJw.js → c4Diagram-LMCZKHZV-Bp1uSrW8.js} +1 -1
  220. package/dist/ui/assets/{cal-BxGPpEZK.js → cal-LVlIOy9W.js} +1 -1
  221. package/dist/ui/assets/{capnproto-Bo2fgXF9.js → capnproto-r9DiQ1H8.js} +1 -1
  222. package/dist/ui/assets/{ceylon-C4Bb4pNB.js → ceylon-CTNzyZJX.js} +1 -1
  223. package/dist/ui/assets/channel-_rFUXR2i.js +1 -0
  224. package/dist/ui/assets/{chunk-2Q5K7J3B-CGTiTBmo.js → chunk-2Q5K7J3B-nnLVtUW3.js} +1 -1
  225. package/dist/ui/assets/{chunk-32BRIVSS-DWagYBp9.js → chunk-32BRIVSS-BDNS6igp.js} +1 -1
  226. package/dist/ui/assets/{chunk-5VM5RSS4-BzSBMKJX.js → chunk-5VM5RSS4-D713xBhI.js} +1 -1
  227. package/dist/ui/assets/{chunk-EX3LRPZG-4-aKwCgZ.js → chunk-EX3LRPZG-DExsU6Rd.js} +1 -1
  228. package/dist/ui/assets/{chunk-JWPE2WC7-CPC_cBN0.js → chunk-JWPE2WC7-DcpW5RnW.js} +1 -1
  229. package/dist/ui/assets/{chunk-MOJQB5TN-DrDE4H9w.js → chunk-MOJQB5TN-BQiSZNTn.js} +1 -1
  230. package/dist/ui/assets/{chunk-RYQCIY6F-DkdXe_kU.js → chunk-RYQCIY6F-DfblgZPd.js} +1 -1
  231. package/dist/ui/assets/{chunk-V7JOEXUC-Da6EWcQt.js → chunk-V7JOEXUC-np--VgmN.js} +1 -1
  232. package/dist/ui/assets/{chunk-VR4S4FIN-nP6dstD5.js → chunk-VR4S4FIN-BG0IhjO6.js} +1 -1
  233. package/dist/ui/assets/{chunk-XXDRQBXY-Bi_rRAPA.js → chunk-XXDRQBXY-DHuoh-RB.js} +1 -1
  234. package/dist/ui/assets/classDiagram-OUVF2IWQ-DqgbMzM1.js +1 -0
  235. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-DqgbMzM1.js +1 -0
  236. package/dist/ui/assets/{clean-cc1m9AxK.js → clean-CtVj0-EB.js} +1 -1
  237. package/dist/ui/assets/{clojure-DX5V8QA8.js → clojure-CZwle60-.js} +1 -1
  238. package/dist/ui/assets/{clojure-repl-FzjnVNWQ.js → clojure-repl-DJXWH00I.js} +1 -1
  239. package/dist/ui/assets/{cmake-COZZyrKs.js → cmake-Boxf0e7r.js} +1 -1
  240. package/dist/ui/assets/{coffeescript-DBsnOmC4.js → coffeescript-h85ZW4Gm.js} +1 -1
  241. package/dist/ui/assets/{c-C95V0zHL.js → coq-CVLui3m8.js} +1 -1
  242. package/dist/ui/assets/{cos-Dm5g-IQT.js → cos-CL0igafw.js} +1 -1
  243. package/dist/ui/assets/{cose-bilkent-JH36ORCC-B3-weOQF.js → cose-bilkent-JH36ORCC-CnXyotYB.js} +1 -1
  244. package/dist/ui/assets/{cpp-_RZxQjg7.js → cpp-vite1NvJ.js} +1 -1
  245. package/dist/ui/assets/{crmsh-DGPJ11Gt.js → crmsh-DqT9g0Iq.js} +1 -1
  246. package/dist/ui/assets/{crystal-BOMSPGge.js → crystal-Oans-K8G.js} +1 -1
  247. package/dist/ui/assets/{csharp-DZXiHH72.js → csharp-sCaDAzIB.js} +1 -1
  248. package/dist/ui/assets/{csp-DDSIMUoU.js → csp-rMcp93pK.js} +1 -1
  249. package/dist/ui/assets/{css-Bjye-ZWr.js → css-BwDLHi_h.js} +1 -1
  250. package/dist/ui/assets/{cynefin-VYW2F7L2-Cj5c4L3y.js → cynefin-VYW2F7L2-D8Bmecdd.js} +1 -1
  251. package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-BYsfTeNX.js → cynefinDiagram-TSTJHNR4-BT2YFmPZ.js} +1 -1
  252. package/dist/ui/assets/{d-22pfurOx.js → d-BFgZm0RV.js} +1 -1
  253. package/dist/ui/assets/{dagre-VKFMJZFB-DiEob-by.js → dagre-VKFMJZFB-BeJU73ex.js} +1 -1
  254. package/dist/ui/assets/{dart-Doiu8cDW.js → dart-rIo85iL3.js} +1 -1
  255. package/dist/ui/assets/{delphi-CQ7epp84.js → delphi-Bi2Rfp1o.js} +1 -1
  256. package/dist/ui/assets/{diagram-FQU43EPY-BOPbQcL4.js → diagram-FQU43EPY-CHQiS5Fr.js} +1 -1
  257. package/dist/ui/assets/{diagram-G47NLZAW-C1UWDJTx.js → diagram-G47NLZAW-EVerd4V8.js} +1 -1
  258. package/dist/ui/assets/{diagram-NH7WQ7WH-CYsBqW3J.js → diagram-NH7WQ7WH-DMP0VOAs.js} +1 -1
  259. package/dist/ui/assets/{diagram-OA4YK3LP-Dnag0x_3.js → diagram-OA4YK3LP-CAur5jK9.js} +1 -1
  260. package/dist/ui/assets/{diagram-WEI45ONY-Bo4CsDoj.js → diagram-WEI45ONY-DvmKkPH7.js} +1 -1
  261. package/dist/ui/assets/{diff-Cs6VQQZt.js → diff-CZZCIG00.js} +1 -1
  262. package/dist/ui/assets/{django-Bo3okOrw.js → django-D88PKHy-.js} +1 -1
  263. package/dist/ui/assets/{dns-BpG60eIX.js → dns-DX4hzjUh.js} +1 -1
  264. package/dist/ui/assets/{dockerfile-BWyH8SlV.js → dockerfile-1lgzEXn1.js} +1 -1
  265. package/dist/ui/assets/{dos-DWlNbaB9.js → dos-CwrC1ROy.js} +1 -1
  266. package/dist/ui/assets/{dsconfig-D_8y8YrJ.js → dsconfig-tvVdBv4w.js} +1 -1
  267. package/dist/ui/assets/{dts-Cz4SyMYR.js → dts-DTgQkdRs.js} +1 -1
  268. package/dist/ui/assets/{dust-Cu4qLkeH.js → dust-BbLlyCpf.js} +1 -1
  269. package/dist/ui/assets/{ebnf-CTVHui3r.js → ebnf-D6Dc4oRr.js} +1 -1
  270. package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-epcXQLEj.js → ebnfDiagram-CCIWWBDH-Kvilk1RF.js} +1 -1
  271. package/dist/ui/assets/{elixir-MAlwXhfU.js → elixir-CnMolQVs.js} +1 -1
  272. package/dist/ui/assets/{elm-Bdmwbvef.js → elm-BQ7VQFn7.js} +1 -1
  273. package/dist/ui/assets/{erDiagram-Q63AITRT-Bb60TqAM.js → erDiagram-Q63AITRT-C-S9oHZd.js} +1 -1
  274. package/dist/ui/assets/{erb-Ce9TpP4g.js → erb-B_1g6fXE.js} +1 -1
  275. package/dist/ui/assets/{erlang-CN2GEiqk.js → erlang-3b3ITXJu.js} +1 -1
  276. package/dist/ui/assets/{erlang-repl-D8K4O_cp.js → erlang-repl-Cy6Z3TdH.js} +1 -1
  277. package/dist/ui/assets/{excel-eVZU1r0f.js → excel-DtkATto8.js} +1 -1
  278. package/dist/ui/assets/{fix-BzKerEv0.js → fix-DsEG7TDI.js} +1 -1
  279. package/dist/ui/assets/{flix-B9CE3skV.js → flix-CQ-rKwGO.js} +1 -1
  280. package/dist/ui/assets/{flowDiagram-23GEKE2U-DzMLZIyt.js → flowDiagram-23GEKE2U-EbHDNMCC.js} +1 -1
  281. package/dist/ui/assets/{fortran-B4__3vos.js → fortran-AqzaRCEt.js} +1 -1
  282. package/dist/ui/assets/{fsharp-BJ3-ARHz.js → fsharp-CCzWGasu.js} +1 -1
  283. package/dist/ui/assets/{gams-Cu43oSYT.js → gams-Bqa6CB_r.js} +1 -1
  284. package/dist/ui/assets/{ganttDiagram-NO4QXBWP-D_aAoMRP.js → ganttDiagram-NO4QXBWP-B6jvc6O7.js} +1 -1
  285. package/dist/ui/assets/{gauss-T8vk_TpE.js → gauss-D4Utubeh.js} +1 -1
  286. package/dist/ui/assets/{gcode-9j3BicpZ.js → gcode-By3KwWjb.js} +1 -1
  287. package/dist/ui/assets/{gherkin-Dyh5KFG-.js → gherkin-PXOPjT7Y.js} +1 -1
  288. package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-CMxCHC-Z.js → gitGraphDiagram-IHSO6WYX-C5l6rHvK.js} +1 -1
  289. package/dist/ui/assets/{glsl-DWWjN4ts.js → glsl-KmmyBk93.js} +1 -1
  290. package/dist/ui/assets/{gml-BcYE-D5A.js → gml-C1Qw_Nrt.js} +1 -1
  291. package/dist/ui/assets/{go-DUnUzOEI.js → go-DaBQtdp1.js} +1 -1
  292. package/dist/ui/assets/{golo-BDoc1QQL.js → golo-D7PDzNpb.js} +1 -1
  293. package/dist/ui/assets/{gradle-B_WRa_bT.js → gradle-nXueCYH-.js} +1 -1
  294. package/dist/ui/assets/{groovy-CgjqFq1e.js → groovy-DFDsQDhl.js} +1 -1
  295. package/dist/ui/assets/{haml-DCqcg7Ti.js → haml-B_zxHzy_.js} +1 -1
  296. package/dist/ui/assets/{handlebars-DSDUQrnw.js → handlebars-BdMY-8KA.js} +1 -1
  297. package/dist/ui/assets/{haskell-DPVnctVi.js → haskell-CftsIPps.js} +1 -1
  298. package/dist/ui/assets/{haxe-BuCGXBa4.js → haxe-BFZb0OIE.js} +1 -1
  299. package/dist/ui/assets/{hsp-BTKpS_u0.js → hsp-EPTuqwtZ.js} +1 -1
  300. package/dist/ui/assets/{htmlbars-Cql3Jvy2.js → htmlbars-B7ZSC-iN.js} +1 -1
  301. package/dist/ui/assets/{http-BB8I9jUh.js → http-BxSd_aa1.js} +1 -1
  302. package/dist/ui/assets/{hy-DG7xkZNz.js → hy-D-rBN9MQ.js} +1 -1
  303. package/dist/ui/assets/index-CWFn1h-J.css +10 -0
  304. package/dist/ui/assets/{index-CfTIGTiY.js → index-DSGZBcd1.js} +166 -171
  305. package/dist/ui/assets/{index-DqIiCkSD.js → index-Dlp8uGHu.js} +3 -3
  306. package/dist/ui/assets/{infoDiagram-FWYZ7A6U-DIzEV-BJ.js → infoDiagram-FWYZ7A6U-BOF_kBqe.js} +1 -1
  307. package/dist/ui/assets/{inform7-BWNpVEkA.js → inform7-OjpbRXZf.js} +1 -1
  308. package/dist/ui/assets/{ini-BMw_C8EP.js → ini-Dc-QApXQ.js} +1 -1
  309. package/dist/ui/assets/{irpf90-Cy42ibFZ.js → irpf90-C4OfYiST.js} +1 -1
  310. package/dist/ui/assets/{isbl-CjFSc0hz.js → isbl-9km6K6Sf.js} +1 -1
  311. package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-BZcxp5am.js → ishikawaDiagram-FXEZZL3T-BvKSD8LY.js} +1 -1
  312. package/dist/ui/assets/{java-BDxe9dp1.js → java-C2mOf3QX.js} +1 -1
  313. package/dist/ui/assets/{javascript-CgLkkj7h.js → javascript-_i0Q5MkQ.js} +1 -1
  314. package/dist/ui/assets/{jboss-cli-C8biclrb.js → jboss-cli-BS5ipQOv.js} +1 -1
  315. package/dist/ui/assets/{journeyDiagram-5HDEW3XC-BbJu6m6Q.js → journeyDiagram-5HDEW3XC-yKdSl63P.js} +1 -1
  316. package/dist/ui/assets/{json-BjJKhmM6.js → json-Dci0MO4x.js} +1 -1
  317. package/dist/ui/assets/{julia-DvKEpg-R.js → julia-bEqo4nlV.js} +1 -1
  318. package/dist/ui/assets/{julia-repl-BDJWZxkU.js → julia-repl-Co6hf47q.js} +1 -1
  319. package/dist/ui/assets/{kanban-definition-HUTT4EX6-DeIVPlbv.js → kanban-definition-HUTT4EX6-B7BbZCd6.js} +1 -1
  320. package/dist/ui/assets/{kotlin-DCoXcnEb.js → kotlin-krx8WewB.js} +1 -1
  321. package/dist/ui/assets/{lasso-C7m0QmV2.js → lasso-d3ZTv9Tj.js} +1 -1
  322. package/dist/ui/assets/{latex-SHnTG9Eq.js → latex-BNWbHYxK.js} +1 -1
  323. package/dist/ui/assets/{ldif-_6hUnKPV.js → ldif-Bs8eb63L.js} +1 -1
  324. package/dist/ui/assets/{leaf-Co9qxlaF.js → leaf-BTbRDVWB.js} +1 -1
  325. package/dist/ui/assets/{less-CJRDPwNA.js → less-DH5cqJTD.js} +1 -1
  326. package/dist/ui/assets/{lisp-JEHGYbiW.js → lisp-CBUvBYtR.js} +1 -1
  327. package/dist/ui/assets/{livecodeserver-BSYaUj4k.js → livecodeserver-CkM7-E4a.js} +1 -1
  328. package/dist/ui/assets/{livescript-WQMCQeuz.js → livescript-DomXyXUO.js} +1 -1
  329. package/dist/ui/assets/{llvm-DnAHqj5I.js → llvm-e_-ff59-.js} +1 -1
  330. package/dist/ui/assets/{lsl--k-ghYia.js → lsl-BNDsGOmv.js} +1 -1
  331. package/dist/ui/assets/{lua-CXb23hbC.js → lua-_ZmkXwc_.js} +1 -1
  332. package/dist/ui/assets/{makefile-CM7o86yn.js → makefile-BhG7cThe.js} +1 -1
  333. package/dist/ui/assets/{markdown-HB3HvChQ.js → markdown-ClW2SRy6.js} +1 -1
  334. package/dist/ui/assets/{mathematica-9NTuf22N.js → mathematica-kqoCR611.js} +1 -1
  335. package/dist/ui/assets/{matlab-CWv-ik4r.js → matlab-DqawyK3q.js} +1 -1
  336. package/dist/ui/assets/{maxima-CqYiKCrw.js → maxima-B0qzCXe1.js} +1 -1
  337. package/dist/ui/assets/{mel-BbsRpUm5.js → mel-BZaSas3B.js} +1 -1
  338. package/dist/ui/assets/{mercury-Cz2j4HhU.js → mercury-ByD0wyJH.js} +1 -1
  339. package/dist/ui/assets/{mindmap-definition-LN4V7U3C-WyJS8oye.js → mindmap-definition-LN4V7U3C-Ce6QsaH5.js} +1 -1
  340. package/dist/ui/assets/{mipsasm-BqWSRbQV.js → mipsasm-B08lqZSo.js} +1 -1
  341. package/dist/ui/assets/{mizar-JLBfQ6vt.js → mizar-7iaUqWPq.js} +1 -1
  342. package/dist/ui/assets/{mojolicious-D0LbMmyk.js → mojolicious-CbH-d8Wh.js} +1 -1
  343. package/dist/ui/assets/{monkey-DAGL6-JN.js → monkey-D5z6-hFH.js} +1 -1
  344. package/dist/ui/assets/{moonscript-DzbwNSKy.js → moonscript-DuLd7pdm.js} +1 -1
  345. package/dist/ui/assets/{n1ql-dkgKq6Yv.js → n1ql-EbVfQMfD.js} +1 -1
  346. package/dist/ui/assets/{nginx-AUoaDPV4.js → nginx-D-4AxpHP.js} +1 -1
  347. package/dist/ui/assets/{nim-CdqYmVrl.js → nim-wPHQEX5v.js} +1 -1
  348. package/dist/ui/assets/{nix-CxmVjwwo.js → nix-6SVkxAXi.js} +1 -1
  349. package/dist/ui/assets/{node-repl-B1Z3zUAh.js → node-repl-CaFKEOyj.js} +1 -1
  350. package/dist/ui/assets/{nsis-CTAuPWhe.js → nsis-BmqbwVv_.js} +1 -1
  351. package/dist/ui/assets/{objectivec-CvbKeAPz.js → objectivec-BX0R-sI2.js} +1 -1
  352. package/dist/ui/assets/{ocaml-DCiyXKOH.js → ocaml-CyfdrIqo.js} +1 -1
  353. package/dist/ui/assets/{openscad-CPGUwmeR.js → openscad-B5qfaF1E.js} +1 -1
  354. package/dist/ui/assets/{oxygene-CI_bD1Gw.js → oxygene-CmlCgXLr.js} +1 -1
  355. package/dist/ui/assets/{parser3-C91CVs85.js → parser3-DdpPyZkn.js} +1 -1
  356. package/dist/ui/assets/{pegDiagram-2B236MQR-yF8AW7GR.js → pegDiagram-2B236MQR-ByyVqaXh.js} +1 -1
  357. package/dist/ui/assets/{perl-ChxfKl-n.js → perl-D3qc2wEe.js} +1 -1
  358. package/dist/ui/assets/{pf-CKCHkzIA.js → pf-Bv3zza37.js} +1 -1
  359. package/dist/ui/assets/{pgsql-BwOP20uH.js → pgsql-BZIppw1a.js} +1 -1
  360. package/dist/ui/assets/{php-B7Rs2tM5.js → php-D1ScecZC.js} +1 -1
  361. package/dist/ui/assets/{php-template-Cx-Fh4AR.js → php-template-sEqzzKWJ.js} +1 -1
  362. package/dist/ui/assets/{pieDiagram-ENE6RG2P-BS4hnGNX.js → pieDiagram-ENE6RG2P-T1OgWN3l.js} +1 -1
  363. package/dist/ui/assets/{plaintext-U7qkdtgS.js → plaintext-DO7Jy_T2.js} +1 -1
  364. package/dist/ui/assets/{pony-_fGYgePh.js → pony-CTXTp2Tb.js} +1 -1
  365. package/dist/ui/assets/{powershell-CFBTcUce.js → powershell-C9lzZsbj.js} +1 -1
  366. package/dist/ui/assets/{processing-BWHneU0K.js → processing-hzJAP_Li.js} +1 -1
  367. package/dist/ui/assets/{profile-BJ-HxhzS.js → profile-bFiAkh7e.js} +1 -1
  368. package/dist/ui/assets/{prolog-ChHo7n6L.js → prolog-CE0trHSn.js} +1 -1
  369. package/dist/ui/assets/{properties-e_DOYclC.js → properties-MeANnTVc.js} +1 -1
  370. package/dist/ui/assets/{protobuf-5aGSIv7w.js → protobuf-S-rp7SK0.js} +1 -1
  371. package/dist/ui/assets/{puppet-D2vQatzX.js → puppet-B5YT8Ct1.js} +1 -1
  372. package/dist/ui/assets/{purebasic-n6krfaeF.js → purebasic-DO-5HeDl.js} +1 -1
  373. package/dist/ui/assets/{python-CbIo0XxP.js → python-DVGTQbwU.js} +1 -1
  374. package/dist/ui/assets/{python-repl-BpIq9kyr.js → python-repl-CQ4VlKLC.js} +1 -1
  375. package/dist/ui/assets/{q-jntnvcCx.js → q-nS96imov.js} +1 -1
  376. package/dist/ui/assets/{qml-BafQlZNV.js → qml-BkzkCgUU.js} +1 -1
  377. package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-C3Th8mUJ.js → quadrantDiagram-ABIIQ3AL-BkaCzlXD.js} +1 -1
  378. package/dist/ui/assets/{r-CHgvQFLK.js → r-y4Q5t85r.js} +1 -1
  379. package/dist/ui/assets/{railroadDiagram-RFXS5EU6-CMQkbGJl.js → railroadDiagram-RFXS5EU6-C1lbwk19.js} +1 -1
  380. package/dist/ui/assets/{reasonml-DNwlPD_T.js → reasonml-Bzhzc5Ao.js} +1 -1
  381. package/dist/ui/assets/{requirementDiagram-TGXJPOKE-B70_oR7v.js → requirementDiagram-TGXJPOKE-C8Rw6N2I.js} +1 -1
  382. package/dist/ui/assets/{rib-CX4e9JSF.js → rib-BP3Y9dW3.js} +1 -1
  383. package/dist/ui/assets/{roboconf-ee4qsPGf.js → roboconf-87QE7cIh.js} +1 -1
  384. package/dist/ui/assets/{routeros-BJSwvu2L.js → routeros-BV3nt8wW.js} +1 -1
  385. package/dist/ui/assets/{rsl-BiKdMl_F.js → rsl-DfQf4CW_.js} +1 -1
  386. package/dist/ui/assets/{ruby-CAXTU5LY.js → ruby-DQxFKbgX.js} +1 -1
  387. package/dist/ui/assets/{ruleslanguage-C1kgDGXM.js → ruleslanguage-B8oCm_aw.js} +1 -1
  388. package/dist/ui/assets/{rust-DyEf_GXL.js → rust-DzZgPf9W.js} +1 -1
  389. package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-CvUfseMg.js → sankeyDiagram-HTMAVEWB-Dxiuo8Hz.js} +1 -1
  390. package/dist/ui/assets/{sas-Q1rlUxPH.js → sas-CFh-Rsrv.js} +1 -1
  391. package/dist/ui/assets/{scala-Dg6KNmge.js → scala-3UDyJBiS.js} +1 -1
  392. package/dist/ui/assets/{scheme-D9iooUxI.js → scheme-KaUTge9W.js} +1 -1
  393. package/dist/ui/assets/{scilab-CztEJXJY.js → scilab-CLSBZzuh.js} +1 -1
  394. package/dist/ui/assets/{scss-BMh-JkdE.js → scss-DaEkfHWX.js} +1 -1
  395. package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-DB0c9kf4.js → sequenceDiagram-DBY2YBRQ-Cv__zR2v.js} +1 -1
  396. package/dist/ui/assets/{shell-DWo6z0MG.js → shell-B0d4cZTk.js} +1 -1
  397. package/dist/ui/assets/{sizeCapture-X5ZJPWSS-BcQlgjfD.js → sizeCapture-X5ZJPWSS-C4nD-ShQ.js} +1 -1
  398. package/dist/ui/assets/{smali-Cijeb6pL.js → smali-CLhfky4R.js} +1 -1
  399. package/dist/ui/assets/{smalltalk-D0lvqa_d.js → smalltalk-B4aaTMO5.js} +1 -1
  400. package/dist/ui/assets/{sml-B-vqWZ3b.js → sml-x4CTxWEZ.js} +1 -1
  401. package/dist/ui/assets/{sqf-BJ-1Q583.js → sqf-G_0vdVVs.js} +1 -1
  402. package/dist/ui/assets/{sql-CMGLxEYV.js → sql-C--WH0Fo.js} +1 -1
  403. package/dist/ui/assets/{sql_more-gsRmbNCH.js → sql_more-B4LrzCtd.js} +1 -1
  404. package/dist/ui/assets/{stan-D1AlTSpf.js → stan-CACDFOA0.js} +1 -1
  405. package/dist/ui/assets/{stata-DnEYviI0.js → stata-BP9M7sZt.js} +1 -1
  406. package/dist/ui/assets/{stateDiagram-2N3HPSRC-BSRgVsHO.js → stateDiagram-2N3HPSRC-z3-31Cr2.js} +1 -1
  407. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BKIXFHzO.js +1 -0
  408. package/dist/ui/assets/{step21-DbQV9sMo.js → step21-MAOu4dNb.js} +1 -1
  409. package/dist/ui/assets/{stylus-Cyc7vdUc.js → stylus-CpuP3pvE.js} +1 -1
  410. package/dist/ui/assets/{subunit-16ipyMie.js → subunit-NWzuqFhT.js} +1 -1
  411. package/dist/ui/assets/{swift-DTNnw4qS.js → swift-DuFKNmKv.js} +1 -1
  412. package/dist/ui/assets/{swimlanes-5IMT3BWC-DgOdcc4_.js → swimlanes-5IMT3BWC-E463-rXd.js} +2 -2
  413. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-CkQvBOYs.js +8 -0
  414. package/dist/ui/assets/{taggerscript-DM6pvUWE.js → taggerscript-BDnv2jvg.js} +1 -1
  415. package/dist/ui/assets/{tap-Ch-uyKZq.js → tap-aB2cLXdf.js} +1 -1
  416. package/dist/ui/assets/{tcl-D0T_V5dA.js → tcl-7WepIaIa.js} +1 -1
  417. package/dist/ui/assets/{thrift-D9xJjYw4.js → thrift-BLh6pdjc.js} +1 -1
  418. package/dist/ui/assets/{timeline-definition-FHXFAJF6-BBeDMHxb.js → timeline-definition-FHXFAJF6-FA_RNhFQ.js} +1 -1
  419. package/dist/ui/assets/{tp-kUrCGo9X.js → tp-D1rt5u_j.js} +1 -1
  420. package/dist/ui/assets/{twig-Cgub6rxA.js → twig-DgfeYg4W.js} +1 -1
  421. package/dist/ui/assets/{typescript-BxNP9Ap9.js → typescript-oU560Q8V.js} +1 -1
  422. package/dist/ui/assets/{vala-DF9ZZagU.js → vala-DlXsaz2B.js} +1 -1
  423. package/dist/ui/assets/{vbnet-Cf46ypDg.js → vbnet-BjpxjeMZ.js} +1 -1
  424. package/dist/ui/assets/{vbscript-DNs-QKLH.js → vbscript-DfNdtdO3.js} +1 -1
  425. package/dist/ui/assets/{vbscript-html-DyS6I5L1.js → vbscript-html-D09WPsgK.js} +1 -1
  426. package/dist/ui/assets/{vennDiagram-L72KCM5P-8WpWycE-.js → vennDiagram-L72KCM5P-zaCDWwTs.js} +1 -1
  427. package/dist/ui/assets/{verilog-CF5wC4X-.js → verilog-B9vENtLK.js} +1 -1
  428. package/dist/ui/assets/{vhdl-Dm0jpDMn.js → vhdl-CJLTZOu1.js} +1 -1
  429. package/dist/ui/assets/{vim-nyO2DRAx.js → vim-FuPhupu9.js} +1 -1
  430. package/dist/ui/assets/{wardleyDiagram-EHGQE667-UeIOK-jv.js → wardleyDiagram-EHGQE667-BS8ApwmV.js} +1 -1
  431. package/dist/ui/assets/{x86asm-BNw2-6GG.js → x86asm-kX_Cp6wB.js} +1 -1
  432. package/dist/ui/assets/{xl-D-YHxr6V.js → xl-MuHNmLUj.js} +1 -1
  433. package/dist/ui/assets/{xml-BijAlrow.js → xml-Mbn2z12n.js} +1 -1
  434. package/dist/ui/assets/{xquery-z0wxWBKz.js → xquery-Dy4lt-m-.js} +1 -1
  435. package/dist/ui/assets/{xychartDiagram-FW5EYKEG-BNzHLweN.js → xychartDiagram-FW5EYKEG-DoNZtZus.js} +1 -1
  436. package/dist/ui/assets/{yaml-n5TIQArR.js → yaml-CxxAisfE.js} +1 -1
  437. package/dist/ui/assets/{zephir-DrGhH8jG.js → zephir-WWG8qyld.js} +1 -1
  438. package/dist/ui/index.html +2 -2
  439. package/package.json +2 -2
  440. package/dist/ui/assets/channel-D9Y4iN1l.js +0 -1
  441. package/dist/ui/assets/classDiagram-OUVF2IWQ-C4UVH6RI.js +0 -1
  442. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-C4UVH6RI.js +0 -1
  443. package/dist/ui/assets/index-CK_lJsTu.css +0 -10
  444. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BLdfpGJO.js +0 -1
  445. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DRVnkg3M.js +0 -8
@@ -0,0 +1,63 @@
1
+ import{_ as i,o as a,c as n,a2 as t}from"./chunks/framework.D_Xv2a7c.js";const E=JSON.parse('{"title":"proxy-core / 公共工具","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-core/utilities.md","filePath":"proxy-core/utilities.md"}'),h={name:"proxy-core/utilities.md"};function e(k,s,l,p,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t(`<h1 id="proxy-core-公共工具" tabindex="-1">proxy-core / 公共工具 <a class="header-anchor" href="#proxy-core-公共工具" aria-label="Permalink to &quot;proxy-core / 公共工具&quot;">​</a></h1><h2 id="本文档覆盖的源文件" tabindex="-1">本文档覆盖的源文件 <a class="header-anchor" href="#本文档覆盖的源文件" aria-label="Permalink to &quot;本文档覆盖的源文件&quot;">​</a></h2><ul><li><code>apps/proxy-core/src/utils/paths.ts</code></li><li><code>apps/proxy-core/src/utils/esm-dirname.ts</code></li><li><code>apps/proxy-core/src/utils/net.ts</code></li><li><code>apps/proxy-core/src/utils/version.ts</code></li><li><code>apps/proxy-core/src/utils/sse-accumulator.ts</code></li><li><code>apps/proxy-core/src/server/auth.ts</code></li><li><code>apps/proxy-core/src/server/middleware/request-id.ts</code></li><li><code>apps/proxy-core/src/types/*.ts</code></li></ul><h2 id="paths-ts-—-数据目录锚点" tabindex="-1"><code>paths.ts</code> — 数据目录锚点 <a class="header-anchor" href="#paths-ts-—-数据目录锚点" aria-label="Permalink to &quot;\`paths.ts\` — 数据目录锚点&quot;">​</a></h2><p><code>apps/proxy-core/src/utils/paths.ts</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> dataDir</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> path.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">join</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(os.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">homedir</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(), </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;.cc-monitoring&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
2
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> logsDir</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> path.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">join</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(dataDir, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;logs&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
3
+ <span class="line"></span>
4
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> configPathOverride</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span></span>
5
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setConfigPathOverride</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">absPath</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> void</span></span>
6
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getConfigPath</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
7
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> configPathOverride</span></span>
8
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> process.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">CONFIG_PATH</span></span>
9
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> path.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">join</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(dataDir, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;config.json&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
10
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
11
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ensureDataDirs</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> void</span></span></code></pre></div><p><strong>为什么锚定 <code>$HOME/.cc-monitoring</code></strong>:全局 npm/pnpm 安装后 <code>process.cwd()</code> 是用户当前目录(任意),PM2 fork 后 cwd 由 ecosystem 决定;只有主目录相对稳定。所有 config/log/db 都放这里,跨启动方式一致。</p><p><strong>config 路径优先级</strong>:<code>--config &lt;path&gt;</code> CLI 参数 &gt; <code>CONFIG_PATH</code> 环境变量 &gt; 默认 <code>$HOME/.cc-monitoring/config.json</code>。三层策略给 CI/多环境部署留出口子。</p><p><code>ensureDataDirs</code>:首次运行时 <code>mkdirSync(logsDir, { recursive: true })</code>——由 <code>loadConfig</code> 在文件缺失时调用(<code>config/index.ts:10</code>)。</p><h2 id="esm-dirname-ts-—-esm-cjs-双模-dirname" tabindex="-1"><code>esm-dirname.ts</code> — ESM/CJS 双模 __dirname <a class="header-anchor" href="#esm-dirname-ts-—-esm-cjs-双模-dirname" aria-label="Permalink to &quot;\`esm-dirname.ts\` — ESM/CJS 双模 __dirname&quot;">​</a></h2><p>详见 <a href="./pm2.html#esm-__dirname-替代-esm-dirnamets">pm2.md</a>。三个导出:</p><ul><li><code>utilsDirname</code>:本文件目录(编译后 <code>dist/utils/</code>)</li><li><code>getCallerDirname(relativePath)</code>:相对本文件算出调用方目录</li><li><code>getCurrentModuleUrl()</code>:包装 <code>import.meta.url</code></li></ul><p><code>__mocks__/esm-dirname.ts</code> 在 ts-jest CJS 环境下替换整个模块,避免语法错误。</p><h2 id="net-ts-—-端口探测" tabindex="-1"><code>net.ts</code> — 端口探测 <a class="header-anchor" href="#net-ts-—-端口探测" aria-label="Permalink to &quot;\`net.ts\` — 端口探测&quot;">​</a></h2><p><code>apps/proxy-core/src/utils/net.ts</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> tryConnect</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">host</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">port</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">timeout</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Promise</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt; {</span></span>
12
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> Promise</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">((</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">resolve</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
13
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> socket</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> net.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">createConnection</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ host, port })</span></span>
14
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // connect / timeout / error 都 destroy + resolve</span></span>
15
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
16
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
17
+ <span class="line"></span>
18
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> waitForPort</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">host</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">port</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">onAttempt</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Promise</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt; {</span></span>
19
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> target</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">host </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> host </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;0.0.0.0&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> host </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;::&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;127.0.0.1&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> host</span></span>
20
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> for</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> attempt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; attempt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&lt;=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 5</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; attempt</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">++</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
21
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> sleep</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(attempt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 1s + 2s + 3s + 4s + 5s = 15s</span></span>
22
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onAttempt</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">?.(attempt, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">5</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
23
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> tryConnect</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(target, port)) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> true</span></span>
24
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
25
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</span></span>
26
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li><strong>递增退避</strong>:而非固定间隔,让服务启动慢时也能等到</li><li><strong>0.0.0.0 → 127.0.0.1</strong>:<code>0.0.0.0</code> 是监听通配符,连接需要具体 IP</li><li><strong>回调</strong>:<code>onAttempt</code> 让 CLI 用 ora spinner 显示 <code>Verifying port host:port (attempt X/5)</code></li></ul><p><strong>唯一调用点</strong>:<code>start.ts</code> 和 <code>reload.ts</code> 的最后一步端口探测。</p><h2 id="version-ts-—-版本信息" tabindex="-1"><code>version.ts</code> — 版本信息 <a class="header-anchor" href="#version-ts-—-版本信息" aria-label="Permalink to &quot;\`version.ts\` — 版本信息&quot;">​</a></h2><p><code>apps/proxy-core/src/utils/version.ts</code>。三个导出:</p><h3 id="getprojectversion" tabindex="-1"><code>getProjectVersion()</code> <a class="header-anchor" href="#getprojectversion" aria-label="Permalink to &quot;\`getProjectVersion()\`&quot;">​</a></h3><p>从<strong>本包自身</strong>的 <code>package.json</code> 读取 <code>version</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> pkgPath</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> path.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">join</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getCallerDirname</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;../..&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">), </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;package.json&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span></code></pre></div><p><code>../..</code> 相对 <code>utils/</code>,即 <code>apps/proxy-core/</code>。用 <code>getCallerDirname</code> 避免依赖 cwd。</p><h3 id="getclaudeversion" tabindex="-1"><code>getClaudeVersion()</code> <a class="header-anchor" href="#getclaudeversion" aria-label="Permalink to &quot;\`getClaudeVersion()\`&quot;">​</a></h3><p>三级 fallback 找 Claude Code CLI 版本:</p><ol><li><code>execSync(&#39;claude --version&#39;)</code>(最可靠,跨平台,超时 5s)</li><li><code>execSync(&#39;npm root -g&#39;)</code> 拿到全局 root → <code>&lt;root&gt;/@anthropic-ai/claude-code/package.json</code></li><li>硬编码常见路径遍历(macOS npm、Windows npm、pnpm 全局)——<code>*</code> 通配处 <code>readdirSync</code> 展开</li></ol><p>任何步骤失败进下一步。全部失败返回 <code>&#39;not installed&#39;</code>。</p><p><strong>PM2 环境的坑</strong>:PM2 fork 子进程继承 <code>PATH</code> 需要 shell 环境已导出,如果 PM2 daemon 是别的 shell 启动的,<code>claude</code> 命令可能找不到。注释里提到 <code>如果版本信息不正确,执行 pm2 kill 后重启</code>。</p><h3 id="getversioninfo" tabindex="-1"><code>getVersionInfo()</code> <a class="header-anchor" href="#getversioninfo" aria-label="Permalink to &quot;\`getVersionInfo()\`&quot;">​</a></h3><p>合并返回 <code>{ projectVersion, claudeVersion }</code>,被 <code>/ui/api/config</code> 端点使用(<code>ui-route.ts:63</code>)。</p><h2 id="sse-accumulator-ts-—-transform-流形式的-sse-解析" tabindex="-1"><code>sse-accumulator.ts</code> — Transform 流形式的 SSE 解析 <a class="header-anchor" href="#sse-accumulator-ts-—-transform-流形式的-sse-解析" aria-label="Permalink to &quot;\`sse-accumulator.ts\` — Transform 流形式的 SSE 解析&quot;">​</a></h2><p><code>apps/proxy-core/src/utils/sse-accumulator.ts</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> class</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SSEAccumulator</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> extends</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Transform</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
27
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> events</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> unknown</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> []</span></span>
28
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> private</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> leftover</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;&#39;</span></span>
29
+ <span class="line"></span>
30
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> _transform</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">chunk</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">enc</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">cb</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
31
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> text</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> this</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.leftover </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> chunk.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">toString</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;utf-8&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
32
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> lines</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> text.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">split</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">\\n</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
33
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> this</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.leftover </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> lines.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pop</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;&#39;</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 保留末尾不完整行</span></span>
34
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> for</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> line</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> of</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> lines) {</span></span>
35
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (line.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">startsWith</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;data: &#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)) {</span></span>
36
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">this</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.events.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">push</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">JSON</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">parse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(line.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">slice</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">6</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">))) }</span></span>
37
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">this</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.events.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">push</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ raw: line.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">slice</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">6</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) }) }</span></span>
38
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
39
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
40
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> this</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">push</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(chunk) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 转发原样 chunk</span></span>
41
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> cb</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
42
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
43
+ <span class="line"></span>
44
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> _flush</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">cb</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) { </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">/* 处理 leftover */</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
45
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p><strong>特点</strong>:</p><ul><li>处理 chunk 边界:不完整的最后一行留到下个 chunk</li><li><code>push(chunk)</code> 保证下游 pipe 拿到原始字节(相当于 SSE tap)</li><li><code>data: </code> 后有空格(vs <code>sse-writer</code> 的 <code>data:</code> 无空格)——反映标准 SSE 与 Anthropic 变体的差异</li></ul><p><strong>目前未被使用</strong>:<code>proxy.ts</code> 的常规 SSE pipe 分支(<code>proxy.ts:404-457</code>)直接手写 <code>on(&#39;data&#39;)</code> 解析,<code>SSEAccumulator</code> 是<strong>预留组件</strong>,等未来重构或需要更严谨解析时启用。</p><h2 id="server-auth-ts-—-bearer-token-校验" tabindex="-1"><code>server/auth.ts</code> — Bearer Token 校验 <a class="header-anchor" href="#server-auth-ts-—-bearer-token-校验" aria-label="Permalink to &quot;\`server/auth.ts\` — Bearer Token 校验&quot;">​</a></h2><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> AUTH_TOKEN_ENV</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;UI_AUTH_TOKEN&#39;</span></span>
46
+ <span class="line"></span>
47
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> checkAuth</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">request</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">config</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> boolean</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
48
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> token</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> config?.auth?.token </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> process.env[</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">AUTH_TOKEN_ENV</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">]</span></span>
49
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">token) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> true</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 未配置 → 完全放行(开发模式)</span></span>
50
+ <span class="line"></span>
51
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> authHeader</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.headers?.authorization</span></span>
52
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">authHeader) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</span></span>
53
+ <span class="line"></span>
54
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> provided</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> authHeader.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">startsWith</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;Bearer &#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
55
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> authHeader.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">slice</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">7</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
56
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> authHeader</span></span>
57
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> provided </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> token</span></span>
58
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li><strong>触发点</strong>:<code>POST /ui/api/config</code>、<code>POST /ui/api/control</code>、<code>POST /ui/api/providers</code> 三个写接口</li><li><strong>优先级</strong>:<code>config.auth.token</code> &gt; 环境变量 <code>UI_AUTH_TOKEN</code></li><li><strong>两种头格式</strong>:接受 <code>Bearer &lt;token&gt;</code> 和裸 <code>&lt;token&gt;</code></li><li><strong>恒等对比</strong>:<code>===</code> 字符串对比(非常量时间——如果需要防时序攻击应换成 <code>crypto.timingSafeEqual</code>)</li></ul><h2 id="middleware-request-id-ts" tabindex="-1"><code>middleware/request-id.ts</code> <a class="header-anchor" href="#middleware-request-id-ts" aria-label="Permalink to &quot;\`middleware/request-id.ts\`&quot;">​</a></h2><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> requestIdMiddleware</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">fastify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
59
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fastify.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">addHook</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;onRequest&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">request</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
60
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> headerId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.headers[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-request-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> undefined</span></span>
61
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> headerId </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> nanoid</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">12</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
62
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
63
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>Fastify plugin。在 <code>server/index.ts:23</code> 最先注册。</p><ul><li><strong>客户端可指定</strong>:若请求头带 <code>x-request-id</code>,用它作为 <code>request.id</code>,方便跨系统链路追踪</li><li><strong>否则生成 12 位 nanoid</strong>:短、URL-safe、碰撞概率对本项目量级足够</li><li><strong><code>request.id</code> 覆盖 Fastify 默认</strong>:Fastify 默认自己生成一个 request-id,本 hook 提前覆盖它</li></ul><p>日志里的 <code>reqId</code> 字段就来自这个 <code>request.id</code>。</p><h2 id="类型定义-types" tabindex="-1">类型定义(<code>types/</code>) <a class="header-anchor" href="#类型定义-types" aria-label="Permalink to &quot;类型定义(\`types/\`)&quot;">​</a></h2><ul><li><code>types/api.ts</code>:REST 响应类型(例如 <code>{ success, error, errors[] }</code>),供 route handler 引用</li><li><code>types/config.ts</code>:Zod schema 的等价 TS 接口(冗余定义,历史遗留)</li><li><code>types/log.ts</code>:Pino level 相关类型</li><li><code>types/pm2.ts</code>:<code>Pm2ProcessStatus</code> 简化壳(<code>{ name, status, cpu, memory, uptime, restarts }</code>),<code>getProcessStatus</code> 的返回类型</li><li><code>types/index.ts</code>:barrel 转发</li></ul><p>其中 <code>types/config.ts</code> 与 <code>config/schema.ts</code> 定义重叠。<strong>主类型</strong>是 Zod 推导的 <code>AppConfig</code>(<code>schema.ts:31</code>);<code>types/config.ts</code> 的接口用于 pino 传入等非 Zod 依赖场景。</p><h2 id="相关文档" tabindex="-1">相关文档 <a class="header-anchor" href="#相关文档" aria-label="Permalink to &quot;相关文档&quot;">​</a></h2><ul><li>启动链 → <a href="./entry.html">entry.md</a></li><li>PM2 集成 → <a href="./pm2.html">pm2.md</a></li><li>Zod schema → <a href="./config.html">config.md</a></li></ul>`,50)])])}const g=i(h,[["render",e]]);export{E as __pageData,g as default};
@@ -0,0 +1 @@
1
+ import{_ as i,o as a,c as n,a2 as t}from"./chunks/framework.D_Xv2a7c.js";const E=JSON.parse('{"title":"proxy-core / 公共工具","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-core/utilities.md","filePath":"proxy-core/utilities.md"}'),h={name:"proxy-core/utilities.md"};function e(k,s,l,p,r,d){return a(),n("div",null,[...s[0]||(s[0]=[t("",50)])])}const g=i(h,[["render",e]]);export{E as __pageData,g as default};
@@ -0,0 +1,38 @@
1
+ import{_ as i,o as a,c as t,a2 as e}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"01. 快速上手","description":"","frontmatter":{},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),n={name:"quickstart.md"};function p(d,s,l,o,h,r){return a(),t("div",null,[...s[0]||(s[0]=[e(`<h1 id="_01-快速上手" tabindex="-1">01. 快速上手 <a class="header-anchor" href="#_01-快速上手" aria-label="Permalink to &quot;01. 快速上手&quot;">​</a></h1><h2 id="本文档覆盖的源文件" tabindex="-1">本文档覆盖的源文件 <a class="header-anchor" href="#本文档覆盖的源文件" aria-label="Permalink to &quot;本文档覆盖的源文件&quot;">​</a></h2><ul><li><code>package.json</code>(根 scripts)</li><li><code>apps/proxy-core/package.json</code></li><li><code>apps/proxy-core/src/cli/index.ts:15-80</code></li><li><code>apps/proxy-core/src/utils/paths.ts</code></li><li><code>apps/proxy-core/ecosystem.config.cjs</code></li><li><code>apps/proxy-cli/vite.config.ts</code></li><li><code>apps/proxy-admin/vite.config.ts</code></li><li><code>apps/proxy-admin/src/vite-env.d.ts</code></li></ul><h2 id="环境要求" tabindex="-1">环境要求 <a class="header-anchor" href="#环境要求" aria-label="Permalink to &quot;环境要求&quot;">​</a></h2><ul><li><strong>Node.js</strong> ≥ 18</li><li><strong>pnpm</strong> ≥ 8</li><li>macOS / Linux / Windows(PM2 fork 模式跨平台)</li></ul><h2 id="首次安装" tabindex="-1">首次安装 <a class="header-anchor" href="#首次安装" aria-label="Permalink to &quot;首次安装&quot;">​</a></h2><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> install</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 安装 monorepo 全部依赖</span></span>
2
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 构建三个应用</span></span>
3
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> start</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # PM2 守护启动代理服务器</span></span></code></pre></div><p>启动脚本对应 <code>apps/proxy-core/dist/cli/index.js start</code>。首次运行会自动在数据目录写入默认 <code>config.json</code>(见下节)。</p><h2 id="数据目录约定" tabindex="-1">数据目录约定 <a class="header-anchor" href="#数据目录约定" aria-label="Permalink to &quot;数据目录约定&quot;">​</a></h2><p>所有运行时数据统一在 <code>~/.cc-monitoring/</code>(<code>apps/proxy-core/src/utils/paths.ts:7</code>):</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>~/.cc-monitoring/</span></span>
4
+ <span class="line"><span>├── config.json # 运行时配置(缺省则用默认值写入)</span></span>
5
+ <span class="line"><span>└── logs/</span></span>
6
+ <span class="line"><span> ├── proxy.log # Pino 主日志</span></span>
7
+ <span class="line"><span> ├── proxy-YYYY-MM-DD.log # 按日轮转</span></span>
8
+ <span class="line"><span> ├── error.log # PM2 错误日志</span></span>
9
+ <span class="line"><span> ├── out.log # PM2 输出日志</span></span>
10
+ <span class="line"><span> └── proxy.db # SQLite 数据文件</span></span></code></pre></div><p>优先级(<code>getConfigPath()</code> in <code>paths.ts:18-20</code>):</p><ol><li><code>--config &lt;path&gt;</code> CLI 参数(<code>src/cli/index.ts:19-25</code> 通过 <code>preAction</code> 钩子写入 override)</li><li><code>CONFIG_PATH</code> 环境变量</li><li><code>~/.cc-monitoring/config.json</code> 默认</li></ol><h2 id="端口约定" tabindex="-1">端口约定 <a class="header-anchor" href="#端口约定" aria-label="Permalink to &quot;端口约定&quot;">​</a></h2><table tabindex="0"><thead><tr><th>服务</th><th>默认端口</th><th>来源</th></tr></thead><tbody><tr><td>proxy-core(生产)</td><td>9527</td><td><code>~/.cc-monitoring/config.json</code> 的 <code>server.port</code></td></tr><tr><td>proxy-cli(开发)</td><td>Vite 默认</td><td><code>apps/proxy-cli/vite.config.ts</code>,<code>/ui/api</code> 反代到 <code>http://localhost:3000</code></td></tr><tr><td>proxy-admin(开发)</td><td>3000</td><td><code>apps/proxy-admin/vite.config.ts:21</code></td></tr></tbody></table><p>⚠️ proxy-admin 开发端口 3000 与 proxy-cli 早期反代目标一致;同时开发时需修改二者之一避免冲突。</p><h2 id="根级便捷命令" tabindex="-1">根级便捷命令 <a class="header-anchor" href="#根级便捷命令" aria-label="Permalink to &quot;根级便捷命令&quot;">​</a></h2><p><code>package.json</code> 提供的 script 会转发到 proxy-core CLI:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> start</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 启动 (PM2)</span></span>
11
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> stop</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 停止</span></span>
12
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> status</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 状态</span></span>
13
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> reload</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 优雅重启</span></span>
14
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> logs</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [N] </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 查看最近 N 行日志</span></span>
15
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> config</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 显示当前配置</span></span>
16
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test-connection</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 探测上游连通性</span></span>
17
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ui</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 浏览器打开 http://localhost:9527/ui</span></span>
18
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> cli</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --help</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 全部 CLI 命令</span></span></code></pre></div><p>分应用命令:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-core</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # tsx 热重载运行 Fastify</span></span>
19
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-cli</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # Vite HMR 运行 proxy-cli</span></span>
20
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-admin</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # Vite HMR 运行 proxy-admin</span></span>
21
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 只启 proxy-core dev(根 script 别名)</span></span>
22
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 全量构建(pnpm -r build)</span></span>
23
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build:proxy-core</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 单独构建 proxy-core</span></span>
24
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build:proxy-cli</span></span>
25
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> build:proxy-admin</span></span>
26
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 全量测试(pnpm -r test)</span></span></code></pre></div><h2 id="cli-命令速查" tabindex="-1">CLI 命令速查 <a class="header-anchor" href="#cli-命令速查" aria-label="Permalink to &quot;CLI 命令速查&quot;">​</a></h2><p>(详见 <a href="./proxy-core/cli.html">cli.md</a>)</p><table tabindex="0"><thead><tr><th>命令</th><th>作用</th><th>常用参数</th></tr></thead><tbody><tr><td><code>start</code></td><td>PM2 守护启动</td><td><code>-p, --port &lt;port&gt;</code> 覆盖配置端口</td></tr><tr><td><code>stop</code></td><td>停止进程</td><td>—</td></tr><tr><td><code>status</code></td><td>状态(CPU/内存/uptime/重启次数)</td><td>—</td></tr><tr><td><code>reload</code></td><td>优雅重启,探测 online + 端口</td><td>—</td></tr><tr><td><code>logs [n]</code></td><td>打印最近 n 行日志</td><td><code>-l level</code>、<code>-g pattern</code></td></tr><tr><td><code>config</code></td><td>show / set / reset</td><td><code>config set proxy.target &lt;url&gt;</code></td></tr><tr><td><code>test</code></td><td>HEAD 探测上游</td><td>—</td></tr><tr><td><code>ui</code></td><td>打开面板</td><td><code>--build</code> 强制重建 UI</td></tr><tr><td><code>clean-requests</code></td><td>清理旧请求记录</td><td><code>--days 7</code></td></tr></tbody></table><p>全局参数:<code>-c, --config &lt;path&gt;</code> 覆盖配置文件路径。</p><h2 id="配置文件" tabindex="-1">配置文件 <a class="header-anchor" href="#配置文件" aria-label="Permalink to &quot;配置文件&quot;">​</a></h2><p>启动时 Zod 校验(<code>apps/proxy-core/src/config/schema.ts</code>),字段结构:</p><div class="language-json vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
27
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;server&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;port&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">9527</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;host&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;0.0.0.0&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
28
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;proxy&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;target&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;https://ark.cn-beijing.volces.com/api/coding&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;changeOrigin&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;apiKey&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;sk-...&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
29
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;logging&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;level&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;info&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;file&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;logs/proxy.log&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;maxSize&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;10m&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;interval&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;1d&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;compress&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
30
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;storage&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;type&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;sqlite&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;path&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;logs/proxy.db&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;maxDays&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">7</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
31
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;auth&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;token&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;...&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
32
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><blockquote><p><code>logging.file</code> 和 <code>storage.path</code> 中 <code>logs/</code> 是<strong>相对于 config 所在目录</strong>的路径,实际存储在 <code>~/.cc-monitoring/logs/</code> 下,项目根目录不含这些文件。</p></blockquote><ul><li><code>logging.file</code> 和 <code>storage.path</code> 是相对路径时,以 config 所在目录为基准解析(<code>config/index.ts:23-30</code>)</li><li><code>storage.maxDays = 0</code> 表示保留全部历史(<code>request-writer.ts:189-193</code>)</li><li><code>auth.token</code> 未设置时,<code>/ui/api/config</code>、<code>/ui/api/control</code>、<code>/ui/api/providers</code> 的写接口不做校验(<code>server/auth.ts:5</code>)</li></ul><h2 id="环境变量" tabindex="-1">环境变量 <a class="header-anchor" href="#环境变量" aria-label="Permalink to &quot;环境变量&quot;">​</a></h2><p><strong>proxy-core</strong></p><table tabindex="0"><thead><tr><th>变量</th><th>作用</th></tr></thead><tbody><tr><td><code>CONFIG_PATH</code></td><td>覆盖 config 路径(低于 <code>--config</code>)</td></tr><tr><td><code>CC_DATA_DIR</code></td><td>覆盖数据目录(ecosystem.config.cjs 使用)</td></tr><tr><td><code>UI_AUTH_TOKEN</code></td><td>覆盖 <code>auth.token</code>,<code>config.auth.token</code> 未配置时兜底</td></tr><tr><td><code>NODE_ENV</code></td><td>PM2 环境切换(development / production)</td></tr></tbody></table><p><strong>proxy-cli</strong></p><p>由 <code>apps/proxy-cli/vite.config.ts:11-19</code> 的 dev 代理决定:<code>/ui/api</code> 转发到 <code>http://localhost:3000</code>(含 WebSocket 升级)。</p><p><strong>proxy-admin</strong>(<code>.env</code> / <code>.env.local</code>)</p><table tabindex="0"><thead><tr><th>变量</th><th>默认</th><th>作用</th></tr></thead><tbody><tr><td><code>VITE_API_PREFIX</code></td><td><code>/api</code></td><td>axios baseURL</td></tr><tr><td><code>VITE_API_PROXY_TARGET</code></td><td><code>http://localhost:8080</code></td><td>Vite 开发代理目标</td></tr></tbody></table><p>类型声明位于 <code>apps/proxy-admin/src/vite-env.d.ts:3-8</code>。</p><h2 id="连接-claude-code" tabindex="-1">连接 Claude Code <a class="header-anchor" href="#连接-claude-code" aria-label="Permalink to &quot;连接 Claude Code&quot;">​</a></h2><p>启动后,把 Claude Code / Claude Agent SDK 的 API endpoint 指向本地代理:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ANTHROPIC_BASE_URL</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">http://localhost:9527</span></span>
33
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 或</span></span>
34
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ANTHROPIC_API_URL</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">http://localhost:9527</span></span>
35
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">claude</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ...</span></span></code></pre></div><p>之后所有 <code>/v1/*</code> 请求都会经过 proxy-core 转发到 <code>proxy.target</code> 配置的上游,同时被记录到 SQLite。</p><h2 id="开发工作流" tabindex="-1">开发工作流 <a class="header-anchor" href="#开发工作流" aria-label="Permalink to &quot;开发工作流&quot;">​</a></h2><p><strong>只改 proxy-core</strong>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-core</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # tsx 直接跑 src/server/index.ts</span></span></code></pre></div><p>自动重载。此模式<strong>不走 PM2</strong>,直接用 Fastify 的 <code>startServer()</code>(<code>server/index.ts:30-40</code>)。</p><p><strong>改 proxy-cli 组件</strong>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 终端 1</span></span>
36
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-core</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 后端 9527</span></span>
37
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># 终端 2</span></span>
38
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-cli</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # 前端 Vite HMR,通过 vite.config.ts 反代到 localhost:3000/ui/api(注意:vite 硬编码 3000,与 core 默认 9527 不一致,dev 时需将 core 端口改成 3000 或改 vite 配置)</span></span></code></pre></div><p>注意:<code>useWebSocketData</code> 和 <code>useLogs</code> 在 <code>import.meta.env.DEV</code> 下直连 <code>ws://localhost:3000</code>(<code>apps/proxy-cli/src/hooks/useWebSocketData.ts:88</code>)——目前是硬编码 3000。生产模式则用 <code>location.host</code>。</p><p><strong>改 proxy-admin</strong>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">pnpm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev:proxy-admin</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # Vite + vite-plugin-mock(假数据来自 src/mock/*)</span></span></code></pre></div><h2 id="生产部署" tabindex="-1">生产部署 <a class="header-anchor" href="#生产部署" aria-label="Permalink to &quot;生产部署&quot;">​</a></h2><ul><li>直接在服务器上 <code>pnpm install &amp;&amp; pnpm build &amp;&amp; pnpm start</code></li><li>PM2 通过 <code>apps/proxy-core/ecosystem.config.cjs</code> 守护,参数:<code>max_memory_restart: 200M</code>、<code>exec_mode: fork</code>(因 ESM 只能 fork)</li><li>数据与配置默认写 <code>$HOME/.cc-monitoring/</code>,可通过 <code>CC_DATA_DIR</code> 覆盖</li><li>通过 <code>/ui/api/control</code>(Bearer 认证)可远程 start/stop/restart 进程;也可 <code>pnpm stop / reload</code></li></ul><h2 id="常见故障" tabindex="-1">常见故障 <a class="header-anchor" href="#常见故障" aria-label="Permalink to &quot;常见故障&quot;">​</a></h2><table tabindex="0"><thead><tr><th>现象</th><th>定位</th></tr></thead><tbody><tr><td><code>start</code> 卡在 <code>Verifying port</code></td><td>上游 target 不可达,看 <code>~/.cc-monitoring/logs/error.log</code></td></tr><tr><td>面板显示 disconnected 红条</td><td><code>ConnectionBanner</code> 检测 WebSocket 断开;服务未启动或端口不通</td></tr><tr><td><code>POST /ui/api/config</code> 返回 401</td><td>配置了 <code>auth.token</code> 但请求头缺 <code>Authorization: Bearer &lt;token&gt;</code></td></tr><tr><td><code>POST /ui/api/providers</code> 报重名/duplicate name</td><td>validateProviders 检测到重复 <code>name</code>(<code>providers-db.ts:140-148</code>)</td></tr><tr><td>版本信息 <code>claudeVersion: not installed</code></td><td>未装 Claude Code CLI,或 PM2 环境 <code>PATH</code> 丢失(<code>utils/version.ts</code>)</td></tr></tbody></table>`,55)])])}const g=i(n,[["render",p]]);export{c as __pageData,g as default};
@@ -0,0 +1 @@
1
+ import{_ as i,o as a,c as t,a2 as e}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"01. 快速上手","description":"","frontmatter":{},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),n={name:"quickstart.md"};function p(d,s,l,o,h,r){return a(),t("div",null,[...s[0]||(s[0]=[e("",55)])])}const g=i(n,[["render",p]]);export{c as __pageData,g as default};
@@ -0,0 +1,146 @@
1
+ import{_ as a,o as i,c as e,a2 as n}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"02. 端到端请求流转","description":"","frontmatter":{},"headers":[],"relativePath":"request-flow.md","filePath":"request-flow.md"}'),t={name:"request-flow.md"};function l(p,s,d,o,h,E){return i(),e("div",null,[...s[0]||(s[0]=[n(`<h1 id="_02-端到端请求流转" tabindex="-1">02. 端到端请求流转 <a class="header-anchor" href="#_02-端到端请求流转" aria-label="Permalink to &quot;02. 端到端请求流转&quot;">​</a></h1><h2 id="本文档覆盖的源文件" tabindex="-1">本文档覆盖的源文件 <a class="header-anchor" href="#本文档覆盖的源文件" aria-label="Permalink to &quot;本文档覆盖的源文件&quot;">​</a></h2><ul><li><code>apps/proxy-core/src/server/index.ts</code></li><li><code>apps/proxy-core/src/server/proxy.ts</code></li><li><code>apps/proxy-core/src/server/chat-route.ts</code></li><li><code>apps/proxy-core/src/server/middleware/request-id.ts</code></li><li><code>apps/proxy-core/src/server/data-push.ts</code></li><li><code>apps/proxy-core/src/utils/request-writer.ts</code></li><li><code>apps/proxy-core/src/utils/sse-writer.ts</code></li><li><code>apps/proxy-core/src/utils/tool-injector.ts</code></li><li><code>apps/proxy-core/src/utils/inject-loop.ts</code></li><li><code>apps/proxy-core/src/utils/sse-stream-processor.ts</code></li><li><code>apps/proxy-core/src/utils/machine-id.ts</code></li><li><code>apps/proxy-cli/src/hooks/useWebSocketData.ts</code></li></ul><p>本文用一次业务请求串起整个系统,具体到各分支的实现请转到对应深入文档。</p><h2 id="一次业务请求经过什么" tabindex="-1">一次业务请求经过什么 <a class="header-anchor" href="#一次业务请求经过什么" aria-label="Permalink to &quot;一次业务请求经过什么&quot;">​</a></h2><p>系统有两条业务路径:<code>/v1/*</code>(纯代理)和 <code>/api/chat</code>(MCP 增强)。下面用 mermaid 展示 <code>/api/chat</code> 的完整流程(<code>/v1/*</code> 更简单,见 <a href="./proxy-core/proxy.html">proxy.md</a>)。</p><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">sequenceDiagram</span></span>
2
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> autonumber</span></span>
3
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> actor CC as Claude Code</span></span>
4
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant F as Fastify (proxy-core)</span></span>
5
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant M as request-id middleware</span></span>
6
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant CH as setupChatRoute handler</span></span>
7
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant R as resolveProxyTarget</span></span>
8
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant GM as getProxyModel</span></span>
9
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant TI as injectMcpTools</span></span>
10
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant DB as SQLite</span></span>
11
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant SP as SSEStreamProcessor</span></span>
12
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant IL as runStreamingInjectLoop</span></span>
13
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant UP as 上游 API</span></span>
14
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant PUSH as pushNewRequest (data-push)</span></span>
15
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant WS as WebSocket clients</span></span>
16
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant UI as proxy-cli 面板</span></span>
17
+ <span class="line"></span>
18
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CC-&gt;&gt;F: POST /api/chat&lt;br/&gt;headers + JSON body</span></span>
19
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> F-&gt;&gt;M: onRequest hook</span></span>
20
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> M--&gt;&gt;F: request.id = x-request-id | nanoid(12)</span></span>
21
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> F-&gt;&gt;CH: 匹配 /api/chat</span></span>
22
+ <span class="line"></span>
23
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CH: 生成/复用 sessionId&lt;br/&gt;x-chat-session-id header</span></span>
24
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> alt session resume(providedSessionId 存在)</span></span>
25
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;DB: loadSessionHistory(providedSessionId)</span></span>
26
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> DB--&gt;&gt;CH: history.messages + history.system</span></span>
27
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CH: prepend 历史 messages 到 body</span></span>
28
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
29
+ <span class="line"></span>
30
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;R: 解析 provider(SQLite is_default=1)</span></span>
31
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> R--&gt;&gt;CH: {baseUrl, targetPath, apiKey?, model?, haiku_model?, sonnet_model?, opus_model?}</span></span>
32
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;GM: getProxyModel(originalModel, tierModels)</span></span>
33
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> GM--&gt;&gt;CH: proxyModel 或 undefined</span></span>
34
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CH: body.model = proxyModel(如有)</span></span>
35
+ <span class="line"></span>
36
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;TI: injectMcpTools(body)(仅 MCP tools,不含 probe/curl)</span></span>
37
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> TI--&gt;&gt;CH: injectedNames[]</span></span>
38
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CH: filterForwardHeaders + 注入 x-chat-session-id</span></span>
39
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;DB: cleanOldRequestsDB(maxDays)</span></span>
40
+ <span class="line"></span>
41
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> alt shouldMock(body) — PoC</span></span>
42
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH--&gt;&gt;CC: reply.hijack() + writeTextAsSSE 合成 SSE</span></span>
43
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> else 正常转发</span></span>
44
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;UP: fetch(baseUrl + targetPath + /v1/messages)</span></span>
45
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> UP--&gt;&gt;CH: response(JSON 或 SSE)</span></span>
46
+ <span class="line"></span>
47
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> alt JSON 响应 + injected + tool_use</span></span>
48
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;IL: runJsonInjectLoop(JSON body 内部循环)</span></span>
49
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> IL--&gt;&gt;CH: {finalBody, iterations}</span></span>
50
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;DB: saveRequestDB(原始 + 每次迭代独立记录)</span></span>
51
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH--&gt;&gt;CC: reply.code(200) + x-chat-session-id header</span></span>
52
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> else JSON 响应(常规)</span></span>
53
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;DB: saveRequestDB</span></span>
54
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH--&gt;&gt;CC: reply.code(status) + _sessionId + x-chat-session-id header</span></span>
55
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> else SSE 响应(核心路径)</span></span>
56
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CH: reply.hijack + writeHead + x-chat-session-id</span></span>
57
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;SP: SSEStreamProcessor(reply.raw)</span></span>
58
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> UP--&gt;&gt;SP: SSE stream</span></span>
59
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SP--&gt;&gt;CC: processChunk → 实时转发原始 SSE</span></span>
60
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SP-&gt;&gt;SP: 增量解析 → events[] + contentBlocks + stopReason</span></span>
61
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SP-&gt;&gt;DB: stream end → saveRequestDB(第 1 条记录)</span></span>
62
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SP-&gt;&gt;PUSH: pushNewRequest</span></span>
63
+ <span class="line"></span>
64
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> alt hasInjectedToolUse()</span></span>
65
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CC: writeSSEEvent(proxy_status)</span></span>
66
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;IL: runStreamingInjectLoop(流式续接到同一 reply.raw)</span></span>
67
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> loop 每次迭代(max 3)</span></span>
68
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> IL-&gt;&gt;UP: callUpstream(body)</span></span>
69
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> UP--&gt;&gt;CC: streamAndParse → 流式转发 loop SSE</span></span>
70
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> IL-&gt;&gt;DB: saveIterationDB(独立记录)</span></span>
71
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
72
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
73
+ <span class="line"></span>
74
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CH-&gt;&gt;CH: reply.raw.end()</span></span>
75
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
76
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
77
+ <span class="line"></span>
78
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PUSH--&gt;&gt;WS: broadcast type=request action=new</span></span>
79
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> WS--&gt;&gt;UI: 前端 useWebSocketData 收到消息</span></span>
80
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> UI-&gt;&gt;UI: 去重 + 排序 + 截取前 1000</span></span>
81
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> UI-)F: 触发一次 fetchTodayStats(今日实时刷新)</span></span></code></pre></div><h2 id="关键契约" tabindex="-1">关键契约 <a class="header-anchor" href="#关键契约" aria-label="Permalink to &quot;关键契约&quot;">​</a></h2><h3 id="请求-id" tabindex="-1">请求 ID <a class="header-anchor" href="#请求-id" aria-label="Permalink to &quot;请求 ID&quot;">​</a></h3><ul><li>Fastify <code>onRequest</code> 钩子(<code>middleware/request-id.ts:5-12</code>)优先取 <code>x-request-id</code> 头;缺则 <code>nanoid(12)</code></li><li>上游返回后从响应头 <code>x-request-id</code> 取云端 ID,覆盖 <code>requestData.requestId</code></li><li>前端用「<code>sessionId:requestId</code>」的 <code>compositeId</code> 唯一标识一条请求(<code>request-writer.ts:168</code>)</li></ul><h3 id="会话-id" tabindex="-1">会话 ID <a class="header-anchor" href="#会话-id" aria-label="Permalink to &quot;会话 ID&quot;">​</a></h3><ul><li><code>/v1/*</code>:来自客户端头 <code>x-claude-code-session-id</code>,无值时记 <code>&#39;unknown-session&#39;</code></li><li><code>/api/chat</code>:来自客户端头 <code>x-chat-session-id</code>,无值时 server 生成 UUID。生成的 sessionId 注入到 <code>forwardHeaders</code>(上游始终能看到),并通过 response header <code>x-chat-session-id</code> 返回给客户端</li></ul><h3 id="session-resume" tabindex="-1">Session Resume <a class="header-anchor" href="#session-resume" aria-label="Permalink to &quot;Session Resume&quot;">​</a></h3><p><code>/api/chat</code> 独有能力。当客户端带 <code>x-chat-session-id</code> 且 DB 中有历史记录:</p><ul><li><code>loadSessionHistory(sessionId)</code> 从 SQLite 加载该 session 的历史 messages + system prompt</li><li>历史 messages prepend 到当前请求的 messages 前面</li><li>system prompt 仅在当前请求未提供时 carry over</li></ul><h3 id="api-key-双记录" tabindex="-1">API Key 双记录 <a class="header-anchor" href="#api-key-双记录" aria-label="Permalink to &quot;API Key 双记录&quot;">​</a></h3><ul><li><code>apiKey</code>:客户端原始 Bearer / <code>x-api-key</code></li><li><code>proxyApiKey</code>:实际转发给上游的 key(若 <code>resolved.apiKey</code> 存在则用它,否则透传客户端)</li></ul><p>两者都写入 <code>requests</code> 表,便于审计。</p><h3 id="model-覆盖-tier-rewrite" tabindex="-1">Model 覆盖(Tier Rewrite) <a class="header-anchor" href="#model-覆盖-tier-rewrite" aria-label="Permalink to &quot;Model 覆盖(Tier Rewrite)&quot;">​</a></h3><ul><li><code>getProxyModel(originalModel, resolved)</code> 按 tier 映射替换: <ul><li><code>claude-haiku*</code> → <code>haiku_model</code>(fallback: <code>model</code>)</li><li><code>claude-sonnet*</code> → <code>sonnet_model</code>(fallback: <code>model</code>)</li><li><code>claude-opus*</code> → <code>opus_model</code>(fallback: <code>model</code>)</li><li>其它 → <code>model</code></li><li>所有为空 → 不替换</li></ul></li><li><code>/v1/*</code> 和 <code>/api/chat</code> 都使用 <code>getProxyModel</code></li></ul><h3 id="machineid" tabindex="-1">machineId <a class="header-anchor" href="#machineid" aria-label="Permalink to &quot;machineId&quot;">​</a></h3><ul><li><code>getMachineIdSync()</code> 返回基于 hostname 的稳定标识(<code>machine-id.ts</code>)</li><li>写入 <code>requestData.machineId</code> 和 <code>requests</code> 表 <code>machine_id</code> 列</li><li>用于区分多台机器的请求记录</li></ul><h3 id="header-过滤" tabindex="-1">Header 过滤 <a class="header-anchor" href="#header-过滤" aria-label="Permalink to &quot;Header 过滤&quot;">​</a></h3><p><code>filterForwardHeaders</code>(<code>proxy.ts:131-161</code>):</p><ul><li>删掉 <code>host</code>(上游会 404)</li><li>删掉 <code>content-length</code>(body 已重新序列化,长度变了)</li><li>删掉 <code>x-req-key</code></li><li>若 provider 有 <code>api_key</code>,覆盖 <code>x-api-key</code> 与 <code>authorization: Bearer &lt;k&gt;</code></li><li><code>/api/chat</code> 还注入 <code>x-chat-session-id</code> 到 forwardHeaders</li></ul><p>##两条路径的响应分支</p><h3 id="v1-三分支-纯代理" tabindex="-1"><code>/v1/*</code> 三分支(纯代理) <a class="header-anchor" href="#v1-三分支-纯代理" aria-label="Permalink to &quot;\`/v1/*\` 三分支(纯代理)&quot;">​</a></h3><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart TD</span></span>
82
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> START([POST /v1/*]) --&gt; RESOLVE[resolveProxyTarget + getProxyModel]</span></span>
83
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESOLVE --&gt; HEADER[extractSafeHeaders → filterForwardHeaders]</span></span>
84
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HEADER --&gt; FETCH[fetch 上游]</span></span>
85
+ <span class="line"></span>
86
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> FETCH --&gt; CT{&quot;content-type&quot;}</span></span>
87
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CT -- application/json --&gt; JSON[response.text&lt;br/&gt;save + reply.code.send]</span></span>
88
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CT -- text/event-stream --&gt; PIPE[&quot;reply.hijack + Readable.fromWeb.pipe(reply.raw)&lt;br/&gt;边转发边解析 data: 行&quot;]</span></span>
89
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> FETCH --&gt; CATCH[catch → error]</span></span>
90
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CATCH --&gt; ERR[pushNewRequest(error) → reply.code.send]</span></span>
91
+ <span class="line"></span>
92
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> JSON --&gt; END([返回])</span></span>
93
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PIPE --&gt; END2[stream end → save + push → 返回]</span></span>
94
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ERR --&gt; END3([返回错误])</span></span></code></pre></div><h3 id="api-chat-分支-mcp-增强代理" tabindex="-1"><code>/api/chat</code> 分支(MCP 增强代理) <a class="header-anchor" href="#api-chat-分支-mcp-增强代理" aria-label="Permalink to &quot;\`/api/chat\` 分支(MCP 增强代理)&quot;">​</a></h3><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart TD</span></span>
95
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> START([POST /api/chat]) --&gt; VALID{body 有 model + messages?}</span></span>
96
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> VALID -- 否 --&gt; 400[400 invalid_request]</span></span>
97
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> VALID -- 是 --&gt; SESSION[生成/复用 sessionId]</span></span>
98
+ <span class="line"></span>
99
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SESSION --&gt; RESUME{x-chat-session-id 存在?}</span></span>
100
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESUME -- 是 --&gt; HISTORY[loadSessionHistory prepend]</span></span>
101
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESUME -- 否 --&gt; MODEL</span></span>
102
+ <span class="line"></span>
103
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HISTORY --&gt; MODEL[getProxyModel tier rewrite]</span></span>
104
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MODEL --&gt; INJECT[injectMcpTools MCP-only]</span></span>
105
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> INJECT --&gt; HEADER[filterForwardHeaders + x-chat-session-id]</span></span>
106
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HEADER --&gt; MOCK{shouldMock?}</span></span>
107
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOCK -- 是 --&gt; MOCK_RESP[writeTextAsSSE 合成返回]</span></span>
108
+ <span class="line"></span>
109
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOCK -- 否 --&gt; FETCH[fetch 上游 /v1/messages]</span></span>
110
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> FETCH --&gt; CT{&quot;content-type&quot;}</span></span>
111
+ <span class="line"></span>
112
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CT -- application/json --&gt; JSON_PATH[JSON 分支]</span></span>
113
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CT -- text/event-stream --&gt; SSE_PATH[SSE 分支]</span></span>
114
+ <span class="line"></span>
115
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SSE_PATH --&gt; PHASE1[Phase 1: SSEStreamProcessor&lt;br/&gt;边转发边增量解析]</span></span>
116
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PHASE1 --&gt; STREAM_END[stream end → save DB 第 1 条]</span></span>
117
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> STREAM_END --&gt; HIT{hasInjectedToolUse?}</span></span>
118
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HIT -- 否 --&gt; CLOSE[reply.raw.end]</span></span>
119
+ <span class="line"></span>
120
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HIT -- 是 --&gt; PROXY_STATUS[writeSSEEvent proxy_status]</span></span>
121
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PROXY_STATUS --&gt; LOOP[Phase 2: runStreamingInjectLoop]</span></span>
122
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP --&gt; LOOP_ITER{迭代: exec tool → fetch → stream forward → save DB}</span></span>
123
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP_ITER --&gt; NEXT{还有 tool_use?}</span></span>
124
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> NEXT -- 否 --&gt; CLOSE</span></span>
125
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> NEXT -- 是 --&gt; LOOP_ITER</span></span>
126
+ <span class="line"></span>
127
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOCK_RESP --&gt; END([返回])</span></span>
128
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> JSON_PATH --&gt; END2([返回 JSON + sessionId])</span></span>
129
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CLOSE --&gt; END3([返回 SSE])</span></span></code></pre></div><ul><li><code>/v1/*</code> 纯代理:JSON(<code>proxy.ts:324-362</code>)、SSE pipe(<code>proxy.ts:364-426</code>)、Error(<code>proxy.ts:428-456</code>)</li><li><code>/api/chat</code> 增强代理:详见 <a href="./proxy-core/chat-api.html">chat-api.md</a></li></ul><p>细节请转到 <a href="./proxy-core/proxy.html">proxy.md</a>。</p><h2 id="写库与推送" tabindex="-1">写库与推送 <a class="header-anchor" href="#写库与推送" aria-label="Permalink to &quot;写库与推送&quot;">​</a></h2><p>无论哪条分支,最后都会:</p><ol><li>计算 <code>responseTime = Date.now() - startTime</code>(SSE 用 <code>end</code> 事件时刻)</li><li><code>saveRequestDB(sessionId, cloudRequestId, requestData)</code>:<code>INSERT OR REPLACE INTO requests</code> 完整字段(含 headers/body/events/machine_id/base_url 都 JSON.stringify)</li><li><code>extractTokenUsage</code>:从 <code>message_delta</code> 事件的 <code>usage</code> 提取 Token(<code>request-writer.ts:50-54</code>)</li><li><code>pushNewRequest</code>:向 <code>data-push.ts</code> 的 <code>dataClients</code> 集合广播 JSON</li></ol><p>广播消息形状:</p><div class="language-json vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span></span>
130
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;type&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;request&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
131
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;action&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;new&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
132
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;data&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: {</span></span>
133
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;requestId&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;...&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
134
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;sessionId&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;...&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
135
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;compositeId&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;sess:req&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
136
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;method&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;POST&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
137
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;path&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;/v1/messages&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
138
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;timestamp&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;2026-07-04T...&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
139
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;statusCode&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">200</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
140
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;responseTime&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">3421</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
141
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;model&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;auto&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
142
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;machineId&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;hostname-hash&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
143
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;baseUrl&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;https://ark.cn-beijing.volces.com&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
144
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> &quot;usage&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: { </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;input_tokens&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;output_tokens&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;cache_read_input_tokens&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">&quot;cache_creation_input_tokens&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
145
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
146
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p><strong><code>/api/chat</code> 的 DB 记录特点</strong>:一条请求可能产生 1~N 条记录。第 1 条保存原始 SSE events(与客户端收到的完全一致),每次 inject loop 迭代有独立 DB 记录。所有记录共享同一 <code>sessionId</code>。</p><h2 id="面板端消费" tabindex="-1">面板端消费 <a class="header-anchor" href="#面板端消费" aria-label="Permalink to &quot;面板端消费&quot;">​</a></h2><p><code>apps/proxy-cli/src/hooks/useWebSocketData.ts:111-165</code>:</p><ul><li>收到 <code>type=request action=new</code>:去重(同 <code>compositeId</code> 剔除旧的) + 追加到列表首 + 按 <code>timestamp</code> 倒序 + 截 1000</li><li>同时 <code>fetchTodayStats()</code> 主动刷一次今日汇总(因为 stats 预聚合表每 5 分钟才更新)</li><li><code>type=stats action=notify</code>:触发一次 <code>fetchStats()</code> 拉最新 hourly/daily</li><li><code>type=status action=snapshot</code>:直接覆盖 <code>status</code> + <code>history</code></li><li><code>type=ping</code>:回一个 <code>{ type: &#39;pong&#39; }</code>,同时刷新 <code>lastActivity</code> 时间戳(30s 内无活动即关闭并触发重连)</li></ul><p>自动重连:指数退避 1s → 2s → 4s → 8s(封顶);<code>connectionState</code> 转成 <code>disconnected</code> 后由 <code>useEffect</code> 定时器触发 <code>connect()</code>。</p><h2 id="与并行数据源的关系" tabindex="-1">与并行数据源的关系 <a class="header-anchor" href="#与并行数据源的关系" aria-label="Permalink to &quot;与并行数据源的关系&quot;">​</a></h2><table tabindex="0"><thead><tr><th>数据类别</th><th>主通道</th><th>备用/初始 REST</th></tr></thead><tbody><tr><td>请求列表</td><td>WebSocket <code>type=request</code></td><td><code>GET /ui/api/requests?limit=1000</code></td></tr><tr><td>状态</td><td>WebSocket <code>type=status</code>(10s push)</td><td><code>GET /ui/api/status</code> + <code>/ui/api/status/history?duration=3600000</code></td></tr><tr><td>今日统计</td><td>WebSocket 触发前端主动 GET</td><td><code>GET /ui/api/stats/today?since=&lt;midnight ISO&gt;</code></td></tr><tr><td>小时/日聚合</td><td>WebSocket <code>type=stats</code> notify 触发主动 GET</td><td><code>GET /ui/api/stats</code></td></tr><tr><td>日志</td><td>独立通道 <code>/ui/api/logs/stream</code></td><td>—</td></tr><tr><td>配置</td><td>REST only</td><td><code>GET /ui/api/config</code></td></tr><tr><td>供应商</td><td>REST only</td><td><code>GET /ui/api/providers</code></td></tr><tr><td>MCP servers</td><td>REST only</td><td><code>GET /ui/api/mcp/servers</code></td></tr><tr><td>MCP tools</td><td>REST only</td><td><code>GET /ui/api/mcp/tools</code></td></tr></tbody></table><p>首帧数据来自 <code>refreshAll()</code>(<code>useWebSocketData.ts:61-75</code>)并发 5 个 REST;WebSocket 建连后接管增量。</p><h2 id="性能与容量注意" tabindex="-1">性能与容量注意 <a class="header-anchor" href="#性能与容量注意" aria-label="Permalink to &quot;性能与容量注意&quot;">​</a></h2><ul><li>SQLite 使用 WAL + <code>synchronous = NORMAL</code>(<code>db.ts:29-30</code>),单进程写、多连接读友好</li><li>每次业务请求都会跑 <code>cleanOldRequestsDB(maxDays)</code>(<code>proxy.ts:233</code>),成本是一个按 timestamp 索引扫描的 DELETE;<code>maxDays=0</code> 时函数直接 return</li><li><code>stats</code> 聚合每 5 分钟一次(<code>proxy.ts:154-160</code>),并在启动时执行一次</li><li>大 SSE 响应(工具调用循环)走缓冲路径(<code>proxy.ts:339</code>)会占用内存等于响应总大小;纯 pipe 路径不缓冲</li></ul><h2 id="相关文档" tabindex="-1">相关文档 <a class="header-anchor" href="#相关文档" aria-label="Permalink to &quot;相关文档&quot;">​</a></h2><ul><li><code>/v1/*</code> 纯代理路径 → <a href="./proxy-core/proxy.html">proxy.md</a></li><li><code>/api/chat</code> 增强代理路径 → <a href="./proxy-core/chat-api.html">chat-api.md</a></li><li>Tool 注入 + MCP → <a href="./proxy-core/tool.html">tool.md</a></li><li>供应商 <code>resolveProxyTarget</code> → <a href="./proxy-core/providers.html">providers.md</a></li><li>UI 端 REST/WebSocket 端点表 → <a href="./proxy-core/ui-routes.html">ui-routes.md</a></li><li>面板消费 → <a href="./proxy-cli/data-hooks.html">data-hooks.md</a></li></ul>`,49)])])}const k=a(t,[["render",l]]);export{c as __pageData,k as default};
@@ -0,0 +1 @@
1
+ import{_ as a,o as i,c as e,a2 as n}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"02. 端到端请求流转","description":"","frontmatter":{},"headers":[],"relativePath":"request-flow.md","filePath":"request-flow.md"}'),t={name:"request-flow.md"};function l(p,s,d,o,h,E){return i(),e("div",null,[...s[0]||(s[0]=[n("",49)])])}const k=a(t,[["render",l]]);export{c as __pageData,k as default};