@jonathanleelx/meddle 0.0.1

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 (361) hide show
  1. package/CONFIG_STRUCTURE.md +315 -0
  2. package/LICENSE +21 -0
  3. package/README.md +298 -0
  4. package/bin/commands/mock/add.js +92 -0
  5. package/bin/commands/mock/delete.js +58 -0
  6. package/bin/commands/mock/index.js +50 -0
  7. package/bin/commands/mock/list.js +68 -0
  8. package/bin/commands/mock/toggle.js +64 -0
  9. package/bin/commands/mock/update.js +94 -0
  10. package/bin/commands/route/active.js +141 -0
  11. package/bin/commands/route/add.js +127 -0
  12. package/bin/commands/route/create.js +77 -0
  13. package/bin/commands/route/delete.js +120 -0
  14. package/bin/commands/route/index.js +59 -0
  15. package/bin/commands/route/list.js +67 -0
  16. package/bin/commands/route/preview.js +159 -0
  17. package/bin/commands/route/show.js +111 -0
  18. package/bin/commands/route/update.js +126 -0
  19. package/bin/commands/session/create.js +166 -0
  20. package/bin/commands/session/delete.js +69 -0
  21. package/bin/commands/session/index.js +61 -0
  22. package/bin/commands/session/list.js +42 -0
  23. package/bin/commands/session/prune.js +31 -0
  24. package/bin/commands/start.js +43 -0
  25. package/bin/commands/status.js +115 -0
  26. package/bin/commands/supervise.js +106 -0
  27. package/bin/commands/url.js +30 -0
  28. package/bin/doctor.js +356 -0
  29. package/bin/index +130 -0
  30. package/bin/lib/api-client.js +72 -0
  31. package/bin/lib/file-access.js +337 -0
  32. package/bin/lib/meddle-home.js +20 -0
  33. package/bin/lib/output.js +146 -0
  34. package/bin/lib/parsers.js +127 -0
  35. package/bin/lib/proxy-detect.js +105 -0
  36. package/bin/lib/route-preview.js +180 -0
  37. package/bin/lib/session-args.js +54 -0
  38. package/bin/lib/sessions.js +213 -0
  39. package/dist/cert.d.ts +10 -0
  40. package/dist/cert.d.ts.map +1 -0
  41. package/dist/cert.js +184 -0
  42. package/dist/cert.js.map +1 -0
  43. package/dist/core/application-identity.d.ts +55 -0
  44. package/dist/core/application-identity.d.ts.map +1 -0
  45. package/dist/core/application-identity.js +321 -0
  46. package/dist/core/application-identity.js.map +1 -0
  47. package/dist/core/body-utils.d.ts +2 -0
  48. package/dist/core/body-utils.d.ts.map +1 -0
  49. package/dist/core/body-utils.js +21 -0
  50. package/dist/core/body-utils.js.map +1 -0
  51. package/dist/core/browser.d.ts +2 -0
  52. package/dist/core/browser.d.ts.map +1 -0
  53. package/dist/core/browser.js +92 -0
  54. package/dist/core/browser.js.map +1 -0
  55. package/dist/core/client-identity.d.ts +27 -0
  56. package/dist/core/client-identity.d.ts.map +1 -0
  57. package/dist/core/client-identity.js +136 -0
  58. package/dist/core/client-identity.js.map +1 -0
  59. package/dist/core/config-diagnostics.d.ts +14 -0
  60. package/dist/core/config-diagnostics.d.ts.map +1 -0
  61. package/dist/core/config-diagnostics.js +137 -0
  62. package/dist/core/config-diagnostics.js.map +1 -0
  63. package/dist/core/connect-tunnel.d.ts +5 -0
  64. package/dist/core/connect-tunnel.d.ts.map +1 -0
  65. package/dist/core/connect-tunnel.js +45 -0
  66. package/dist/core/connect-tunnel.js.map +1 -0
  67. package/dist/core/content-encoding.d.ts +2 -0
  68. package/dist/core/content-encoding.d.ts.map +1 -0
  69. package/dist/core/content-encoding.js +77 -0
  70. package/dist/core/content-encoding.js.map +1 -0
  71. package/dist/core/custom-plugin-loader.d.ts +18 -0
  72. package/dist/core/custom-plugin-loader.d.ts.map +1 -0
  73. package/dist/core/custom-plugin-loader.js +178 -0
  74. package/dist/core/custom-plugin-loader.js.map +1 -0
  75. package/dist/core/h2-pool.d.ts +4 -0
  76. package/dist/core/h2-pool.d.ts.map +1 -0
  77. package/dist/core/h2-pool.js +180 -0
  78. package/dist/core/h2-pool.js.map +1 -0
  79. package/dist/core/inspection-dispatch.d.ts +5 -0
  80. package/dist/core/inspection-dispatch.d.ts.map +1 -0
  81. package/dist/core/inspection-dispatch.js +146 -0
  82. package/dist/core/inspection-dispatch.js.map +1 -0
  83. package/dist/core/log-rate-limit.d.ts +34 -0
  84. package/dist/core/log-rate-limit.d.ts.map +1 -0
  85. package/dist/core/log-rate-limit.js +52 -0
  86. package/dist/core/log-rate-limit.js.map +1 -0
  87. package/dist/core/map-local.d.ts +4 -0
  88. package/dist/core/map-local.d.ts.map +1 -0
  89. package/dist/core/map-local.js +195 -0
  90. package/dist/core/map-local.js.map +1 -0
  91. package/dist/core/meddle-home.d.ts +13 -0
  92. package/dist/core/meddle-home.d.ts.map +1 -0
  93. package/dist/core/meddle-home.js +56 -0
  94. package/dist/core/meddle-home.js.map +1 -0
  95. package/dist/core/mock-gate.d.ts +3 -0
  96. package/dist/core/mock-gate.d.ts.map +1 -0
  97. package/dist/core/mock-gate.js +20 -0
  98. package/dist/core/mock-gate.js.map +1 -0
  99. package/dist/core/mock-handler.d.ts +5 -0
  100. package/dist/core/mock-handler.d.ts.map +1 -0
  101. package/dist/core/mock-handler.js +339 -0
  102. package/dist/core/mock-handler.js.map +1 -0
  103. package/dist/core/on-mode-gate.d.ts +4 -0
  104. package/dist/core/on-mode-gate.d.ts.map +1 -0
  105. package/dist/core/on-mode-gate.js +64 -0
  106. package/dist/core/on-mode-gate.js.map +1 -0
  107. package/dist/core/pipeline-gate.d.ts +3 -0
  108. package/dist/core/pipeline-gate.d.ts.map +1 -0
  109. package/dist/core/pipeline-gate.js +34 -0
  110. package/dist/core/pipeline-gate.js.map +1 -0
  111. package/dist/core/pipeline.d.ts +6 -0
  112. package/dist/core/pipeline.d.ts.map +1 -0
  113. package/dist/core/pipeline.js +228 -0
  114. package/dist/core/pipeline.js.map +1 -0
  115. package/dist/core/plugin-bootstrap-runner.d.ts +6 -0
  116. package/dist/core/plugin-bootstrap-runner.d.ts.map +1 -0
  117. package/dist/core/plugin-bootstrap-runner.js +148 -0
  118. package/dist/core/plugin-bootstrap-runner.js.map +1 -0
  119. package/dist/core/plugin-bootstrap.d.ts +3 -0
  120. package/dist/core/plugin-bootstrap.d.ts.map +1 -0
  121. package/dist/core/plugin-bootstrap.js +15 -0
  122. package/dist/core/plugin-bootstrap.js.map +1 -0
  123. package/dist/core/plugin-compiler.d.ts +37 -0
  124. package/dist/core/plugin-compiler.d.ts.map +1 -0
  125. package/dist/core/plugin-compiler.js +172 -0
  126. package/dist/core/plugin-compiler.js.map +1 -0
  127. package/dist/core/plugin-context-factory.d.ts +29 -0
  128. package/dist/core/plugin-context-factory.d.ts.map +1 -0
  129. package/dist/core/plugin-context-factory.js +206 -0
  130. package/dist/core/plugin-context-factory.js.map +1 -0
  131. package/dist/core/plugin-generator.d.ts +47 -0
  132. package/dist/core/plugin-generator.d.ts.map +1 -0
  133. package/dist/core/plugin-generator.js +697 -0
  134. package/dist/core/plugin-generator.js.map +1 -0
  135. package/dist/core/plugin-health.d.ts +3 -0
  136. package/dist/core/plugin-health.d.ts.map +1 -0
  137. package/dist/core/plugin-health.js +54 -0
  138. package/dist/core/plugin-health.js.map +1 -0
  139. package/dist/core/plugin-intercept.d.ts +17 -0
  140. package/dist/core/plugin-intercept.d.ts.map +1 -0
  141. package/dist/core/plugin-intercept.js +133 -0
  142. package/dist/core/plugin-intercept.js.map +1 -0
  143. package/dist/core/plugin-runtime.d.ts +33 -0
  144. package/dist/core/plugin-runtime.d.ts.map +1 -0
  145. package/dist/core/plugin-runtime.js +254 -0
  146. package/dist/core/plugin-runtime.js.map +1 -0
  147. package/dist/core/proxy-context.d.ts +3 -0
  148. package/dist/core/proxy-context.d.ts.map +1 -0
  149. package/dist/core/proxy-context.js +129 -0
  150. package/dist/core/proxy-context.js.map +1 -0
  151. package/dist/core/proxy-record.d.ts +3 -0
  152. package/dist/core/proxy-record.d.ts.map +1 -0
  153. package/dist/core/proxy-record.js +32 -0
  154. package/dist/core/proxy-record.js.map +1 -0
  155. package/dist/core/refactor-config.d.ts +6 -0
  156. package/dist/core/refactor-config.d.ts.map +1 -0
  157. package/dist/core/refactor-config.js +45 -0
  158. package/dist/core/refactor-config.js.map +1 -0
  159. package/dist/core/refactor-status.d.ts +3 -0
  160. package/dist/core/refactor-status.d.ts.map +1 -0
  161. package/dist/core/refactor-status.js +19 -0
  162. package/dist/core/refactor-status.js.map +1 -0
  163. package/dist/core/remote-access.d.ts +40 -0
  164. package/dist/core/remote-access.d.ts.map +1 -0
  165. package/dist/core/remote-access.js +281 -0
  166. package/dist/core/remote-access.js.map +1 -0
  167. package/dist/core/route-decision.d.ts +3 -0
  168. package/dist/core/route-decision.d.ts.map +1 -0
  169. package/dist/core/route-decision.js +20 -0
  170. package/dist/core/route-decision.js.map +1 -0
  171. package/dist/core/route-loader.d.ts +14 -0
  172. package/dist/core/route-loader.d.ts.map +1 -0
  173. package/dist/core/route-loader.js +94 -0
  174. package/dist/core/route-loader.js.map +1 -0
  175. package/dist/core/route-preview.d.ts +15 -0
  176. package/dist/core/route-preview.d.ts.map +1 -0
  177. package/dist/core/route-preview.js +91 -0
  178. package/dist/core/route-preview.js.map +1 -0
  179. package/dist/core/runtime-health.d.ts +92 -0
  180. package/dist/core/runtime-health.d.ts.map +1 -0
  181. package/dist/core/runtime-health.js +205 -0
  182. package/dist/core/runtime-health.js.map +1 -0
  183. package/dist/core/sessions.d.ts +19 -0
  184. package/dist/core/sessions.d.ts.map +1 -0
  185. package/dist/core/sessions.js +93 -0
  186. package/dist/core/sessions.js.map +1 -0
  187. package/dist/core/shadow-compare.d.ts +8 -0
  188. package/dist/core/shadow-compare.d.ts.map +1 -0
  189. package/dist/core/shadow-compare.js +83 -0
  190. package/dist/core/shadow-compare.js.map +1 -0
  191. package/dist/core/shadow-readiness.d.ts +4 -0
  192. package/dist/core/shadow-readiness.d.ts.map +1 -0
  193. package/dist/core/shadow-readiness.js +118 -0
  194. package/dist/core/shadow-readiness.js.map +1 -0
  195. package/dist/core/short-response.d.ts +5 -0
  196. package/dist/core/short-response.d.ts.map +1 -0
  197. package/dist/core/short-response.js +18 -0
  198. package/dist/core/short-response.js.map +1 -0
  199. package/dist/core/static-server.d.ts +9 -0
  200. package/dist/core/static-server.d.ts.map +1 -0
  201. package/dist/core/static-server.js +136 -0
  202. package/dist/core/static-server.js.map +1 -0
  203. package/dist/core/types.d.ts +590 -0
  204. package/dist/core/types.d.ts.map +1 -0
  205. package/dist/core/types.js +4 -0
  206. package/dist/core/types.js.map +1 -0
  207. package/dist/helpers.d.ts +36 -0
  208. package/dist/helpers.d.ts.map +1 -0
  209. package/dist/helpers.js +290 -0
  210. package/dist/helpers.js.map +1 -0
  211. package/dist/plugins/builtin/index.d.ts +3 -0
  212. package/dist/plugins/builtin/index.d.ts.map +1 -0
  213. package/dist/plugins/builtin/index.js +23 -0
  214. package/dist/plugins/builtin/index.js.map +1 -0
  215. package/dist/plugins/builtin/logger-plugin.d.ts +8 -0
  216. package/dist/plugins/builtin/logger-plugin.d.ts.map +1 -0
  217. package/dist/plugins/builtin/logger-plugin.js +121 -0
  218. package/dist/plugins/builtin/logger-plugin.js.map +1 -0
  219. package/dist/plugins/builtin/mock-plugin.d.ts +3 -0
  220. package/dist/plugins/builtin/mock-plugin.d.ts.map +1 -0
  221. package/dist/plugins/builtin/mock-plugin.js +99 -0
  222. package/dist/plugins/builtin/mock-plugin.js.map +1 -0
  223. package/dist/plugins/builtin/router-plugin.d.ts +3 -0
  224. package/dist/plugins/builtin/router-plugin.d.ts.map +1 -0
  225. package/dist/plugins/builtin/router-plugin.js +36 -0
  226. package/dist/plugins/builtin/router-plugin.js.map +1 -0
  227. package/dist/server/agent/model.d.ts +30 -0
  228. package/dist/server/agent/model.d.ts.map +1 -0
  229. package/dist/server/agent/model.js +143 -0
  230. package/dist/server/agent/model.js.map +1 -0
  231. package/dist/server/agent/routes.d.ts +4 -0
  232. package/dist/server/agent/routes.d.ts.map +1 -0
  233. package/dist/server/agent/routes.js +188 -0
  234. package/dist/server/agent/routes.js.map +1 -0
  235. package/dist/server/agent/runtime.d.ts +12 -0
  236. package/dist/server/agent/runtime.d.ts.map +1 -0
  237. package/dist/server/agent/runtime.js +208 -0
  238. package/dist/server/agent/runtime.js.map +1 -0
  239. package/dist/server/agent/tools.d.ts +13 -0
  240. package/dist/server/agent/tools.d.ts.map +1 -0
  241. package/dist/server/agent/tools.js +1201 -0
  242. package/dist/server/agent/tools.js.map +1 -0
  243. package/dist/server/agent/types.d.ts +56 -0
  244. package/dist/server/agent/types.d.ts.map +1 -0
  245. package/dist/server/agent/types.js +3 -0
  246. package/dist/server/agent/types.js.map +1 -0
  247. package/dist/server/config.d.ts +9 -0
  248. package/dist/server/config.d.ts.map +1 -0
  249. package/dist/server/config.js +124 -0
  250. package/dist/server/config.js.map +1 -0
  251. package/dist/server/health.d.ts +4 -0
  252. package/dist/server/health.d.ts.map +1 -0
  253. package/dist/server/health.js +22 -0
  254. package/dist/server/health.js.map +1 -0
  255. package/dist/server/index.d.ts +239 -0
  256. package/dist/server/index.d.ts.map +1 -0
  257. package/dist/server/index.js +44 -0
  258. package/dist/server/index.js.map +1 -0
  259. package/dist/server/logs.d.ts +4 -0
  260. package/dist/server/logs.d.ts.map +1 -0
  261. package/dist/server/logs.js +40 -0
  262. package/dist/server/logs.js.map +1 -0
  263. package/dist/server/mocks.d.ts +9 -0
  264. package/dist/server/mocks.d.ts.map +1 -0
  265. package/dist/server/mocks.js +103 -0
  266. package/dist/server/mocks.js.map +1 -0
  267. package/dist/server/pipeline.d.ts +16 -0
  268. package/dist/server/pipeline.d.ts.map +1 -0
  269. package/dist/server/pipeline.js +159 -0
  270. package/dist/server/pipeline.js.map +1 -0
  271. package/dist/server/plugins.d.ts +32 -0
  272. package/dist/server/plugins.d.ts.map +1 -0
  273. package/dist/server/plugins.js +795 -0
  274. package/dist/server/plugins.js.map +1 -0
  275. package/dist/server/refactor.d.ts +4 -0
  276. package/dist/server/refactor.d.ts.map +1 -0
  277. package/dist/server/refactor.js +86 -0
  278. package/dist/server/refactor.js.map +1 -0
  279. package/dist/server/rule-files.d.ts +34 -0
  280. package/dist/server/rule-files.d.ts.map +1 -0
  281. package/dist/server/rule-files.js +389 -0
  282. package/dist/server/rule-files.js.map +1 -0
  283. package/dist/server/rules.d.ts +4 -0
  284. package/dist/server/rules.d.ts.map +1 -0
  285. package/dist/server/rules.js +40 -0
  286. package/dist/server/rules.js.map +1 -0
  287. package/dist/server/sessions.d.ts +4 -0
  288. package/dist/server/sessions.d.ts.map +1 -0
  289. package/dist/server/sessions.js +20 -0
  290. package/dist/server/sessions.js.map +1 -0
  291. package/index.js +950 -0
  292. package/mcp-server.js +794 -0
  293. package/package.json +92 -0
  294. package/plugins/builtin/index.ts +25 -0
  295. package/plugins/builtin/logger-plugin.ts +126 -0
  296. package/plugins/builtin/mock-plugin.ts +112 -0
  297. package/plugins/builtin/router-plugin.ts +35 -0
  298. package/web/README.md +111 -0
  299. package/web/dist/assets/ai-config-store-DQXVJVn_.js +1 -0
  300. package/web/dist/assets/alert-COF-DIAE.js +1 -0
  301. package/web/dist/assets/arrow-right-B4Mrlj2-.js +1 -0
  302. package/web/dist/assets/babel-DsprIpXZ.js +15 -0
  303. package/web/dist/assets/body-diff-view-D7dCWajG.js +6 -0
  304. package/web/dist/assets/button-BTToMaBW.js +1 -0
  305. package/web/dist/assets/checkbox-DIBarrJx.js +1 -0
  306. package/web/dist/assets/chevron-down-CPngAx4M.js +1 -0
  307. package/web/dist/assets/chevron-right-V1DGIDbL.js +1 -0
  308. package/web/dist/assets/circle-alert-Q8cZk9Rv.js +1 -0
  309. package/web/dist/assets/circle-x-C9USji_R.js +1 -0
  310. package/web/dist/assets/code-5_eJ_XpJ.js +1 -0
  311. package/web/dist/assets/code-fixer-fQtWZ5He.js +20 -0
  312. package/web/dist/assets/copy-BYjq1hdN.js +1 -0
  313. package/web/dist/assets/detail-panel-BX_hxeI0.js +3 -0
  314. package/web/dist/assets/dist-B8XUKgXe.js +1 -0
  315. package/web/dist/assets/dist-Bb9TeEub.js +1 -0
  316. package/web/dist/assets/dist-C5nMErq8.js +1 -0
  317. package/web/dist/assets/dist-C6eaYCUo.js +1 -0
  318. package/web/dist/assets/dist-Cn0y0IRn.js +1 -0
  319. package/web/dist/assets/dist-CxdY_A67.js +5 -0
  320. package/web/dist/assets/dist-D5Dj17P8.js +1 -0
  321. package/web/dist/assets/dist-DZJ9SMlJ.js +1 -0
  322. package/web/dist/assets/es2015-CfXu88Y7.js +41 -0
  323. package/web/dist/assets/estree-BP7k0NIt.js +44 -0
  324. package/web/dist/assets/file-system-access-CtcvBfj4.js +1 -0
  325. package/web/dist/assets/global-panel-shell-ChdO0dWd.js +6 -0
  326. package/web/dist/assets/health-panel-CQeCQ7gr.js +1 -0
  327. package/web/dist/assets/html-6FIWbqxX.js +25 -0
  328. package/web/dist/assets/index-CjqaTnE_.css +2 -0
  329. package/web/dist/assets/index-L7uWxTnp.js +18 -0
  330. package/web/dist/assets/mobile-proxy-panel-Dj1iLami.js +8 -0
  331. package/web/dist/assets/mock-config-BTTCw7RK.js +1 -0
  332. package/web/dist/assets/mock-editor-panel-C-aVfFme.js +1 -0
  333. package/web/dist/assets/monaco-editor-B3brLg8j.js +11 -0
  334. package/web/dist/assets/pencil-line-Cqe41E4h.js +1 -0
  335. package/web/dist/assets/plugin-code-editor-CPjCbJ9g.js +2 -0
  336. package/web/dist/assets/plugin-config-BzmCkvz3.js +1 -0
  337. package/web/dist/assets/plugin-generator-BnEafDF9.js +2 -0
  338. package/web/dist/assets/plugin-test-dialog-BWoWsWV4.js +7 -0
  339. package/web/dist/assets/plus-tVxSydJ8.js +1 -0
  340. package/web/dist/assets/postcss-Dnf30fQU.js +61 -0
  341. package/web/dist/assets/refresh-cw-CG3HaiQT.js +1 -0
  342. package/web/dist/assets/rotate-ccw-CAYM6Vv0.js +1 -0
  343. package/web/dist/assets/route-preview-BX7sfY0O.js +1 -0
  344. package/web/dist/assets/rule-ai-assistant-panel-WBiOOUw5.js +47 -0
  345. package/web/dist/assets/rule-config-CHpVij2M.css +1 -0
  346. package/web/dist/assets/rule-config-fTIZVwg1.js +15 -0
  347. package/web/dist/assets/select-CkFOB61l.js +1 -0
  348. package/web/dist/assets/server-Cpj4KNwN.js +1 -0
  349. package/web/dist/assets/settings-panel-COCYiIUg.js +1 -0
  350. package/web/dist/assets/shield-check-OqUmVLQt.js +1 -0
  351. package/web/dist/assets/smartphone-DKeDuJTU.js +1 -0
  352. package/web/dist/assets/standalone-CjxtLKw-.js +29 -0
  353. package/web/dist/assets/switch-C-Xk56TK.js +1 -0
  354. package/web/dist/assets/syntax-highlight-DVhPdkuV.js +5 -0
  355. package/web/dist/assets/table-CT97lAYq.js +1 -0
  356. package/web/dist/assets/textarea-C6NooVK1.js +1 -0
  357. package/web/dist/assets/wand-sparkles-wkul5vje.js +1 -0
  358. package/web/dist/assets/wifi-D9M35Ajj.js +1 -0
  359. package/web/dist/assets/zap-Djo4cgux.js +1 -0
  360. package/web/dist/index.html +24 -0
  361. package/web/dist/vite.svg +1 -0
@@ -0,0 +1,795 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.reloadPlugins = reloadPlugins;
37
+ exports.setPluginEnabled = setPluginEnabled;
38
+ exports.sortPluginsByHookOrder = sortPluginsByHookOrder;
39
+ exports.selectTestPluginsForHook = selectTestPluginsForHook;
40
+ exports.registerPluginsRoutes = registerPluginsRoutes;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ async function reloadPlugins(ctx) {
44
+ const plugins = await ctx.reloadCustomPlugins();
45
+ const summaries = plugins.map((p) => {
46
+ const plugin = p;
47
+ return {
48
+ id: plugin.manifest.id,
49
+ name: plugin.manifest.name,
50
+ version: plugin.manifest.version,
51
+ };
52
+ });
53
+ return {
54
+ status: 'success',
55
+ message: `已重新加载 ${summaries.length} 个自定义插件`,
56
+ count: summaries.length,
57
+ plugins: summaries,
58
+ };
59
+ }
60
+ function setPluginEnabled(ctx, pluginId, enabled) {
61
+ const allPlugins = ctx.pluginManager.getAll();
62
+ const target = allPlugins.find(p => p.manifest.id === pluginId);
63
+ if (!target) {
64
+ throw new Error('插件不存在');
65
+ }
66
+ const newState = enabled ? 'running' : 'disabled';
67
+ ctx.pluginManager.setState(pluginId, newState);
68
+ try {
69
+ let settings = {};
70
+ if (fs.existsSync(ctx.settingsPath)) {
71
+ settings = JSON.parse(fs.readFileSync(ctx.settingsPath, 'utf8'));
72
+ }
73
+ const disabledPlugins = Array.isArray(settings.disabledPlugins)
74
+ ? settings.disabledPlugins
75
+ : [];
76
+ if (enabled) {
77
+ settings.disabledPlugins = disabledPlugins.filter(id => id !== pluginId);
78
+ }
79
+ else {
80
+ if (!disabledPlugins.includes(pluginId)) {
81
+ disabledPlugins.push(pluginId);
82
+ }
83
+ settings.disabledPlugins = disabledPlugins;
84
+ }
85
+ fs.writeFileSync(ctx.settingsPath, JSON.stringify(settings, null, 2), 'utf8');
86
+ }
87
+ catch (e) {
88
+ console.error('保存插件状态失败:', e);
89
+ }
90
+ return {
91
+ status: 'success',
92
+ pluginId,
93
+ state: newState,
94
+ };
95
+ }
96
+ function sortPluginsByHookOrder(plugins) {
97
+ return [...plugins].sort((a, b) => {
98
+ const priorityA = typeof a.manifest.priority === 'number' ? a.manifest.priority : 100;
99
+ const priorityB = typeof b.manifest.priority === 'number' ? b.manifest.priority : 100;
100
+ if (priorityA !== priorityB)
101
+ return priorityA - priorityB;
102
+ return a.manifest.id.localeCompare(b.manifest.id);
103
+ });
104
+ }
105
+ function selectTestPluginsForHook(allPlugins, hookName, targetPluginId, includeBuiltinFlow) {
106
+ const allowedIds = new Set([targetPluginId]);
107
+ if (includeBuiltinFlow) {
108
+ allowedIds.add('builtin.mock');
109
+ allowedIds.add('builtin.router');
110
+ }
111
+ return sortPluginsByHookOrder(allPlugins.filter((plugin) => allowedIds.has(plugin.manifest.id) &&
112
+ Array.isArray(plugin.manifest.hooks) &&
113
+ plugin.manifest.hooks.includes(hookName)));
114
+ }
115
+ function registerPluginsRoutes(app, ctx) {
116
+ const meddleDir = ctx.meddleDir;
117
+ // API: 生成插件代码(流式)
118
+ app.post('/api/plugins/generate-stream', async (req, res) => {
119
+ try {
120
+ const data = req.body;
121
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
122
+ const { generatePluginStream, cleanAIResponse } = require('../core/plugin-generator');
123
+ // 设置 SSE 响应头
124
+ res.writeHead(200, {
125
+ 'Content-Type': 'text/event-stream',
126
+ 'Cache-Control': 'no-cache',
127
+ 'Connection': 'keep-alive',
128
+ 'Access-Control-Allow-Origin': '*'
129
+ });
130
+ // 发送初始事件
131
+ res.write('event: start\n');
132
+ res.write('data: {"status":"generating"}\n\n');
133
+ let accumulatedCode = '';
134
+ // 生成插件,实时发送chunk
135
+ const result = await generatePluginStream(data.requirement, data.aiConfig, (chunk) => {
136
+ accumulatedCode += chunk;
137
+ res.write('event: chunk\n');
138
+ res.write(`data: ${JSON.stringify({ chunk, accumulated: cleanAIResponse(accumulatedCode) })}\n\n`);
139
+ });
140
+ // 发送完成事件
141
+ res.write('event: complete\n');
142
+ res.write(`data: ${JSON.stringify({ status: 'success', plugin: result })}\n\n`);
143
+ res.end();
144
+ }
145
+ catch (error) {
146
+ res.write('event: error\n');
147
+ res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
148
+ res.end();
149
+ }
150
+ });
151
+ // API: 生成插件代码(非流式,向后兼容)
152
+ app.post('/api/plugins/generate', async (req, res) => {
153
+ res.setHeader('Content-Type', 'application/json');
154
+ try {
155
+ const data = req.body;
156
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
157
+ const { generatePlugin } = require('../core/plugin-generator');
158
+ const result = await generatePlugin(data.requirement, data.aiConfig);
159
+ res.write(JSON.stringify({ status: 'success', plugin: result }));
160
+ }
161
+ catch (error) {
162
+ res.statusCode = 500;
163
+ res.write(JSON.stringify({ error: error.message }));
164
+ }
165
+ res.end();
166
+ });
167
+ // API: 保存插件到配置目录
168
+ app.post('/api/plugins/save', (req, res) => {
169
+ res.setHeader('Content-Type', 'application/json');
170
+ try {
171
+ const data = req.body;
172
+ const pluginsDir = path.resolve(meddleDir, 'plugins');
173
+ // 创建 plugins 目录
174
+ if (!fs.existsSync(pluginsDir)) {
175
+ fs.mkdirSync(pluginsDir, { recursive: true });
176
+ }
177
+ const filePath = path.resolve(pluginsDir, data.filename);
178
+ fs.writeFileSync(filePath, data.code, 'utf8');
179
+ console.log(`已保存插件: ${data.filename}`);
180
+ res.write(JSON.stringify({
181
+ status: 'success',
182
+ message: '插件已保存',
183
+ path: filePath
184
+ }));
185
+ }
186
+ catch (error) {
187
+ res.statusCode = 500;
188
+ res.write(JSON.stringify({ error: error.message }));
189
+ }
190
+ res.end();
191
+ });
192
+ // API: 列出自定义插件
193
+ app.get('/api/plugins/custom', (_req, res) => {
194
+ res.setHeader('Content-Type', 'application/json');
195
+ try {
196
+ const pluginsDir = path.resolve(meddleDir, 'plugins');
197
+ if (!fs.existsSync(pluginsDir)) {
198
+ res.write(JSON.stringify({ plugins: [] }));
199
+ res.end();
200
+ return;
201
+ }
202
+ const files = fs.readdirSync(pluginsDir);
203
+ const pluginInfo = [];
204
+ // 只列出.js文件
205
+ const jsFiles = files.filter(f => f.endsWith('.js'));
206
+ jsFiles.forEach(jsFile => {
207
+ const jsPath = path.resolve(pluginsDir, jsFile);
208
+ const jsStat = fs.statSync(jsPath);
209
+ pluginInfo.push({
210
+ filename: jsFile,
211
+ path: jsPath,
212
+ modified: jsStat.mtime
213
+ });
214
+ });
215
+ res.write(JSON.stringify({ plugins: pluginInfo }));
216
+ }
217
+ catch (error) {
218
+ res.statusCode = 500;
219
+ res.write(JSON.stringify({ error: error.message }));
220
+ }
221
+ res.end();
222
+ });
223
+ // API: 读取插件源码
224
+ app.get('/api/plugins/custom/:filename/code', (req, res) => {
225
+ try {
226
+ const filename = decodeURIComponent(req.params.filename);
227
+ const pluginsDir = path.resolve(meddleDir, 'plugins');
228
+ const filePath = path.resolve(pluginsDir, filename);
229
+ if (!filePath.startsWith(pluginsDir)) {
230
+ res.status(403).json({ error: '非法的文件路径' });
231
+ return;
232
+ }
233
+ if (!fs.existsSync(filePath)) {
234
+ res.status(404).json({ error: '插件文件不存在' });
235
+ return;
236
+ }
237
+ const code = fs.readFileSync(filePath, 'utf8');
238
+ res.json({ filename, code });
239
+ }
240
+ catch (error) {
241
+ res.status(500).json({ error: error.message });
242
+ }
243
+ });
244
+ // API: 更新插件源码
245
+ app.put('/api/plugins/custom/:filename/code', (req, res) => {
246
+ try {
247
+ const filename = decodeURIComponent(req.params.filename);
248
+ const pluginsDir = path.resolve(meddleDir, 'plugins');
249
+ const filePath = path.resolve(pluginsDir, filename);
250
+ if (!filePath.startsWith(pluginsDir)) {
251
+ res.status(403).json({ error: '非法的文件路径' });
252
+ return;
253
+ }
254
+ if (!fs.existsSync(filePath)) {
255
+ res.status(404).json({ error: '插件文件不存在' });
256
+ return;
257
+ }
258
+ const { code } = req.body;
259
+ if (typeof code !== 'string') {
260
+ res.status(400).json({ error: '缺少 code 字段' });
261
+ return;
262
+ }
263
+ fs.writeFileSync(filePath, code, 'utf8');
264
+ console.log(`已更新插件代码: ${filename}`);
265
+ res.json({ status: 'success', message: '插件代码已保存' });
266
+ }
267
+ catch (error) {
268
+ res.status(500).json({ error: error.message });
269
+ }
270
+ });
271
+ // API: 删除自定义插件
272
+ app.delete('/api/plugins/custom/:filename', (req, res) => {
273
+ res.setHeader('Content-Type', 'application/json');
274
+ try {
275
+ const filename = decodeURIComponent(req.params.filename);
276
+ const pluginsDir = path.resolve(meddleDir, 'plugins');
277
+ const filePath = path.resolve(pluginsDir, filename);
278
+ // 安全检查:确保文件在 plugins 目录内
279
+ if (!filePath.startsWith(pluginsDir)) {
280
+ res.statusCode = 403;
281
+ res.write(JSON.stringify({ error: '非法的文件路径' }));
282
+ res.end();
283
+ return;
284
+ }
285
+ if (fs.existsSync(filePath)) {
286
+ fs.unlinkSync(filePath);
287
+ // 同时删除编译后的.js文件
288
+ if (filename.endsWith('.ts')) {
289
+ const jsPath = filePath.replace(/\.ts$/, '.js');
290
+ if (fs.existsSync(jsPath)) {
291
+ fs.unlinkSync(jsPath);
292
+ }
293
+ }
294
+ res.write(JSON.stringify({
295
+ status: 'success',
296
+ message: '插件已删除'
297
+ }));
298
+ }
299
+ else {
300
+ res.statusCode = 404;
301
+ res.write(JSON.stringify({ error: '插件文件不存在' }));
302
+ }
303
+ }
304
+ catch (error) {
305
+ res.statusCode = 500;
306
+ res.write(JSON.stringify({ error: error.message }));
307
+ }
308
+ res.end();
309
+ });
310
+ // API: 热加载自定义插件
311
+ app.post('/api/plugins/reload', async (_req, res) => {
312
+ res.setHeader('Content-Type', 'application/json');
313
+ try {
314
+ res.write(JSON.stringify(await reloadPlugins(ctx)));
315
+ }
316
+ catch (error) {
317
+ res.statusCode = 500;
318
+ res.write(JSON.stringify({ error: error.message }));
319
+ }
320
+ res.end();
321
+ });
322
+ // API: AI自动修复插件
323
+ app.post('/api/plugins/fix', async (req, res) => {
324
+ res.setHeader('Content-Type', 'application/json');
325
+ try {
326
+ const data = req.body;
327
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
328
+ const { fixPluginWithAI } = require('../core/plugin-generator');
329
+ const fixedCode = await fixPluginWithAI(data.originalCode, data.testError, data.requirement, data.aiConfig);
330
+ res.write(JSON.stringify({ status: 'success', fixedCode }));
331
+ }
332
+ catch (error) {
333
+ res.statusCode = 500;
334
+ res.write(JSON.stringify({ error: error.message }));
335
+ }
336
+ res.end();
337
+ });
338
+ // API: AI自动修复插件(流式)
339
+ app.post('/api/plugins/fix-stream', async (req, res) => {
340
+ try {
341
+ const data = req.body;
342
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
343
+ const { fixPluginWithAIStream, cleanAIResponse } = require('../core/plugin-generator');
344
+ res.writeHead(200, {
345
+ 'Content-Type': 'text/event-stream',
346
+ 'Cache-Control': 'no-cache',
347
+ 'Connection': 'keep-alive',
348
+ 'Access-Control-Allow-Origin': '*'
349
+ });
350
+ res.write('event: start\n');
351
+ res.write('data: {"status":"generating"}\n\n');
352
+ let accumulatedCode = '';
353
+ const fixedCode = await fixPluginWithAIStream(data.originalCode, data.testError, data.requirement, data.aiConfig, (chunk) => {
354
+ accumulatedCode += chunk;
355
+ res.write('event: chunk\n');
356
+ res.write(`data: ${JSON.stringify({ chunk, accumulated: cleanAIResponse(accumulatedCode) })}\n\n`);
357
+ });
358
+ res.write('event: complete\n');
359
+ res.write(`data: ${JSON.stringify({ status: 'success', fixedCode })}\n\n`);
360
+ res.end();
361
+ }
362
+ catch (error) {
363
+ res.write('event: error\n');
364
+ res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
365
+ res.end();
366
+ }
367
+ });
368
+ app.post('/api/plugins/revise-stream', async (req, res) => {
369
+ try {
370
+ const data = req.body;
371
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
372
+ const { revisePluginWithAIStream, cleanAIResponse } = require('../core/plugin-generator');
373
+ res.writeHead(200, {
374
+ 'Content-Type': 'text/event-stream',
375
+ 'Cache-Control': 'no-cache',
376
+ 'Connection': 'keep-alive',
377
+ 'Access-Control-Allow-Origin': '*'
378
+ });
379
+ res.write('event: start\n');
380
+ res.write('data: {"status":"generating"}\n\n');
381
+ let accumulatedCode = '';
382
+ const revisedCode = await revisePluginWithAIStream(data.originalCode, data.instruction, data.requirement, data.aiConfig, (chunk) => {
383
+ accumulatedCode += chunk;
384
+ res.write('event: chunk\n');
385
+ res.write(`data: ${JSON.stringify({ chunk, accumulated: cleanAIResponse(accumulatedCode) })}\n\n`);
386
+ });
387
+ res.write('event: complete\n');
388
+ res.write(`data: ${JSON.stringify({ status: 'success', revisedCode })}\n\n`);
389
+ res.end();
390
+ }
391
+ catch (error) {
392
+ res.write('event: error\n');
393
+ res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
394
+ res.end();
395
+ }
396
+ });
397
+ // API: 测试插件功能(真实请求模式)
398
+ app.post('/api/plugins/test', async (req, res) => {
399
+ res.setHeader('Content-Type', 'application/json');
400
+ try {
401
+ const data = req.body;
402
+ const pluginId = data.pluginId;
403
+ const url = data.url || 'http://example.com/test';
404
+ const method = (data.method || 'GET').toUpperCase();
405
+ const integrated = data.integrated !== false;
406
+ const allPlugins = ctx.pluginManager.getAll();
407
+ const targetPlugin = allPlugins.find(p => p.manifest.id === pluginId);
408
+ if (!targetPlugin) {
409
+ res.status(404).json({ error: '插件不存在' });
410
+ return;
411
+ }
412
+ const testLogs = [];
413
+ const testLogger = {
414
+ debug: (...args) => testLogs.push({ level: 'debug', message: args.join(' '), timestamp: Date.now() }),
415
+ log: (...args) => testLogs.push({ level: 'log', message: args.join(' '), timestamp: Date.now() }),
416
+ info: (...args) => testLogs.push({ level: 'info', message: args.join(' '), timestamp: Date.now() }),
417
+ warn: (...args) => testLogs.push({ level: 'warn', message: args.join(' '), timestamp: Date.now() }),
418
+ error: (...args) => testLogs.push({ level: 'error', message: args.join(' '), timestamp: Date.now() }),
419
+ };
420
+ const hooks = targetPlugin.manifest.hooks || [];
421
+ const hookResults = {};
422
+ // integrated=true:尽量贴近真实代理前半段(直出 Mock / 内置 Mock / Router 的先后)
423
+ const source = url;
424
+ const legacyTarget = integrated && typeof ctx.resolveTargetUrlForTest === 'function'
425
+ ? ctx.resolveTargetUrlForTest(source)
426
+ : source;
427
+ const usePipelineFlow = integrated && typeof ctx.canUsePipelineExecuteForTest === 'function'
428
+ ? ctx.canUsePipelineExecuteForTest(source)
429
+ : false;
430
+ let currentTarget = usePipelineFlow ? source : legacyTarget;
431
+ const requestMutable = {
432
+ method,
433
+ url: source,
434
+ headers: { 'user-agent': 'meddle-test/1.0', ...(data.headers || {}) },
435
+ body: data.body || '',
436
+ };
437
+ const initialRequestSnapshot = { headers: { ...requestMutable.headers }, body: requestMutable.body };
438
+ let shortCircuited = false;
439
+ let shortCircuitResponse = null;
440
+ let realResponse = null;
441
+ let fetchError = null;
442
+ let fetchDuration = 0;
443
+ let usedMock = false;
444
+ const requestMeta = { _test: true, _pluginRequestStartAt: Date.now() };
445
+ // --- Phase 0: 与真实代理一致,先处理“直出 Mock”路径 ---
446
+ if (integrated) {
447
+ const mockRule = typeof ctx.matchMockRuleForTest === 'function'
448
+ ? ctx.matchMockRuleForTest(source, method)
449
+ : null;
450
+ if (mockRule && typeof ctx.shouldUseMockForTest === 'function' && ctx.shouldUseMockForTest(source, mockRule) && typeof ctx.buildMockResponseForTest === 'function') {
451
+ const mockRes = ctx.buildMockResponseForTest(mockRule);
452
+ currentTarget = source;
453
+ realResponse = { statusCode: mockRes.statusCode, headers: mockRes.headers, body: mockRes.body };
454
+ fetchDuration = 0;
455
+ usedMock = true;
456
+ }
457
+ }
458
+ // --- Phase 1: onRequestStart / onBeforeProxy ---
459
+ if (!realResponse) {
460
+ for (const hookName of ['onRequestStart', 'onBeforeProxy']) {
461
+ const orderedPlugins = selectTestPluginsForHook(allPlugins, hookName, pluginId, integrated && usePipelineFlow);
462
+ if (orderedPlugins.length === 0)
463
+ continue;
464
+ const hookStartTarget = currentTarget;
465
+ const hookCtx = {
466
+ log: testLogger,
467
+ request: requestMutable,
468
+ target: currentTarget,
469
+ meta: requestMeta,
470
+ shortCircuited,
471
+ shortCircuitResponse,
472
+ setTarget: (t) => { hookCtx.target = t; currentTarget = t; },
473
+ respond: (r) => {
474
+ hookCtx.shortCircuited = true;
475
+ hookCtx.shortCircuitResponse = r;
476
+ shortCircuited = true;
477
+ shortCircuitResponse = r;
478
+ },
479
+ };
480
+ for (const plugin of orderedPlugins) {
481
+ const hookFn = plugin[hookName];
482
+ if (typeof hookFn !== 'function')
483
+ continue;
484
+ const t0 = Date.now();
485
+ try {
486
+ await hookFn.call(plugin, hookCtx);
487
+ if (plugin.manifest.id === pluginId) {
488
+ hookResults[hookName] = {
489
+ status: 'success',
490
+ duration: Date.now() - t0,
491
+ targetChanged: currentTarget !== hookStartTarget ? currentTarget : null,
492
+ shortCircuited,
493
+ };
494
+ }
495
+ }
496
+ catch (e) {
497
+ if (plugin.manifest.id === pluginId) {
498
+ hookResults[hookName] = {
499
+ status: 'error',
500
+ duration: Date.now() - t0,
501
+ error: e.message,
502
+ stack: e.stack,
503
+ };
504
+ }
505
+ }
506
+ }
507
+ }
508
+ }
509
+ const modifiedRequestSnapshot = { headers: { ...requestMutable.headers }, body: requestMutable.body };
510
+ const requestHeadersChanged = JSON.stringify(initialRequestSnapshot.headers) !== JSON.stringify(modifiedRequestSnapshot.headers);
511
+ const requestBodyChanged = initialRequestSnapshot.body !== modifiedRequestSnapshot.body;
512
+ // --- Phase 1.5: onAfterRequest (请求处理阶段完成,即将发送) ---
513
+ if (!shortCircuited && hooks.includes('onAfterRequest')) {
514
+ const hookFn = targetPlugin.onAfterRequest;
515
+ if (typeof hookFn === 'function') {
516
+ const hookCtx = {
517
+ log: testLogger,
518
+ request: requestMutable,
519
+ target: currentTarget,
520
+ meta: { _test: true, _pluginRequestStartAt: Date.now() },
521
+ requestSentAt: Date.now(),
522
+ };
523
+ const t0 = Date.now();
524
+ try {
525
+ await hookFn.call(targetPlugin, hookCtx);
526
+ hookResults['onAfterRequest'] = { status: 'success', duration: Date.now() - t0 };
527
+ }
528
+ catch (e) {
529
+ hookResults['onAfterRequest'] = { status: 'error', duration: Date.now() - t0, error: e.message, stack: e.stack };
530
+ }
531
+ }
532
+ }
533
+ // --- Phase 2: 发起真实 HTTP 请求 ---
534
+ if (!shortCircuited) {
535
+ if (!realResponse) {
536
+ const http = require('http');
537
+ const https = require('https');
538
+ const parsed = new URL(currentTarget);
539
+ const transport = parsed.protocol === 'https:' ? https : http;
540
+ const fetchStart = Date.now();
541
+ try {
542
+ realResponse = await new Promise((resolve, reject) => {
543
+ const reqOpts = {
544
+ hostname: parsed.hostname,
545
+ port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
546
+ path: parsed.pathname + parsed.search,
547
+ method: requestMutable.method,
548
+ headers: requestMutable.headers,
549
+ timeout: 15000,
550
+ rejectUnauthorized: false,
551
+ };
552
+ const outReq = transport.request(reqOpts, (inRes) => {
553
+ const chunks = [];
554
+ inRes.on('data', (c) => chunks.push(c));
555
+ inRes.on('end', () => {
556
+ const bodyBuf = Buffer.concat(chunks);
557
+ const hdrs = {};
558
+ for (const [k, v] of Object.entries(inRes.headers)) {
559
+ if (v)
560
+ hdrs[k] = Array.isArray(v) ? v.join(', ') : v;
561
+ }
562
+ resolve({
563
+ statusCode: inRes.statusCode || 0,
564
+ headers: hdrs,
565
+ body: bodyBuf.toString('utf-8'),
566
+ });
567
+ });
568
+ });
569
+ outReq.on('error', reject);
570
+ outReq.on('timeout', () => { outReq.destroy(); reject(new Error('请求超时 (15s)')); });
571
+ if (requestMutable.body)
572
+ outReq.write(requestMutable.body);
573
+ outReq.end();
574
+ });
575
+ }
576
+ catch (e) {
577
+ fetchError = e.message;
578
+ }
579
+ fetchDuration = Date.now() - fetchStart;
580
+ }
581
+ }
582
+ // --- Phase 3: onBeforeResponse / onAfterResponse(用真实响应) ---
583
+ let modifiedResponse = null;
584
+ const originalBody = realResponse?.body || '';
585
+ if (realResponse && !shortCircuited) {
586
+ const responseCopy = {
587
+ statusCode: realResponse.statusCode,
588
+ headers: { ...realResponse.headers },
589
+ body: realResponse.body,
590
+ };
591
+ for (const hookName of ['onBeforeResponse', 'onAfterResponse']) {
592
+ if (!hooks.includes(hookName))
593
+ continue;
594
+ const hookFn = targetPlugin[hookName];
595
+ if (typeof hookFn !== 'function')
596
+ continue;
597
+ const hookCtx = {
598
+ log: testLogger,
599
+ request: requestMutable,
600
+ target: currentTarget,
601
+ meta: { _test: true, _pluginRequestStartAt: Date.now() },
602
+ response: responseCopy,
603
+ };
604
+ const t0 = Date.now();
605
+ try {
606
+ await hookFn.call(targetPlugin, hookCtx);
607
+ hookResults[hookName] = { status: 'success', duration: Date.now() - t0 };
608
+ }
609
+ catch (e) {
610
+ hookResults[hookName] = { status: 'error', duration: Date.now() - t0, error: e.message, stack: e.stack };
611
+ }
612
+ }
613
+ modifiedResponse = responseCopy;
614
+ }
615
+ // --- Phase 4: 构造返回结果 ---
616
+ const bodyChanged = modifiedResponse && (modifiedResponse.body !== originalBody);
617
+ const truncate = (s, max) => s.length > max ? s.slice(0, max) + `\n...(已截断,共 ${s.length} 字符)` : s;
618
+ const headersEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
619
+ const responseHeadersChanged = !!(realResponse && modifiedResponse && !headersEqual(realResponse.headers, modifiedResponse.headers));
620
+ const DIFF_PREVIEW_LEN = 2500;
621
+ // 写入代理日志,便于在「日志」页查看此次测试请求
622
+ if (typeof ctx.appendProxyRecordFromPluginTest === 'function' && !fetchError) {
623
+ const logData = {
624
+ method,
625
+ source,
626
+ target: usedMock ? `[MOCK] ${currentTarget}` : currentTarget,
627
+ time: new Date().toLocaleTimeString(),
628
+ statusCode: realResponse?.statusCode,
629
+ duration: fetchDuration,
630
+ _fromPluginTest: true,
631
+ };
632
+ const detail = realResponse
633
+ ? {
634
+ requestHeaders: requestMutable.headers,
635
+ requestBody: requestMutable.body || '',
636
+ responseHeaders: realResponse.headers,
637
+ responseBody: truncate(originalBody, 5000),
638
+ statusCode: realResponse.statusCode,
639
+ method,
640
+ url: source,
641
+ }
642
+ : undefined;
643
+ ctx.appendProxyRecordFromPluginTest(logData, detail);
644
+ }
645
+ res.json({
646
+ status: 'success',
647
+ results: {
648
+ pluginId,
649
+ pluginName: targetPlugin.manifest.name,
650
+ hooks,
651
+ logs: testLogs,
652
+ hookResults,
653
+ realRequest: {
654
+ method,
655
+ url: currentTarget,
656
+ fetchDuration,
657
+ fetchError,
658
+ usedMock,
659
+ targetResolved: integrated && legacyTarget !== source,
660
+ testMode: integrated ? 'integrated' : 'standalone',
661
+ },
662
+ originalRequest: (requestHeadersChanged || requestBodyChanged) ? {
663
+ headers: initialRequestSnapshot.headers,
664
+ body: initialRequestSnapshot.body,
665
+ } : null,
666
+ modifiedRequest: (requestHeadersChanged || requestBodyChanged) ? {
667
+ headers: modifiedRequestSnapshot.headers,
668
+ body: modifiedRequestSnapshot.body,
669
+ } : null,
670
+ requestHeadersChanged,
671
+ requestBodyChanged,
672
+ originalResponse: realResponse ? {
673
+ statusCode: realResponse.statusCode,
674
+ headers: realResponse.headers,
675
+ bodyPreview: truncate(originalBody, 3000),
676
+ bodyLength: originalBody.length,
677
+ bodyForDiff: truncate(originalBody, DIFF_PREVIEW_LEN),
678
+ } : null,
679
+ modifiedResponse: modifiedResponse ? (() => {
680
+ const h = modifiedResponse.headers;
681
+ const headersNormalized = h ? Object.fromEntries(Object.entries(h).map(([k, v]) => [k, v != null ? String(v) : ''])) : {};
682
+ return {
683
+ statusCode: modifiedResponse.statusCode,
684
+ headers: headersNormalized,
685
+ bodyPreview: truncate(String(modifiedResponse.body || ''), 3000),
686
+ bodyLength: String(modifiedResponse.body || '').length,
687
+ bodyChanged,
688
+ bodyForDiff: truncate(String(modifiedResponse.body || ''), DIFF_PREVIEW_LEN),
689
+ };
690
+ })() : null,
691
+ responseHeadersChanged,
692
+ shortCircuited,
693
+ shortCircuitResponse: shortCircuitResponse ? {
694
+ statusCode: shortCircuitResponse.statusCode,
695
+ body: truncate(String(shortCircuitResponse.body || ''), 2000),
696
+ } : null,
697
+ },
698
+ });
699
+ }
700
+ catch (error) {
701
+ res.status(500).json({ error: error.message });
702
+ }
703
+ });
704
+ // API: 启用/禁用单个插件
705
+ app.put('/api/plugins/:id/toggle', (req, res) => {
706
+ const pluginId = String(req.params.id);
707
+ const { enabled } = req.body;
708
+ try {
709
+ res.json(setPluginEnabled(ctx, pluginId, Boolean(enabled)));
710
+ }
711
+ catch (error) {
712
+ if (error.message === '插件不存在') {
713
+ res.status(404).json({ error: '插件不存在' });
714
+ return;
715
+ }
716
+ res.status(500).json({ error: error.message });
717
+ }
718
+ });
719
+ // API: 获取所有插件列表
720
+ app.get('/api/plugins', (_req, res) => {
721
+ res.setHeader('Content-Type', 'application/json');
722
+ const pluginStats = ctx.hookDispatcher.getPluginStats ? ctx.hookDispatcher.getPluginStats() : {};
723
+ const plugins = ctx.pluginManager.getAll().map((plugin) => ({
724
+ id: plugin.manifest.id,
725
+ name: plugin.manifest.name,
726
+ version: plugin.manifest.version,
727
+ hooks: plugin.manifest.hooks,
728
+ permissions: plugin.manifest.permissions,
729
+ priority: plugin.manifest.priority,
730
+ state: ctx.pluginManager.getState(plugin.manifest.id),
731
+ stats: pluginStats[plugin.manifest.id] || null,
732
+ }));
733
+ res.write(JSON.stringify({
734
+ mode: ctx.requestPipeline.mode,
735
+ total: plugins.length,
736
+ plugins,
737
+ }));
738
+ res.end();
739
+ });
740
+ // API: Logger 插件信息
741
+ app.get('/api/plugins/logger', (_req, res) => {
742
+ res.setHeader('Content-Type', 'application/json');
743
+ const pluginStats = ctx.hookDispatcher.getPluginStats ? ctx.hookDispatcher.getPluginStats() : {};
744
+ res.write(JSON.stringify({
745
+ pluginId: 'builtin.logger',
746
+ mode: ctx.requestPipeline.mode,
747
+ stats: pluginStats['builtin.logger'] || null,
748
+ summary: typeof ctx.builtinLoggerPlugin.getSummary === 'function'
749
+ ? ctx.builtinLoggerPlugin.getSummary()
750
+ : null,
751
+ recent: typeof ctx.builtinLoggerPlugin.getRecentEntries === 'function'
752
+ ? ctx.builtinLoggerPlugin.getRecentEntries()
753
+ : [],
754
+ }));
755
+ res.end();
756
+ });
757
+ // API: Mock 插件信息
758
+ app.get('/api/plugins/mock', (_req, res) => {
759
+ res.setHeader('Content-Type', 'application/json');
760
+ const pluginStats = ctx.hookDispatcher.getPluginStats ? ctx.hookDispatcher.getPluginStats() : {};
761
+ const ENABLE_BUILTIN_MOCK_PLUGIN = true; // This should come from REFACTOR_CONFIG
762
+ res.write(JSON.stringify({
763
+ pluginId: 'builtin.mock',
764
+ enabled: ENABLE_BUILTIN_MOCK_PLUGIN,
765
+ mode: ctx.requestPipeline.mode,
766
+ stats: pluginStats['builtin.mock'] || null,
767
+ takeoverRule: 'only inline mock in on mode and host-gated',
768
+ allowlist: [], // Should come from context
769
+ }));
770
+ res.end();
771
+ });
772
+ // API: 插件健康检查
773
+ app.get('/api/plugins/health', (_req, res) => {
774
+ res.setHeader('Content-Type', 'application/json');
775
+ const pluginStats = ctx.hookDispatcher.getPluginStats ? ctx.hookDispatcher.getPluginStats() : {};
776
+ const pluginStates = {};
777
+ const manifests = ctx.pluginManager.getAll().map((plugin) => {
778
+ pluginStates[plugin.manifest.id] = ctx.pluginManager.getState(plugin.manifest.id);
779
+ return plugin.manifest;
780
+ });
781
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
782
+ const { buildPluginHealth } = require('../core/plugin-health');
783
+ const health = buildPluginHealth({
784
+ plugins: manifests,
785
+ pluginStates,
786
+ pluginStats,
787
+ });
788
+ res.write(JSON.stringify({
789
+ mode: ctx.requestPipeline.mode,
790
+ ...health,
791
+ }));
792
+ res.end();
793
+ });
794
+ }
795
+ //# sourceMappingURL=plugins.js.map