@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,106 @@
1
+ /**
2
+ * meddle supervise - Run meddle under a lightweight restart supervisor.
3
+ */
4
+
5
+ const fs = require('fs')
6
+ const path = require('path')
7
+ const { spawn } = require('child_process')
8
+ const { resolveMeddleHome } = require('../lib/meddle-home')
9
+
10
+ const rawArgs = process.argv.slice(3)
11
+ const daemonFlag = rawArgs.includes('--daemon')
12
+ const restartCleanExit = rawArgs.includes('--restart-clean')
13
+ const maxRestarts = readNumberOption('--max-restarts', 0)
14
+ const restartDelayMs = readNumberOption('--restart-delay', 1000)
15
+
16
+ if (daemonFlag) {
17
+ startDaemon()
18
+ } else {
19
+ supervise()
20
+ }
21
+
22
+ function supervise() {
23
+ const indexPath = path.join(__dirname, '..', '..', 'index.js')
24
+ const proxyArgs = stripSupervisorArgs(rawArgs)
25
+ const childEnv = { ...process.env, DEBUG: process.env.DEBUG || '', MEDDLE_SUPERVISED: '1' }
26
+
27
+ let child = null
28
+ let stopping = false
29
+ let restarts = 0
30
+
31
+ const stop = (signal) => {
32
+ stopping = true
33
+ if (child && child.exitCode === null) child.kill(signal)
34
+ }
35
+
36
+ process.on('SIGINT', () => stop('SIGINT'))
37
+ process.on('SIGTERM', () => stop('SIGTERM'))
38
+
39
+ const start = () => {
40
+ child = spawn(process.execPath, [indexPath, ...proxyArgs], {
41
+ cwd: process.cwd(),
42
+ env: childEnv,
43
+ stdio: 'inherit',
44
+ })
45
+
46
+ child.on('error', (err) => {
47
+ console.error('[supervisor] failed to start proxy:', err.message)
48
+ process.exit(1)
49
+ })
50
+
51
+ child.on('exit', (code, signal) => {
52
+ if (stopping) process.exit(code || 0)
53
+ if (code === 0 && !restartCleanExit) process.exit(0)
54
+
55
+ restarts += 1
56
+ if (maxRestarts > 0 && restarts > maxRestarts) {
57
+ console.error(`[supervisor] restart limit reached (${maxRestarts}); last exit code=${code} signal=${signal || ''}`)
58
+ process.exit(code || 1)
59
+ }
60
+
61
+ console.error(`[supervisor] proxy exited code=${code} signal=${signal || ''}; restarting in ${restartDelayMs}ms`)
62
+ setTimeout(start, restartDelayMs)
63
+ })
64
+ }
65
+
66
+ start()
67
+ }
68
+
69
+ function startDaemon() {
70
+ const args = rawArgs.filter(arg => arg !== '--daemon')
71
+ const meddleDir = resolveMeddleHome()
72
+ fs.mkdirSync(meddleDir, { recursive: true })
73
+ const logFd = fs.openSync(path.join(meddleDir, 'supervisor.log'), 'a')
74
+ const binPath = path.join(__dirname, '..', 'index')
75
+ const child = spawn(process.execPath, [binPath, 'supervise', ...args], {
76
+ cwd: process.cwd(),
77
+ detached: true,
78
+ stdio: ['ignore', logFd, logFd],
79
+ env: process.env,
80
+ })
81
+ child.unref()
82
+ console.log(`Supervisor started: pid=${child.pid}, log=${path.join(meddleDir, 'supervisor.log')}`)
83
+ }
84
+
85
+ function stripSupervisorArgs(args) {
86
+ const result = []
87
+ for (let i = 0; i < args.length; i++) {
88
+ const arg = args[i]
89
+ if (arg === '--daemon' || arg === '--restart-clean') continue
90
+ if (arg === '--max-restarts' || arg === '--restart-delay') {
91
+ i += 1
92
+ continue
93
+ }
94
+ if (arg.startsWith('--max-restarts=') || arg.startsWith('--restart-delay=')) continue
95
+ result.push(arg)
96
+ }
97
+ return result
98
+ }
99
+
100
+ function readNumberOption(name, fallback) {
101
+ const inline = rawArgs.find(arg => arg.startsWith(name + '='))
102
+ const index = rawArgs.indexOf(name)
103
+ const value = inline ? inline.slice(name.length + 1) : (index >= 0 ? rawArgs[index + 1] : undefined)
104
+ const parsed = Number(value)
105
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback
106
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * meddle url - Get proxy URL
3
+ */
4
+
5
+ const { getProxyUrl, isProxyRunning } = require('../lib/proxy-detect')
6
+ const output = require('../lib/output')
7
+
8
+ // Check for --json flag
9
+ const args = process.argv.slice(2)
10
+ const jsonFlag = args.includes('--json')
11
+ output.setJsonMode(jsonFlag)
12
+
13
+ async function run() {
14
+ const url = getProxyUrl()
15
+ const running = await isProxyRunning()
16
+
17
+ if (output.isJsonMode()) {
18
+ output.jsonRaw({ url, running })
19
+ return
20
+ }
21
+
22
+ output.header('Proxy URL')
23
+ output.kv('URL', url)
24
+ output.kv('Status', running ? 'Running' : 'Not Running')
25
+ }
26
+
27
+ run().catch(e => {
28
+ output.error(e.message)
29
+ process.exit(1)
30
+ })
package/bin/doctor.js ADDED
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Meddle Doctor - 配置文件健康检查工具
5
+ */
6
+
7
+ const fs = require('fs')
8
+ const path = require('path')
9
+ const chalk = require('chalk')
10
+ const { resolveMeddleHome } = require('./lib/meddle-home')
11
+
12
+ const meddleDir = resolveMeddleHome()
13
+ const settingsPath = path.resolve(meddleDir, 'settings.json')
14
+ const routeRulesDir = path.resolve(meddleDir, 'route-rules')
15
+ const defaultMocksPath = path.resolve(meddleDir, 'mocks.json')
16
+ const certDir = path.resolve(meddleDir, 'ca')
17
+ const rootCACrt = path.resolve(certDir, 'rootCA.crt')
18
+ const rootCAKey = path.resolve(certDir, 'rootCA.key')
19
+
20
+ let hasErrors = false
21
+ let hasWarnings = false
22
+
23
+ function printHeader() {
24
+ console.log('')
25
+ console.log(chalk.bold.cyan('════════════════════════════════════════'))
26
+ console.log(chalk.bold.cyan(' Meddle 配置文件健康检查'))
27
+ console.log(chalk.bold.cyan('════════════════════════════════════════'))
28
+ console.log('')
29
+ }
30
+
31
+ function printSection(title) {
32
+ console.log(chalk.bold.yellow(`\n▶ ${title}`))
33
+ console.log(chalk.gray('─'.repeat(40)))
34
+ }
35
+
36
+ function printSuccess(message) {
37
+ console.log(chalk.green(' ✓'), message)
38
+ }
39
+
40
+ function printWarning(message) {
41
+ console.log(chalk.yellow(' ⚠'), message)
42
+ hasWarnings = true
43
+ }
44
+
45
+ function printError(message) {
46
+ console.log(chalk.red(' ✗'), message)
47
+ hasErrors = true
48
+ }
49
+
50
+ function printInfo(message) {
51
+ console.log(chalk.gray(' →'), message)
52
+ }
53
+
54
+ /**
55
+ * 检查目录是否存在
56
+ */
57
+ function checkDirectory() {
58
+ printSection('1. 配置目录检查')
59
+
60
+ if (fs.existsSync(meddleDir)) {
61
+ printSuccess(`配置目录存在: ${meddleDir}`)
62
+ const stats = fs.statSync(meddleDir)
63
+ printInfo(`创建时间: ${stats.birthtime.toLocaleString()}`)
64
+ } else {
65
+ printError(`配置目录不存在: ${meddleDir}`)
66
+ printInfo('运行 meddle 命令将自动创建')
67
+ }
68
+
69
+ if (fs.existsSync(certDir)) {
70
+ printSuccess(`证书目录存在: ${certDir}`)
71
+ } else {
72
+ printWarning('证书目录不存在,HTTPS 代理将无法使用')
73
+ printInfo('首次启动时会自动创建')
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 检查系统设置文件
79
+ */
80
+ function checkSettings() {
81
+ printSection('2. 系统设置检查')
82
+
83
+ if (!fs.existsSync(settingsPath)) {
84
+ printWarning('系统设置文件不存在')
85
+ printInfo('首次打开设置面板时会自动创建')
86
+ return null
87
+ }
88
+
89
+ try {
90
+ const content = fs.readFileSync(settingsPath, 'utf8')
91
+ const settings = JSON.parse(content)
92
+
93
+ printSuccess(`系统设置文件: ${settingsPath}`)
94
+ printInfo(`文件大小: ${content.length} bytes`)
95
+
96
+ // 检查必要字段
97
+ if (settings.theme) {
98
+ printSuccess(`主题设置: ${settings.theme}`)
99
+ } else {
100
+ printWarning('未设置主题')
101
+ }
102
+
103
+ if (settings.fontSize) {
104
+ printSuccess(`字体大小: ${settings.fontSize}`)
105
+ }
106
+
107
+ if (settings.aiConfig) {
108
+ const ai = settings.aiConfig
109
+ if (ai.enabled) {
110
+ printSuccess(`AI 功能: 已启用 (${ai.provider})`)
111
+ printInfo(`模型: ${ai.model}`)
112
+ if (!ai.apiKey) {
113
+ printWarning('AI 已启用但未配置 API Key')
114
+ }
115
+ } else {
116
+ printInfo('AI 功能: 未启用')
117
+ }
118
+
119
+ if (ai.models && ai.models.length > 0) {
120
+ printSuccess(`多模型配置: ${ai.models.length} 个模型`)
121
+ }
122
+ }
123
+
124
+ return settings
125
+
126
+ } catch (error) {
127
+ printError(`系统设置文件格式错误: ${error.message}`)
128
+ return null
129
+ }
130
+ }
131
+
132
+ /**
133
+ * 检查路由规则目录
134
+ */
135
+ function checkRulesFile(settings) {
136
+ printSection('3. 路由规则文件检查')
137
+
138
+ printInfo(`规则目录: ${routeRulesDir}`)
139
+
140
+ if (!fs.existsSync(routeRulesDir)) {
141
+ printWarning('路由规则目录不存在')
142
+ printInfo('首次启动时会自动创建,并生成默认规则文件')
143
+ return
144
+ }
145
+
146
+ const txtFiles = fs.readdirSync(routeRulesDir).filter(f => f.endsWith('.txt'))
147
+ printSuccess(`规则目录存在,包含 ${txtFiles.length} 个规则文件`)
148
+
149
+ // 检查 settings 中的 activeRuleFiles
150
+ const activeNames = (settings && Array.isArray(settings.activeRuleFiles)) ? settings.activeRuleFiles : []
151
+ printInfo(`已启用: ${activeNames.length} 个文件`)
152
+
153
+ let totalRules = 0
154
+ txtFiles.forEach(file => {
155
+ const filePath = path.join(routeRulesDir, file)
156
+ const name = file.replace(/\.txt$/, '')
157
+ const isActive = activeNames.includes(name)
158
+
159
+ try {
160
+ const content = fs.readFileSync(filePath, 'utf8')
161
+ const lines = content.split('\n').filter(line => {
162
+ const trimmed = line.trim()
163
+ return trimmed && !trimmed.startsWith('#') && !trimmed.startsWith('//')
164
+ })
165
+ const validRules = lines.filter(line => line.trim().split(/\s+/).length >= 2).length
166
+ totalRules += validRules
167
+ printSuccess(` ${isActive ? '●' : '○'} ${name} (${validRules} 条规则)`)
168
+ } catch (error) {
169
+ printError(` 读取 ${file} 失败: ${error.message}`)
170
+ }
171
+ })
172
+
173
+ if (totalRules > 0) {
174
+ printSuccess(`有效规则总数: ${totalRules} 条`)
175
+ }
176
+ }
177
+
178
+ /**
179
+ * 检查 Mock 规则文件
180
+ */
181
+ function checkMocksFile(settings) {
182
+ printSection('4. Mock 规则文件检查')
183
+
184
+ let mocksPath = defaultMocksPath
185
+
186
+ // 检查自定义路径
187
+ if (settings && settings.mocksFilePath) {
188
+ mocksPath = settings.mocksFilePath
189
+ printInfo(`使用自定义路径: ${mocksPath}`)
190
+ } else {
191
+ printInfo(`使用默认路径: ${mocksPath}`)
192
+ }
193
+
194
+ if (!fs.existsSync(mocksPath)) {
195
+ printWarning('Mock 规则文件不存在')
196
+ printInfo('可以通过 Web 界面创建 Mock 规则')
197
+ return
198
+ }
199
+
200
+ try {
201
+ const content = fs.readFileSync(mocksPath, 'utf8')
202
+ const data = JSON.parse(content)
203
+
204
+ printSuccess(`Mock 规则文件: ${mocksPath}`)
205
+ printInfo(`文件大小: ${content.length} bytes`)
206
+
207
+ if (!data.rules || !Array.isArray(data.rules)) {
208
+ printError('Mock 文件格式错误:缺少 rules 数组')
209
+ return
210
+ }
211
+
212
+ printSuccess(`Mock 规则数量: ${data.rules.length} 条`)
213
+
214
+ // 检查每条规则
215
+ let enabledCount = 0
216
+ data.rules.forEach((rule, index) => {
217
+ if (rule.enabled) {
218
+ enabledCount++
219
+ }
220
+
221
+ // 检查必要字段
222
+ if (!rule.urlPattern) {
223
+ printWarning(`规则 #${rule.id || index}: 缺少 urlPattern`)
224
+ }
225
+ if (rule.bodyType === 'file' && rule.body && !fs.existsSync(rule.body)) {
226
+ printWarning(`规则 #${rule.id || index}: 文件不存在 ${rule.body}`)
227
+ }
228
+ })
229
+
230
+ printSuccess(`已启用规则: ${enabledCount} 条`)
231
+
232
+ } catch (error) {
233
+ printError(`Mock 规则文件格式错误: ${error.message}`)
234
+ }
235
+ }
236
+
237
+ /**
238
+ * 检查证书文件
239
+ */
240
+ function checkCertificates() {
241
+ printSection('5. SSL 证书检查')
242
+
243
+ if (!fs.existsSync(certDir)) {
244
+ printWarning('证书目录不存在')
245
+ printInfo('首次启动时会自动创建')
246
+ return
247
+ }
248
+
249
+ printSuccess(`证书目录: ${certDir}`)
250
+
251
+ if (fs.existsSync(rootCACrt)) {
252
+ printSuccess('根证书文件存在: rootCA.crt')
253
+ const stats = fs.statSync(rootCACrt)
254
+ printInfo(`文件大小: ${stats.size} bytes`)
255
+ } else {
256
+ printWarning('根证书文件不存在')
257
+ printInfo('首次启动时会自动生成')
258
+ }
259
+
260
+ if (fs.existsSync(rootCAKey)) {
261
+ printSuccess('根证书私钥存在: rootCA.key')
262
+ } else {
263
+ printWarning('根证书私钥不存在')
264
+ }
265
+
266
+ // 检查其他证书文件
267
+ try {
268
+ const files = fs.readdirSync(certDir)
269
+ const certFiles = files.filter(f => f.endsWith('.crt') && f !== 'rootCA.crt')
270
+ if (certFiles.length > 0) {
271
+ printSuccess(`域名证书: ${certFiles.length} 个`)
272
+ certFiles.slice(0, 5).forEach(file => {
273
+ printInfo(` - ${file}`)
274
+ })
275
+ if (certFiles.length > 5) {
276
+ printInfo(` ... 还有 ${certFiles.length - 5} 个`)
277
+ }
278
+ }
279
+ } catch (error) {
280
+ // ignore
281
+ }
282
+ }
283
+
284
+ /**
285
+ * 检查文件权限
286
+ */
287
+ function checkPermissions() {
288
+ printSection('6. 文件权限检查')
289
+
290
+ const checkPaths = [
291
+ { path: meddleDir, name: '配置目录' },
292
+ { path: settingsPath, name: '系统设置文件' },
293
+ { path: routeRulesDir, name: '路由规则目录' },
294
+ { path: defaultMocksPath, name: 'Mock 规则文件' },
295
+ ]
296
+
297
+ checkPaths.forEach(({ path: filePath, name }) => {
298
+ if (fs.existsSync(filePath)) {
299
+ try {
300
+ fs.accessSync(filePath, fs.constants.R_OK | fs.constants.W_OK)
301
+ printSuccess(`${name}: 可读写`)
302
+ } catch (error) {
303
+ printError(`${name}: 权限不足`)
304
+ }
305
+ }
306
+ })
307
+ }
308
+
309
+ /**
310
+ * 生成诊断报告
311
+ */
312
+ function generateReport() {
313
+ printSection('诊断报告')
314
+
315
+ console.log('')
316
+
317
+ if (!hasErrors && !hasWarnings) {
318
+ console.log(chalk.green.bold(' ✓ 所有检查通过!配置正常。'))
319
+ } else {
320
+ if (hasErrors) {
321
+ console.log(chalk.red.bold(` ✗ 发现 ${hasErrors ? '错误' : '问题'}`))
322
+ console.log(chalk.gray(' 请根据上述提示修复错误'))
323
+ }
324
+ if (hasWarnings) {
325
+ console.log(chalk.yellow.bold(' ⚠ 发现警告'))
326
+ console.log(chalk.gray(' 建议检查上述警告项'))
327
+ }
328
+ }
329
+
330
+ console.log('')
331
+ console.log(chalk.gray('提示:'))
332
+ console.log(chalk.gray(' - 运行 meddle 启动代理服务器'))
333
+ console.log(chalk.gray(' - 访问 http://localhost:8899 打开管理界面'))
334
+ console.log(chalk.gray(' - 查看 CONFIG_STRUCTURE.md 了解配置文件详情'))
335
+ console.log('')
336
+ }
337
+
338
+ /**
339
+ * 主函数
340
+ */
341
+ function main() {
342
+ printHeader()
343
+
344
+ checkDirectory()
345
+ const settings = checkSettings()
346
+ checkRulesFile(settings)
347
+ checkMocksFile(settings)
348
+ checkCertificates()
349
+ checkPermissions()
350
+
351
+ generateReport()
352
+
353
+ process.exit(hasErrors ? 1 : 0)
354
+ }
355
+
356
+ main()
package/bin/index ADDED
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Strip --session <id> / --session=<id> from argv so command routing
4
+ // and all downstream `process.argv.slice(N)` calls see a clean argv.
5
+ // The session id is stashed in MEDDLE_SESSION_ID for session-args.js to
6
+ // pick up when applying the session context.
7
+ (function stripSessionFlag() {
8
+ const argv = process.argv
9
+ for (let i = 2; i < argv.length; i++) {
10
+ if (argv[i] === '--session' && i + 1 < argv.length) {
11
+ process.env.MEDDLE_SESSION_ID = argv[i + 1]
12
+ argv.splice(i, 2)
13
+ return
14
+ }
15
+ if (argv[i].startsWith('--session=')) {
16
+ process.env.MEDDLE_SESSION_ID = argv[i].slice('--session='.length)
17
+ argv.splice(i, 1)
18
+ return
19
+ }
20
+ }
21
+ })()
22
+
23
+ const args = process.argv.slice(2)
24
+ const command = args[0]
25
+ const subcommand = args[1]
26
+
27
+ // Command routing map
28
+ const commands = {
29
+ 'doctor': './doctor.js',
30
+ 'start': './commands/start.js',
31
+ 'supervise': './commands/supervise.js',
32
+ 'url': './commands/url.js',
33
+ 'status': './commands/status.js',
34
+ 'session': './commands/session/index.js',
35
+ 'mock': './commands/mock/index.js',
36
+ 'route': './commands/route/index.js'
37
+ }
38
+
39
+ // Check for --help flag
40
+ if (command === '--help' || command === '-h' || command === 'help') {
41
+ showHelp()
42
+ process.exit(0)
43
+ }
44
+
45
+ // Handle nested commands (mock/route/session)
46
+ if (command === 'mock' || command === 'route' || command === 'session') {
47
+ require(commands[command])
48
+ } else if (commands[command]) {
49
+ require(commands[command])
50
+ } else if (!command || command.startsWith('--')) {
51
+ // No command or only flags - start proxy (default behavior)
52
+ require('../index.js')
53
+ } else {
54
+ console.log(`Unknown command: ${command}`)
55
+ showHelp()
56
+ process.exit(1)
57
+ }
58
+
59
+ function showHelp() {
60
+ console.log(`
61
+ Meddle - 开发代理工具
62
+
63
+ 用法:
64
+ meddle 启动代理服务器 (默认)
65
+ meddle start [options] 启动代理服务器
66
+ meddle supervise [options] 以前台守护模式启动并自动重启
67
+ meddle --remote 启动局域网手机代理并解密 HTTPS
68
+ meddle doctor 检查配置文件健康状况
69
+ meddle url 获取代理 URL
70
+ meddle status 查看代理状态
71
+
72
+ Session 命令 (多实例隔离,预览功能):
73
+ meddle session create [--name <label>] [--port <port>]
74
+ 创建一个新的代理 session(独立 MEDDLE_HOME + 端口)
75
+ meddle session list 列出所有 session(含存活检测)
76
+ meddle session delete <id> [--clean]
77
+ 终止 session 并从注册表移除(--clean 同时删除数据目录)
78
+ meddle session prune 清理所有孤儿 session 记录
79
+ meddle --session <id> <command> 对指定 session 执行命令(如 route list)
80
+
81
+ Mock 命令:
82
+ meddle mock list [--json] 列出所有 mock 规则
83
+ meddle mock add [options] 添加 mock 规则
84
+ meddle mock update <id> [opts] 更新 mock 规则
85
+ meddle mock delete <id> 删除 mock 规则
86
+ meddle mock enable <id> 启用 mock 规则
87
+ meddle mock disable <id> 禁用 mock 规则
88
+
89
+ Route 命令:
90
+ meddle route list [--json] 列出所有路由文件
91
+ meddle route show <file> [--json] 查看路由文件规则
92
+ meddle route preview <url> [--file <name>] [--json] 预览 URL 的转发目标
93
+ meddle route active 查看当前激活的路由文件
94
+ meddle route active set <file> 设置激活的路由文件
95
+ meddle route create <name> 创建路由文件
96
+ meddle route add <file> <pattern> <target> 添加路由规则
97
+ meddle route update <file> <pattern> <target> 更新路由规则
98
+ meddle route delete <file> <pattern> 删除路由规则
99
+
100
+ 全局选项:
101
+ --help, -h 显示帮助信息
102
+ --session <id> 指定目标 session(与 MEDDLE_HOME 互斥)
103
+ --json JSON 格式输出 (用于 list/show/preview 命令)
104
+ --open 启动后自动打开浏览器
105
+ --remote 允许局域网设备连接代理
106
+ --remote-token <token> 为远程代理启用 Basic 认证
107
+ --intercept-https 解密所有 HTTPS 流量
108
+ --no-intercept-https 远程模式下不解密 HTTPS
109
+ --daemon supervise 后台运行,日志写入 ~/.meddle/supervisor.log
110
+ --max-restarts <n> supervise 最大重启次数,0 表示不限
111
+ --restart-delay <ms> supervise 重启延迟,默认 1000ms
112
+
113
+ 示例:
114
+ meddle # 启动代理服务器
115
+ meddle --open # 启动并打开浏览器
116
+ meddle --remote # 启动手机抓包代理
117
+ meddle --remote --remote-token "change-me"
118
+ meddle supervise --remote # 守护模式启动远程代理
119
+ meddle doctor # 检查配置文件
120
+ meddle mock list --json # JSON 格式列出 mock 规则
121
+ meddle mock add --name "API" --pattern "api.test.com" --status 200
122
+ meddle route list # 列出路由文件
123
+ meddle route preview "https://api.example.com/v1/users" # 预览转发目标
124
+ meddle route preview "https://cdn.com/assets/js/app.js" --file dev-rules --json
125
+ meddle route add dev-rules "api.test.com" "localhost:3000"
126
+ meddle route active set beta-rules
127
+
128
+ 更多信息请访问: https://github.com/JonathanLee-LX/meddle
129
+ `)
130
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * HTTP API client for proxy operations
3
+ */
4
+
5
+ const { getProxyUrl } = require('./proxy-detect')
6
+
7
+ const DEFAULT_TIMEOUT = 2000
8
+
9
+ /**
10
+ * Make API request to proxy server
11
+ */
12
+ async function apiRequest(method, pathname, body, timeoutMs = DEFAULT_TIMEOUT) {
13
+ const base = getProxyUrl()
14
+ const url = base.replace(/\/$/, '') + pathname
15
+ const opts = {
16
+ method,
17
+ headers: { 'Content-Type': 'application/json' },
18
+ signal: AbortSignal.timeout(timeoutMs)
19
+ }
20
+ if (body !== undefined) {
21
+ opts.body = typeof body === 'string' ? body : JSON.stringify(body)
22
+ }
23
+
24
+ const response = await fetch(url, opts)
25
+
26
+ if (!response.ok) {
27
+ const text = await response.text()
28
+ throw new Error(text || response.statusText)
29
+ }
30
+
31
+ const contentType = response.headers.get('content-type')
32
+ if (contentType && contentType.includes('application/json')) {
33
+ return response.json()
34
+ }
35
+ return response.text()
36
+ }
37
+
38
+ /**
39
+ * GET request
40
+ */
41
+ async function apiGet(pathname, timeoutMs = DEFAULT_TIMEOUT) {
42
+ return apiRequest('GET', pathname, undefined, timeoutMs)
43
+ }
44
+
45
+ /**
46
+ * POST request
47
+ */
48
+ async function apiPost(pathname, body, timeoutMs = DEFAULT_TIMEOUT) {
49
+ return apiRequest('POST', pathname, body, timeoutMs)
50
+ }
51
+
52
+ /**
53
+ * PUT request
54
+ */
55
+ async function apiPut(pathname, body, timeoutMs = DEFAULT_TIMEOUT) {
56
+ return apiRequest('PUT', pathname, body, timeoutMs)
57
+ }
58
+
59
+ /**
60
+ * DELETE request
61
+ */
62
+ async function apiDelete(pathname, timeoutMs = DEFAULT_TIMEOUT) {
63
+ return apiRequest('DELETE', pathname, undefined, timeoutMs)
64
+ }
65
+
66
+ module.exports = {
67
+ apiRequest,
68
+ apiGet,
69
+ apiPost,
70
+ apiPut,
71
+ apiDelete
72
+ }