imposters 0.1.0

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 (426) hide show
  1. package/LICENSE +21 -0
  2. package/Program/package.json +6 -0
  3. package/README.md +365 -0
  4. package/api/AdminApi/package.json +6 -0
  5. package/api/ApiErrors/package.json +6 -0
  6. package/api/ApiSchemas/package.json +6 -0
  7. package/api/Conversions/package.json +6 -0
  8. package/api/ImpostersGroup/package.json +6 -0
  9. package/api/ImpostersHandlers/package.json +6 -0
  10. package/api/SystemGroup/package.json +6 -0
  11. package/api/SystemHandlers/package.json +6 -0
  12. package/bin/imposters +47 -0
  13. package/cli/Commands/package.json +6 -0
  14. package/cli/ConfigLoader/package.json +6 -0
  15. package/client/HandlerHttpClient/package.json +6 -0
  16. package/client/ImpostersClient/package.json +6 -0
  17. package/client/testing/package.json +6 -0
  18. package/dist/cjs/Program.js +4 -0
  19. package/dist/cjs/Program.js.map +1 -0
  20. package/dist/cjs/api/AdminApi.js +11 -0
  21. package/dist/cjs/api/AdminApi.js.map +1 -0
  22. package/dist/cjs/api/ApiErrors.js +30 -0
  23. package/dist/cjs/api/ApiErrors.js.map +1 -0
  24. package/dist/cjs/api/ApiSchemas.js +36 -0
  25. package/dist/cjs/api/ApiSchemas.js.map +1 -0
  26. package/dist/cjs/api/Conversions.js +41 -0
  27. package/dist/cjs/api/Conversions.js.map +1 -0
  28. package/dist/cjs/api/ImpostersGroup.js +37 -0
  29. package/dist/cjs/api/ImpostersGroup.js.map +1 -0
  30. package/dist/cjs/api/ImpostersHandlers.js +361 -0
  31. package/dist/cjs/api/ImpostersHandlers.js.map +1 -0
  32. package/dist/cjs/api/SystemGroup.js +12 -0
  33. package/dist/cjs/api/SystemGroup.js.map +1 -0
  34. package/dist/cjs/api/SystemHandlers.js +74 -0
  35. package/dist/cjs/api/SystemHandlers.js.map +1 -0
  36. package/dist/cjs/cli/Commands.js +104 -0
  37. package/dist/cjs/cli/Commands.js.map +1 -0
  38. package/dist/cjs/cli/ConfigLoader.js +34 -0
  39. package/dist/cjs/cli/ConfigLoader.js.map +1 -0
  40. package/dist/cjs/client/HandlerHttpClient.js +50 -0
  41. package/dist/cjs/client/HandlerHttpClient.js.map +1 -0
  42. package/dist/cjs/client/ImpostersClient.js +20 -0
  43. package/dist/cjs/client/ImpostersClient.js.map +1 -0
  44. package/dist/cjs/client/index.js +57 -0
  45. package/dist/cjs/client/index.js.map +1 -0
  46. package/dist/cjs/client/testing.js +94 -0
  47. package/dist/cjs/client/testing.js.map +1 -0
  48. package/dist/cjs/domain/imposter.js +125 -0
  49. package/dist/cjs/domain/imposter.js.map +1 -0
  50. package/dist/cjs/domain/route.js +185 -0
  51. package/dist/cjs/domain/route.js.map +1 -0
  52. package/dist/cjs/index.js +106 -0
  53. package/dist/cjs/index.js.map +1 -0
  54. package/dist/cjs/layers/ApiLayer.js +18 -0
  55. package/dist/cjs/layers/ApiLayer.js.map +1 -0
  56. package/dist/cjs/layers/MainLayer.js +27 -0
  57. package/dist/cjs/layers/MainLayer.js.map +1 -0
  58. package/dist/cjs/matching/ExpressionEvaluator.js +103 -0
  59. package/dist/cjs/matching/ExpressionEvaluator.js.map +1 -0
  60. package/dist/cjs/matching/RequestMatcher.js +145 -0
  61. package/dist/cjs/matching/RequestMatcher.js.map +1 -0
  62. package/dist/cjs/matching/ResponseGenerator.js +80 -0
  63. package/dist/cjs/matching/ResponseGenerator.js.map +1 -0
  64. package/dist/cjs/matching/TemplateEngine.js +55 -0
  65. package/dist/cjs/matching/TemplateEngine.js.map +1 -0
  66. package/dist/cjs/repositories/ImposterRepository.js +118 -0
  67. package/dist/cjs/repositories/ImposterRepository.js.map +1 -0
  68. package/dist/cjs/schemas/ConfigFileSchema.js +44 -0
  69. package/dist/cjs/schemas/ConfigFileSchema.js.map +1 -0
  70. package/dist/cjs/schemas/ImposterSchema.js +202 -0
  71. package/dist/cjs/schemas/ImposterSchema.js.map +1 -0
  72. package/dist/cjs/schemas/RequestLogSchema.js +51 -0
  73. package/dist/cjs/schemas/RequestLogSchema.js.map +1 -0
  74. package/dist/cjs/schemas/StubSchema.js +84 -0
  75. package/dist/cjs/schemas/StubSchema.js.map +1 -0
  76. package/dist/cjs/schemas/common.js +67 -0
  77. package/dist/cjs/schemas/common.js.map +1 -0
  78. package/dist/cjs/server/AdminServer.js +36 -0
  79. package/dist/cjs/server/AdminServer.js.map +1 -0
  80. package/dist/cjs/server/BunServer.js +13 -0
  81. package/dist/cjs/server/BunServer.js.map +1 -0
  82. package/dist/cjs/server/FiberManager.js +21 -0
  83. package/dist/cjs/server/FiberManager.js.map +1 -0
  84. package/dist/cjs/server/ImposterServer.js +234 -0
  85. package/dist/cjs/server/ImposterServer.js.map +1 -0
  86. package/dist/cjs/services/AppConfig.js +18 -0
  87. package/dist/cjs/services/AppConfig.js.map +1 -0
  88. package/dist/cjs/services/MetricsService.js +113 -0
  89. package/dist/cjs/services/MetricsService.js.map +1 -0
  90. package/dist/cjs/services/PortAllocator.js +50 -0
  91. package/dist/cjs/services/PortAllocator.js.map +1 -0
  92. package/dist/cjs/services/ProxyService.js +109 -0
  93. package/dist/cjs/services/ProxyService.js.map +1 -0
  94. package/dist/cjs/services/RequestLogger.js +60 -0
  95. package/dist/cjs/services/RequestLogger.js.map +1 -0
  96. package/dist/cjs/services/Uuid.js +10 -0
  97. package/dist/cjs/services/Uuid.js.map +1 -0
  98. package/dist/cjs/services/UuidLive.js +16 -0
  99. package/dist/cjs/services/UuidLive.js.map +1 -0
  100. package/dist/cjs/ui/UiRouter.js +242 -0
  101. package/dist/cjs/ui/UiRouter.js.map +1 -0
  102. package/dist/cjs/ui/admin/AdminLayout.js +36 -0
  103. package/dist/cjs/ui/admin/AdminLayout.js.map +1 -0
  104. package/dist/cjs/ui/admin/AdminUiRouter.js +155 -0
  105. package/dist/cjs/ui/admin/AdminUiRouter.js.map +1 -0
  106. package/dist/cjs/ui/admin/pages/AdminDashboard.js +55 -0
  107. package/dist/cjs/ui/admin/pages/AdminDashboard.js.map +1 -0
  108. package/dist/cjs/ui/admin/partials.js +64 -0
  109. package/dist/cjs/ui/admin/partials.js.map +1 -0
  110. package/dist/cjs/ui/html.js +42 -0
  111. package/dist/cjs/ui/html.js.map +1 -0
  112. package/dist/cjs/ui/layout.js +39 -0
  113. package/dist/cjs/ui/layout.js.map +1 -0
  114. package/dist/cjs/ui/pages/dashboard.js +51 -0
  115. package/dist/cjs/ui/pages/dashboard.js.map +1 -0
  116. package/dist/cjs/ui/pages/request-detail.js +119 -0
  117. package/dist/cjs/ui/pages/request-detail.js.map +1 -0
  118. package/dist/cjs/ui/pages/requests.js +120 -0
  119. package/dist/cjs/ui/pages/requests.js.map +1 -0
  120. package/dist/cjs/ui/pages/stubs.js +46 -0
  121. package/dist/cjs/ui/pages/stubs.js.map +1 -0
  122. package/dist/cjs/ui/partials.js +104 -0
  123. package/dist/cjs/ui/partials.js.map +1 -0
  124. package/dist/dts/Program.d.ts +2 -0
  125. package/dist/dts/Program.d.ts.map +1 -0
  126. package/dist/dts/api/AdminApi.d.ts +490 -0
  127. package/dist/dts/api/AdminApi.d.ts.map +1 -0
  128. package/dist/dts/api/ApiErrors.d.ts +26 -0
  129. package/dist/dts/api/ApiErrors.d.ts.map +1 -0
  130. package/dist/dts/api/ApiSchemas.d.ts +36 -0
  131. package/dist/dts/api/ApiSchemas.d.ts.map +1 -0
  132. package/dist/dts/api/Conversions.d.ts +7 -0
  133. package/dist/dts/api/Conversions.d.ts.map +1 -0
  134. package/dist/dts/api/ImpostersGroup.d.ts +448 -0
  135. package/dist/dts/api/ImpostersGroup.d.ts.map +1 -0
  136. package/dist/dts/api/ImpostersHandlers.d.ts +9 -0
  137. package/dist/dts/api/ImpostersHandlers.d.ts.map +1 -0
  138. package/dist/dts/api/SystemGroup.d.ts +46 -0
  139. package/dist/dts/api/SystemGroup.d.ts.map +1 -0
  140. package/dist/dts/api/SystemHandlers.d.ts +4 -0
  141. package/dist/dts/api/SystemHandlers.d.ts.map +1 -0
  142. package/dist/dts/cli/Commands.d.ts +4 -0
  143. package/dist/dts/cli/Commands.d.ts.map +1 -0
  144. package/dist/dts/cli/ConfigLoader.d.ts +13 -0
  145. package/dist/dts/cli/ConfigLoader.d.ts.map +1 -0
  146. package/dist/dts/client/HandlerHttpClient.d.ts +5 -0
  147. package/dist/dts/client/HandlerHttpClient.d.ts.map +1 -0
  148. package/dist/dts/client/ImpostersClient.d.ts +1868 -0
  149. package/dist/dts/client/ImpostersClient.d.ts.map +1 -0
  150. package/dist/dts/client/index.d.ts +6 -0
  151. package/dist/dts/client/index.d.ts.map +1 -0
  152. package/dist/dts/client/testing.d.ts +35 -0
  153. package/dist/dts/client/testing.d.ts.map +1 -0
  154. package/dist/dts/domain/imposter.d.ts +123 -0
  155. package/dist/dts/domain/imposter.d.ts.map +1 -0
  156. package/dist/dts/domain/route.d.ts +128 -0
  157. package/dist/dts/domain/route.d.ts.map +1 -0
  158. package/dist/dts/index.d.ts +60 -0
  159. package/dist/dts/index.d.ts.map +1 -0
  160. package/dist/dts/layers/ApiLayer.d.ts +3 -0
  161. package/dist/dts/layers/ApiLayer.d.ts.map +1 -0
  162. package/dist/dts/layers/MainLayer.d.ts +3 -0
  163. package/dist/dts/layers/MainLayer.d.ts.map +1 -0
  164. package/dist/dts/matching/ExpressionEvaluator.d.ts +11 -0
  165. package/dist/dts/matching/ExpressionEvaluator.d.ts.map +1 -0
  166. package/dist/dts/matching/RequestMatcher.d.ts +13 -0
  167. package/dist/dts/matching/RequestMatcher.d.ts.map +1 -0
  168. package/dist/dts/matching/ResponseGenerator.d.ts +9 -0
  169. package/dist/dts/matching/ResponseGenerator.d.ts.map +1 -0
  170. package/dist/dts/matching/TemplateEngine.d.ts +4 -0
  171. package/dist/dts/matching/TemplateEngine.d.ts.map +1 -0
  172. package/dist/dts/repositories/ImposterRepository.d.ts +33 -0
  173. package/dist/dts/repositories/ImposterRepository.d.ts.map +1 -0
  174. package/dist/dts/schemas/ConfigFileSchema.d.ts +142 -0
  175. package/dist/dts/schemas/ConfigFileSchema.d.ts.map +1 -0
  176. package/dist/dts/schemas/ImposterSchema.d.ts +368 -0
  177. package/dist/dts/schemas/ImposterSchema.d.ts.map +1 -0
  178. package/dist/dts/schemas/RequestLogSchema.d.ts +36 -0
  179. package/dist/dts/schemas/RequestLogSchema.d.ts.map +1 -0
  180. package/dist/dts/schemas/StubSchema.d.ts +112 -0
  181. package/dist/dts/schemas/StubSchema.d.ts.map +1 -0
  182. package/dist/dts/schemas/common.d.ts +56 -0
  183. package/dist/dts/schemas/common.d.ts.map +1 -0
  184. package/dist/dts/server/AdminServer.d.ts +11 -0
  185. package/dist/dts/server/AdminServer.d.ts.map +1 -0
  186. package/dist/dts/server/BunServer.d.ts +17 -0
  187. package/dist/dts/server/BunServer.d.ts.map +1 -0
  188. package/dist/dts/server/FiberManager.d.ts +12 -0
  189. package/dist/dts/server/FiberManager.d.ts.map +1 -0
  190. package/dist/dts/server/ImposterServer.d.ts +29 -0
  191. package/dist/dts/server/ImposterServer.d.ts.map +1 -0
  192. package/dist/dts/services/AppConfig.d.ts +14 -0
  193. package/dist/dts/services/AppConfig.d.ts.map +1 -0
  194. package/dist/dts/services/MetricsService.d.ts +26 -0
  195. package/dist/dts/services/MetricsService.d.ts.map +1 -0
  196. package/dist/dts/services/PortAllocator.d.ts +29 -0
  197. package/dist/dts/services/PortAllocator.d.ts.map +1 -0
  198. package/dist/dts/services/ProxyService.d.ts +24 -0
  199. package/dist/dts/services/ProxyService.d.ts.map +1 -0
  200. package/dist/dts/services/RequestLogger.d.ts +23 -0
  201. package/dist/dts/services/RequestLogger.d.ts.map +1 -0
  202. package/dist/dts/services/Uuid.d.ts +9 -0
  203. package/dist/dts/services/Uuid.d.ts.map +1 -0
  204. package/dist/dts/services/UuidLive.d.ts +4 -0
  205. package/dist/dts/services/UuidLive.d.ts.map +1 -0
  206. package/dist/dts/ui/UiRouter.d.ts +15 -0
  207. package/dist/dts/ui/UiRouter.d.ts.map +1 -0
  208. package/dist/dts/ui/admin/AdminLayout.d.ts +7 -0
  209. package/dist/dts/ui/admin/AdminLayout.d.ts.map +1 -0
  210. package/dist/dts/ui/admin/AdminUiRouter.d.ts +6 -0
  211. package/dist/dts/ui/admin/AdminUiRouter.d.ts.map +1 -0
  212. package/dist/dts/ui/admin/pages/AdminDashboard.d.ts +7 -0
  213. package/dist/dts/ui/admin/pages/AdminDashboard.d.ts.map +1 -0
  214. package/dist/dts/ui/admin/partials.d.ts +14 -0
  215. package/dist/dts/ui/admin/partials.d.ts.map +1 -0
  216. package/dist/dts/ui/html.d.ts +12 -0
  217. package/dist/dts/ui/html.d.ts.map +1 -0
  218. package/dist/dts/ui/layout.d.ts +9 -0
  219. package/dist/dts/ui/layout.d.ts.map +1 -0
  220. package/dist/dts/ui/pages/dashboard.d.ts +10 -0
  221. package/dist/dts/ui/pages/dashboard.d.ts.map +1 -0
  222. package/dist/dts/ui/pages/request-detail.d.ts +11 -0
  223. package/dist/dts/ui/pages/request-detail.d.ts.map +1 -0
  224. package/dist/dts/ui/pages/requests.d.ts +15 -0
  225. package/dist/dts/ui/pages/requests.d.ts.map +1 -0
  226. package/dist/dts/ui/pages/stubs.d.ts +8 -0
  227. package/dist/dts/ui/pages/stubs.d.ts.map +1 -0
  228. package/dist/dts/ui/partials.d.ts +13 -0
  229. package/dist/dts/ui/partials.d.ts.map +1 -0
  230. package/dist/esm/Program.js +2 -0
  231. package/dist/esm/Program.js.map +1 -0
  232. package/dist/esm/api/AdminApi.js +5 -0
  233. package/dist/esm/api/AdminApi.js.map +1 -0
  234. package/dist/esm/api/ApiErrors.js +20 -0
  235. package/dist/esm/api/ApiErrors.js.map +1 -0
  236. package/dist/esm/api/ApiSchemas.js +29 -0
  237. package/dist/esm/api/ApiSchemas.js.map +1 -0
  238. package/dist/esm/api/Conversions.js +32 -0
  239. package/dist/esm/api/Conversions.js.map +1 -0
  240. package/dist/esm/api/ImpostersGroup.js +30 -0
  241. package/dist/esm/api/ImpostersGroup.js.map +1 -0
  242. package/dist/esm/api/ImpostersHandlers.js +354 -0
  243. package/dist/esm/api/ImpostersHandlers.js.map +1 -0
  244. package/dist/esm/api/SystemGroup.js +6 -0
  245. package/dist/esm/api/SystemGroup.js.map +1 -0
  246. package/dist/esm/api/SystemHandlers.js +67 -0
  247. package/dist/esm/api/SystemHandlers.js.map +1 -0
  248. package/dist/esm/cli/Commands.js +98 -0
  249. package/dist/esm/cli/Commands.js.map +1 -0
  250. package/dist/esm/cli/ConfigLoader.js +25 -0
  251. package/dist/esm/cli/ConfigLoader.js.map +1 -0
  252. package/dist/esm/client/HandlerHttpClient.js +42 -0
  253. package/dist/esm/client/HandlerHttpClient.js.map +1 -0
  254. package/dist/esm/client/ImpostersClient.js +10 -0
  255. package/dist/esm/client/ImpostersClient.js.map +1 -0
  256. package/dist/esm/client/index.js +4 -0
  257. package/dist/esm/client/index.js.map +1 -0
  258. package/dist/esm/client/testing.js +86 -0
  259. package/dist/esm/client/testing.js.map +1 -0
  260. package/dist/esm/domain/imposter.js +103 -0
  261. package/dist/esm/domain/imposter.js.map +1 -0
  262. package/dist/esm/domain/route.js +164 -0
  263. package/dist/esm/domain/route.js.map +1 -0
  264. package/dist/esm/index.js +60 -0
  265. package/dist/esm/index.js.map +1 -0
  266. package/dist/esm/layers/ApiLayer.js +11 -0
  267. package/dist/esm/layers/ApiLayer.js.map +1 -0
  268. package/dist/esm/layers/MainLayer.js +20 -0
  269. package/dist/esm/layers/MainLayer.js.map +1 -0
  270. package/dist/esm/matching/ExpressionEvaluator.js +94 -0
  271. package/dist/esm/matching/ExpressionEvaluator.js.map +1 -0
  272. package/dist/esm/matching/RequestMatcher.js +135 -0
  273. package/dist/esm/matching/RequestMatcher.js.map +1 -0
  274. package/dist/esm/matching/ResponseGenerator.js +71 -0
  275. package/dist/esm/matching/ResponseGenerator.js.map +1 -0
  276. package/dist/esm/matching/TemplateEngine.js +47 -0
  277. package/dist/esm/matching/TemplateEngine.js.map +1 -0
  278. package/dist/esm/package.json +4 -0
  279. package/dist/esm/repositories/ImposterRepository.js +110 -0
  280. package/dist/esm/repositories/ImposterRepository.js.map +1 -0
  281. package/dist/esm/schemas/ConfigFileSchema.js +37 -0
  282. package/dist/esm/schemas/ConfigFileSchema.js.map +1 -0
  283. package/dist/esm/schemas/ImposterSchema.js +195 -0
  284. package/dist/esm/schemas/ImposterSchema.js.map +1 -0
  285. package/dist/esm/schemas/RequestLogSchema.js +44 -0
  286. package/dist/esm/schemas/RequestLogSchema.js.map +1 -0
  287. package/dist/esm/schemas/StubSchema.js +77 -0
  288. package/dist/esm/schemas/StubSchema.js.map +1 -0
  289. package/dist/esm/schemas/common.js +59 -0
  290. package/dist/esm/schemas/common.js.map +1 -0
  291. package/dist/esm/server/AdminServer.js +27 -0
  292. package/dist/esm/server/AdminServer.js.map +1 -0
  293. package/dist/esm/server/BunServer.js +6 -0
  294. package/dist/esm/server/BunServer.js.map +1 -0
  295. package/dist/esm/server/FiberManager.js +14 -0
  296. package/dist/esm/server/FiberManager.js.map +1 -0
  297. package/dist/esm/server/ImposterServer.js +225 -0
  298. package/dist/esm/server/ImposterServer.js.map +1 -0
  299. package/dist/esm/services/AppConfig.js +11 -0
  300. package/dist/esm/services/AppConfig.js.map +1 -0
  301. package/dist/esm/services/MetricsService.js +105 -0
  302. package/dist/esm/services/MetricsService.js.map +1 -0
  303. package/dist/esm/services/PortAllocator.js +41 -0
  304. package/dist/esm/services/PortAllocator.js.map +1 -0
  305. package/dist/esm/services/ProxyService.js +101 -0
  306. package/dist/esm/services/ProxyService.js.map +1 -0
  307. package/dist/esm/services/RequestLogger.js +53 -0
  308. package/dist/esm/services/RequestLogger.js.map +1 -0
  309. package/dist/esm/services/Uuid.js +3 -0
  310. package/dist/esm/services/Uuid.js.map +1 -0
  311. package/dist/esm/services/UuidLive.js +9 -0
  312. package/dist/esm/services/UuidLive.js.map +1 -0
  313. package/dist/esm/ui/UiRouter.js +235 -0
  314. package/dist/esm/ui/UiRouter.js.map +1 -0
  315. package/dist/esm/ui/admin/AdminLayout.js +29 -0
  316. package/dist/esm/ui/admin/AdminLayout.js.map +1 -0
  317. package/dist/esm/ui/admin/AdminUiRouter.js +148 -0
  318. package/dist/esm/ui/admin/AdminUiRouter.js.map +1 -0
  319. package/dist/esm/ui/admin/pages/AdminDashboard.js +48 -0
  320. package/dist/esm/ui/admin/pages/AdminDashboard.js.map +1 -0
  321. package/dist/esm/ui/admin/partials.js +54 -0
  322. package/dist/esm/ui/admin/partials.js.map +1 -0
  323. package/dist/esm/ui/html.js +32 -0
  324. package/dist/esm/ui/html.js.map +1 -0
  325. package/dist/esm/ui/layout.js +32 -0
  326. package/dist/esm/ui/layout.js.map +1 -0
  327. package/dist/esm/ui/pages/dashboard.js +44 -0
  328. package/dist/esm/ui/pages/dashboard.js.map +1 -0
  329. package/dist/esm/ui/pages/request-detail.js +112 -0
  330. package/dist/esm/ui/pages/request-detail.js.map +1 -0
  331. package/dist/esm/ui/pages/requests.js +112 -0
  332. package/dist/esm/ui/pages/requests.js.map +1 -0
  333. package/dist/esm/ui/pages/stubs.js +39 -0
  334. package/dist/esm/ui/pages/stubs.js.map +1 -0
  335. package/dist/esm/ui/partials.js +91 -0
  336. package/dist/esm/ui/partials.js.map +1 -0
  337. package/domain/imposter/package.json +6 -0
  338. package/domain/route/package.json +6 -0
  339. package/layers/ApiLayer/package.json +6 -0
  340. package/layers/MainLayer/package.json +6 -0
  341. package/matching/ExpressionEvaluator/package.json +6 -0
  342. package/matching/RequestMatcher/package.json +6 -0
  343. package/matching/ResponseGenerator/package.json +6 -0
  344. package/matching/TemplateEngine/package.json +6 -0
  345. package/package.json +435 -0
  346. package/repositories/ImposterRepository/package.json +6 -0
  347. package/schemas/ConfigFileSchema/package.json +6 -0
  348. package/schemas/ImposterSchema/package.json +6 -0
  349. package/schemas/RequestLogSchema/package.json +6 -0
  350. package/schemas/StubSchema/package.json +6 -0
  351. package/schemas/common/package.json +6 -0
  352. package/server/AdminServer/package.json +6 -0
  353. package/server/BunServer/package.json +6 -0
  354. package/server/FiberManager/package.json +6 -0
  355. package/server/ImposterServer/package.json +6 -0
  356. package/services/AppConfig/package.json +6 -0
  357. package/services/MetricsService/package.json +6 -0
  358. package/services/PortAllocator/package.json +6 -0
  359. package/services/ProxyService/package.json +6 -0
  360. package/services/RequestLogger/package.json +6 -0
  361. package/services/Uuid/package.json +6 -0
  362. package/services/UuidLive/package.json +6 -0
  363. package/src/Program.ts +1 -0
  364. package/src/api/AdminApi.ts +7 -0
  365. package/src/api/ApiErrors.ts +20 -0
  366. package/src/api/ApiSchemas.ts +36 -0
  367. package/src/api/Conversions.ts +34 -0
  368. package/src/api/ImpostersGroup.ts +103 -0
  369. package/src/api/ImpostersHandlers.ts +387 -0
  370. package/src/api/SystemGroup.ts +12 -0
  371. package/src/api/SystemHandlers.ts +76 -0
  372. package/src/cli/Commands.ts +119 -0
  373. package/src/cli/ConfigLoader.ts +41 -0
  374. package/src/client/HandlerHttpClient.ts +50 -0
  375. package/src/client/ImpostersClient.ts +21 -0
  376. package/src/client/index.ts +9 -0
  377. package/src/client/testing.ts +105 -0
  378. package/src/domain/imposter.ts +186 -0
  379. package/src/domain/route.ts +255 -0
  380. package/src/index.ts +153 -0
  381. package/src/layers/ApiLayer.ts +21 -0
  382. package/src/layers/MainLayer.ts +43 -0
  383. package/src/matching/ExpressionEvaluator.ts +102 -0
  384. package/src/matching/RequestMatcher.ts +162 -0
  385. package/src/matching/ResponseGenerator.ts +86 -0
  386. package/src/matching/TemplateEngine.ts +54 -0
  387. package/src/repositories/ImposterRepository.ts +145 -0
  388. package/src/schemas/ConfigFileSchema.ts +32 -0
  389. package/src/schemas/ImposterSchema.ts +232 -0
  390. package/src/schemas/RequestLogSchema.ts +38 -0
  391. package/src/schemas/StubSchema.ts +90 -0
  392. package/src/schemas/common.ts +95 -0
  393. package/src/server/AdminServer.ts +22 -0
  394. package/src/server/BunServer.ts +19 -0
  395. package/src/server/FiberManager.ts +25 -0
  396. package/src/server/ImposterServer.ts +244 -0
  397. package/src/services/AppConfig.ts +22 -0
  398. package/src/services/MetricsService.ts +157 -0
  399. package/src/services/PortAllocator.ts +68 -0
  400. package/src/services/ProxyService.ts +139 -0
  401. package/src/services/RequestLogger.ts +87 -0
  402. package/src/services/Uuid.ts +9 -0
  403. package/src/services/UuidLive.ts +9 -0
  404. package/src/types/bun.d.ts +6 -0
  405. package/src/ui/UiRouter.ts +278 -0
  406. package/src/ui/admin/AdminLayout.ts +36 -0
  407. package/src/ui/admin/AdminUiRouter.ts +170 -0
  408. package/src/ui/admin/pages/AdminDashboard.ts +54 -0
  409. package/src/ui/admin/partials.ts +83 -0
  410. package/src/ui/html.ts +37 -0
  411. package/src/ui/layout.ts +44 -0
  412. package/src/ui/pages/dashboard.ts +64 -0
  413. package/src/ui/pages/request-detail.ts +142 -0
  414. package/src/ui/pages/requests.ts +141 -0
  415. package/src/ui/pages/stubs.ts +52 -0
  416. package/src/ui/partials.ts +133 -0
  417. package/ui/UiRouter/package.json +6 -0
  418. package/ui/admin/AdminLayout/package.json +6 -0
  419. package/ui/admin/AdminUiRouter/package.json +6 -0
  420. package/ui/admin/pages/AdminDashboard/package.json +6 -0
  421. package/ui/admin/partials/package.json +6 -0
  422. package/ui/html/package.json +6 -0
  423. package/ui/layout/package.json +6 -0
  424. package/ui/pages/dashboard/package.json +6 -0
  425. package/ui/pages/requests/package.json +6 -0
  426. package/ui/pages/stubs/package.json +6 -0
@@ -0,0 +1,101 @@
1
+ import { Context, Data, Effect, Layer } from "effect";
2
+ import { NonEmptyString } from "../schemas/common";
3
+ import { Uuid } from "./Uuid";
4
+ export class ProxyError extends Data.TaggedError("ProxyError") {}
5
+ const HOP_BY_HOP_HEADERS = /*#__PURE__*/new Set(["host", "connection", "keep-alive", "transfer-encoding", "upgrade", "proxy-authenticate", "proxy-authorization", "te", "trailers"]);
6
+ export class ProxyService extends Context.Tag("ProxyService")() {}
7
+ export const ProxyServiceLive = /*#__PURE__*/Layer.effect(ProxyService, /*#__PURE__*/Effect.gen(function* () {
8
+ const uuid = yield* Uuid;
9
+ const forward = (ctx, config, originalUrl) => Effect.gen(function* () {
10
+ // Build target URL preserving path and query
11
+ const targetBase = config.targetUrl.replace(/\/$/, "");
12
+ const targetUrl = `${targetBase}${originalUrl.pathname}${originalUrl.search}`;
13
+ // Build headers
14
+ const headers = new Headers();
15
+ for (const [key, val] of Object.entries(ctx.headers)) {
16
+ if (!HOP_BY_HOP_HEADERS.has(key.toLowerCase())) {
17
+ headers.set(key, val);
18
+ }
19
+ }
20
+ // Remove headers specified in config
21
+ for (const h of config.removeHeaders) {
22
+ headers.delete(h);
23
+ }
24
+ // Add headers specified in config
25
+ if (config.addHeaders) {
26
+ for (const [key, val] of Object.entries(config.addHeaders)) {
27
+ headers.set(key, val);
28
+ }
29
+ }
30
+ // Build body
31
+ let body;
32
+ if (ctx.body !== undefined && ctx.body !== null) {
33
+ body = typeof ctx.body === "string" ? ctx.body : JSON.stringify(ctx.body);
34
+ }
35
+ const response = yield* Effect.tryPromise({
36
+ try: signal => fetch(targetUrl, {
37
+ method: ctx.method,
38
+ headers,
39
+ ...(body !== undefined && ctx.method !== "GET" && ctx.method !== "HEAD" ? {
40
+ body
41
+ } : {}),
42
+ redirect: config.followRedirects ? "follow" : "manual",
43
+ signal
44
+ }),
45
+ catch: err => new ProxyError({
46
+ targetUrl,
47
+ reason: `Failed to reach target: ${err}`,
48
+ cause: err
49
+ })
50
+ }).pipe(Effect.timeoutFail({
51
+ duration: `${config.timeout} millis`,
52
+ onTimeout: () => new ProxyError({
53
+ targetUrl,
54
+ reason: `Request timed out after ${config.timeout}ms`
55
+ })
56
+ }));
57
+ return response;
58
+ });
59
+ const recordAsStub = (request, response) => Effect.gen(function* () {
60
+ const id = yield* uuid.generateShort;
61
+ const respHeaders = {};
62
+ response.headers.forEach((val, key) => {
63
+ respHeaders[key] = val;
64
+ });
65
+ const respText = yield* Effect.promise(() => response.text());
66
+ let respBody = respText;
67
+ const contentType = response.headers.get("content-type") ?? "";
68
+ if (contentType.includes("application/json") && respText) {
69
+ try {
70
+ respBody = JSON.parse(respText);
71
+ } catch {
72
+ // keep as string
73
+ }
74
+ }
75
+ return {
76
+ id: NonEmptyString.make(id),
77
+ predicates: [{
78
+ field: "method",
79
+ operator: "equals",
80
+ value: request.method,
81
+ caseSensitive: true
82
+ }, {
83
+ field: "path",
84
+ operator: "equals",
85
+ value: request.path,
86
+ caseSensitive: true
87
+ }],
88
+ responses: [{
89
+ status: response.status,
90
+ headers: respHeaders,
91
+ body: respBody
92
+ }],
93
+ responseMode: "sequential"
94
+ };
95
+ });
96
+ return {
97
+ forward,
98
+ recordAsStub
99
+ };
100
+ }));
101
+ //# sourceMappingURL=ProxyService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProxyService.js","names":["Context","Data","Effect","Layer","NonEmptyString","Uuid","ProxyError","TaggedError","HOP_BY_HOP_HEADERS","Set","ProxyService","Tag","ProxyServiceLive","effect","gen","uuid","forward","ctx","config","originalUrl","targetBase","targetUrl","replace","pathname","search","headers","Headers","key","val","Object","entries","has","toLowerCase","set","h","removeHeaders","delete","addHeaders","body","undefined","JSON","stringify","response","tryPromise","try","signal","fetch","method","redirect","followRedirects","catch","err","reason","cause","pipe","timeoutFail","duration","timeout","onTimeout","recordAsStub","request","id","generateShort","respHeaders","forEach","respText","promise","text","respBody","contentType","get","includes","parse","make","predicates","field","operator","value","caseSensitive","path","responses","status","responseMode"],"sources":["../../../src/services/ProxyService.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,53 @@
1
+ import { Context, Effect, HashMap, Layer, PubSub, Ref } from "effect";
2
+ const MAX_ENTRIES = 100;
3
+ export class RequestLogger extends Context.Tag("RequestLogger")() {}
4
+ export const RequestLoggerLive = /*#__PURE__*/Layer.scoped(RequestLogger, /*#__PURE__*/Effect.gen(function* () {
5
+ const storeRef = yield* Ref.make(HashMap.empty());
6
+ const pubsub = yield* PubSub.sliding(256);
7
+ const log = entry => Effect.gen(function* () {
8
+ yield* Ref.update(storeRef, store => {
9
+ const existing = HashMap.get(store, entry.imposterId);
10
+ const entries = existing._tag === "Some" ? existing.value : [];
11
+ const updated = [...entries, entry].slice(-MAX_ENTRIES);
12
+ return HashMap.set(store, entry.imposterId, updated);
13
+ });
14
+ yield* PubSub.publish(pubsub, entry);
15
+ });
16
+ const getEntries = (imposterId, opts) => Ref.get(storeRef).pipe(Effect.map(store => {
17
+ const existing = HashMap.get(store, imposterId);
18
+ let entries = existing._tag === "Some" ? existing.value : [];
19
+ if (opts?.method !== undefined) {
20
+ entries = entries.filter(e => e.request.method.toUpperCase() === opts.method.toUpperCase());
21
+ }
22
+ if (opts?.path !== undefined) {
23
+ entries = entries.filter(e => e.request.path === opts.path);
24
+ }
25
+ if (opts?.status !== undefined) {
26
+ entries = entries.filter(e => e.response.status === opts.status);
27
+ }
28
+ const limit = opts?.limit ?? 50;
29
+ return entries.slice(-limit);
30
+ }));
31
+ const getCount = imposterId => Ref.get(storeRef).pipe(Effect.map(store => {
32
+ const existing = HashMap.get(store, imposterId);
33
+ return existing._tag === "Some" ? existing.value.length : 0;
34
+ }));
35
+ const clear = imposterId => Ref.update(storeRef, store => HashMap.set(store, imposterId, []));
36
+ const subscribe = PubSub.subscribe(pubsub);
37
+ const getEntryById = (imposterId, entryId) => Ref.get(storeRef).pipe(Effect.map(store => {
38
+ const existing = HashMap.get(store, imposterId);
39
+ if (existing._tag === "None") return null;
40
+ return existing.value.find(e => e.id === entryId) ?? null;
41
+ }));
42
+ const removeImposter = imposterId => Ref.update(storeRef, HashMap.remove(imposterId));
43
+ return {
44
+ log,
45
+ getEntries,
46
+ getCount,
47
+ clear,
48
+ subscribe,
49
+ getEntryById,
50
+ removeImposter
51
+ };
52
+ }));
53
+ //# sourceMappingURL=RequestLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestLogger.js","names":["Context","Effect","HashMap","Layer","PubSub","Ref","MAX_ENTRIES","RequestLogger","Tag","RequestLoggerLive","scoped","gen","storeRef","make","empty","pubsub","sliding","log","entry","update","store","existing","get","imposterId","entries","_tag","value","updated","slice","set","publish","getEntries","opts","pipe","map","method","undefined","filter","e","request","toUpperCase","path","status","response","limit","getCount","length","clear","subscribe","getEntryById","entryId","find","id","removeImposter","remove"],"sources":["../../../src/services/RequestLogger.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ import { Context } from "effect";
2
+ export class Uuid extends Context.Tag("UuidService")() {}
3
+ //# sourceMappingURL=Uuid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Uuid.js","names":["Context","Uuid","Tag"],"sources":["../../../src/services/Uuid.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,OAAO,QAAqB,QAAQ;AAE7C,OAAM,MAAOC,IAAK,SAAQD,OAAO,CAACE,GAAG,CAAC,aAAa,CAAC,EAMjD","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import { v4 } from "uuid";
4
+ import { Uuid } from "./Uuid";
5
+ export const UuidLive = /*#__PURE__*/Layer.succeed(Uuid, {
6
+ generate: /*#__PURE__*/Effect.sync(() => v4()),
7
+ generateShort: /*#__PURE__*/Effect.sync(() => v4().substring(0, 8))
8
+ });
9
+ //# sourceMappingURL=UuidLive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UuidLive.js","names":["Effect","Layer","v4","Uuid","UuidLive","succeed","generate","sync","generateShort","substring"],"sources":["../../../src/services/UuidLive.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAO,KAAKA,MAAM,MAAM,eAAe;AACvC,OAAO,KAAKC,KAAK,MAAM,cAAc;AACrC,SAASC,EAAE,QAAQ,MAAM;AACzB,SAASC,IAAI,QAAQ,QAAQ;AAE7B,OAAO,MAAMC,QAAQ,gBAAGH,KAAK,CAACI,OAAO,CAACF,IAAI,EAAE;EAC1CG,QAAQ,eAAEN,MAAM,CAACO,IAAI,CAAC,MAAML,EAAE,EAAE,CAAC;EACjCM,aAAa,eAAER,MAAM,CAACO,IAAI,CAAC,MAAML,EAAE,EAAE,CAACO,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;CACtD,CAAC","ignoreList":[]}
@@ -0,0 +1,235 @@
1
+ import { Effect, Ref } from "effect";
2
+ import { NonEmptyString } from "../schemas/common";
3
+ import { dashboardPage } from "./pages/dashboard";
4
+ import { requestDetailPage } from "./pages/request-detail";
5
+ import { requestsPage, testResultPartial } from "./pages/requests";
6
+ import { stubsPage } from "./pages/stubs";
7
+ import { errorPartial, requestTablePartial, stubListPartial } from "./partials";
8
+ const htmlResponse = (body, status = 200) => new Response(body, {
9
+ status,
10
+ headers: {
11
+ "content-type": "text/html; charset=utf-8"
12
+ }
13
+ });
14
+ const parseStubIdFromPath = path => {
15
+ const match = path.match(/^\/stubs\/(.+)$/);
16
+ return match ? match[1] : null;
17
+ };
18
+ export const makeUiRouter = deps => async request => {
19
+ const url = new URL(request.url);
20
+ if (!url.pathname.startsWith("/_admin")) return null;
21
+ const path = url.pathname.slice("/_admin".length) || "/";
22
+ const method = request.method.toUpperCase();
23
+ // GET / — dashboard
24
+ if (method === "GET" && (path === "/" || path === "")) {
25
+ return deps.runPromise(Effect.gen(function* () {
26
+ const stubs = yield* Ref.get(deps.stubsRef);
27
+ const requestCount = yield* deps.requestLogger.getCount(deps.id);
28
+ const recentRequests = yield* deps.requestLogger.getEntries(deps.id, {
29
+ limit: 10
30
+ });
31
+ return htmlResponse(dashboardPage({
32
+ config: deps.config,
33
+ stubCount: stubs.length,
34
+ requestCount,
35
+ recentRequests: recentRequests.slice().reverse()
36
+ }).value);
37
+ }));
38
+ }
39
+ // GET /stubs — stubs page
40
+ if (method === "GET" && path === "/stubs") {
41
+ return deps.runPromise(Effect.gen(function* () {
42
+ const stubs = yield* Ref.get(deps.stubsRef);
43
+ return htmlResponse(stubsPage({
44
+ config: deps.config,
45
+ stubs
46
+ }).value);
47
+ }));
48
+ }
49
+ // POST /stubs — add stub
50
+ if (method === "POST" && path === "/stubs") {
51
+ try {
52
+ const formData = await request.formData();
53
+ const predicatesRaw = formData.get("predicates");
54
+ const responsesRaw = formData.get("responses");
55
+ const responseMode = formData.get("responseMode") || "sequential";
56
+ if (!responsesRaw) {
57
+ return htmlResponse(errorPartial("Responses field is required.").value, 200);
58
+ }
59
+ let predicates;
60
+ let responses;
61
+ try {
62
+ predicates = JSON.parse(predicatesRaw || "[]");
63
+ responses = JSON.parse(responsesRaw);
64
+ } catch {
65
+ return htmlResponse(errorPartial("Invalid JSON in predicates or responses.").value, 200);
66
+ }
67
+ if (!Array.isArray(responses) || responses.length === 0) {
68
+ return htmlResponse(errorPartial("Responses must be a non-empty array.").value, 200);
69
+ }
70
+ const stubId = NonEmptyString.make(crypto.randomUUID().slice(0, 8));
71
+ const stub = {
72
+ id: stubId,
73
+ predicates: predicates,
74
+ responses: responses,
75
+ responseMode: responseMode
76
+ };
77
+ return await deps.runPromise(Effect.gen(function* () {
78
+ yield* deps.repo.addStub(deps.id, stub).pipe(Effect.catchAll(() => Effect.void));
79
+ const updated = yield* deps.repo.getStubs(deps.id).pipe(Effect.catchAll(() => Effect.succeed([])));
80
+ yield* Ref.set(deps.stubsRef, updated);
81
+ return htmlResponse(stubListPartial(updated).value);
82
+ }));
83
+ } catch {
84
+ return htmlResponse(errorPartial("Failed to parse form data.").value, 200);
85
+ }
86
+ }
87
+ // DELETE /stubs/:id — delete stub
88
+ const deleteStubId = method === "DELETE" ? parseStubIdFromPath(path) : null;
89
+ if (deleteStubId !== null) {
90
+ return deps.runPromise(Effect.gen(function* () {
91
+ yield* deps.repo.removeStub(deps.id, deleteStubId).pipe(Effect.catchAll(() => Effect.void));
92
+ const updated = yield* deps.repo.getStubs(deps.id).pipe(Effect.catchAll(() => Effect.succeed([])));
93
+ yield* Ref.set(deps.stubsRef, updated);
94
+ return htmlResponse(stubListPartial(updated).value);
95
+ }));
96
+ }
97
+ // PUT /stubs/:id — update stub
98
+ const putStubId = method === "PUT" ? parseStubIdFromPath(path) : null;
99
+ if (putStubId !== null) {
100
+ try {
101
+ const formData = await request.formData();
102
+ const predicatesRaw = formData.get("predicates");
103
+ const responsesRaw = formData.get("responses");
104
+ const responseMode = formData.get("responseMode");
105
+ return await deps.runPromise(Effect.gen(function* () {
106
+ yield* deps.repo.updateStub(deps.id, putStubId, existing => ({
107
+ ...existing,
108
+ ...(predicatesRaw ? {
109
+ predicates: JSON.parse(predicatesRaw)
110
+ } : {}),
111
+ ...(responsesRaw ? {
112
+ responses: JSON.parse(responsesRaw)
113
+ } : {}),
114
+ ...(responseMode ? {
115
+ responseMode: responseMode
116
+ } : {})
117
+ })).pipe(Effect.catchAll(() => Effect.void));
118
+ const updated = yield* deps.repo.getStubs(deps.id).pipe(Effect.catchAll(() => Effect.succeed([])));
119
+ yield* Ref.set(deps.stubsRef, updated);
120
+ return htmlResponse(stubListPartial(updated).value);
121
+ }));
122
+ } catch {
123
+ return htmlResponse(errorPartial("Failed to parse form data.").value, 200);
124
+ }
125
+ }
126
+ // GET /requests — full page
127
+ if (method === "GET" && path === "/requests") {
128
+ return deps.runPromise(Effect.gen(function* () {
129
+ const entries = yield* deps.requestLogger.getEntries(deps.id, {
130
+ limit: 100
131
+ });
132
+ return htmlResponse(requestsPage({
133
+ config: deps.config,
134
+ entries
135
+ }).value);
136
+ }));
137
+ }
138
+ // GET /requests/list — HTMX partial (filtered table body)
139
+ if (method === "GET" && path === "/requests/list") {
140
+ const params = url.searchParams;
141
+ return deps.runPromise(Effect.gen(function* () {
142
+ const opts = {
143
+ limit: 100
144
+ };
145
+ const methodFilter = params.get("method");
146
+ if (methodFilter) opts.method = methodFilter;
147
+ const pathFilter = params.get("path");
148
+ if (pathFilter) opts.path = pathFilter;
149
+ const statusFilter = params.get("status");
150
+ if (statusFilter) opts.status = Number(statusFilter);
151
+ const entries = yield* deps.requestLogger.getEntries(deps.id, opts);
152
+ return htmlResponse(requestTablePartial(entries.slice().reverse()).value);
153
+ }));
154
+ }
155
+ // POST /requests/test — send test request to own port
156
+ if (method === "POST" && path === "/requests/test") {
157
+ try {
158
+ const formData = await request.formData();
159
+ const testMethod = formData.get("method") || "GET";
160
+ const testPath = formData.get("path") || "/";
161
+ const testBody = formData.get("body");
162
+ const testContentType = formData.get("contentType") || "application/json";
163
+ const testHeadersRaw = formData.get("headers") || "";
164
+ const headers = {};
165
+ if (testContentType && testBody) {
166
+ headers["content-type"] = testContentType;
167
+ }
168
+ for (const line of testHeadersRaw.split("\n")) {
169
+ const colonIdx = line.indexOf(":");
170
+ if (colonIdx > 0) {
171
+ headers[line.slice(0, colonIdx).trim()] = line.slice(colonIdx + 1).trim();
172
+ }
173
+ }
174
+ const startTime = Date.now();
175
+ const testResp = await fetch(`http://localhost:${deps.config.port}${testPath}`, {
176
+ method: testMethod,
177
+ headers,
178
+ ...(testBody && testMethod !== "GET" && testMethod !== "HEAD" ? {
179
+ body: testBody
180
+ } : {})
181
+ });
182
+ const duration = Date.now() - startTime;
183
+ const respBody = await testResp.text();
184
+ const respHeaders = {};
185
+ testResp.headers.forEach((val, key) => {
186
+ respHeaders[key] = val;
187
+ });
188
+ return htmlResponse(testResultPartial({
189
+ status: testResp.status,
190
+ headers: respHeaders,
191
+ body: respBody,
192
+ duration
193
+ }).value);
194
+ } catch (err) {
195
+ return htmlResponse(`<div class="bg-red-50 border border-red-200 text-red-700 rounded p-3">Request failed: ${String(err)}</div>`);
196
+ }
197
+ }
198
+ // DELETE /requests — clear log
199
+ if (method === "DELETE" && path === "/requests") {
200
+ return deps.runPromise(Effect.gen(function* () {
201
+ yield* deps.requestLogger.clear(deps.id);
202
+ return htmlResponse(requestTablePartial([]).value);
203
+ }));
204
+ }
205
+ // GET /requests/:id — detail page
206
+ if (method === "GET" && path.startsWith("/requests/")) {
207
+ const entryId = path.slice("/requests/".length);
208
+ if (entryId && !entryId.includes("/")) {
209
+ return deps.runPromise(Effect.gen(function* () {
210
+ const entry = yield* deps.requestLogger.getEntryById(deps.id, entryId);
211
+ if (entry === null) {
212
+ return htmlResponse("<h1>Request not found</h1>", 404);
213
+ }
214
+ // Try to find matched stub
215
+ let matchedStub = null;
216
+ if (entry.response.matchedStubId) {
217
+ try {
218
+ const stubs = yield* deps.repo.getStubs(deps.id).pipe(Effect.catchAll(() => Effect.succeed([])));
219
+ matchedStub = stubs.find(s => s.id === entry.response.matchedStubId) ?? null;
220
+ } catch {
221
+ // ignore
222
+ }
223
+ }
224
+ return htmlResponse(requestDetailPage({
225
+ config: deps.config,
226
+ entry,
227
+ matchedStub
228
+ }).value);
229
+ }));
230
+ }
231
+ }
232
+ // Fallback: 404 within /_admin
233
+ return htmlResponse("<h1>Not Found</h1>", 404);
234
+ };
235
+ //# sourceMappingURL=UiRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UiRouter.js","names":["Effect","Ref","NonEmptyString","dashboardPage","requestDetailPage","requestsPage","testResultPartial","stubsPage","errorPartial","requestTablePartial","stubListPartial","htmlResponse","body","status","Response","headers","parseStubIdFromPath","path","match","makeUiRouter","deps","request","url","URL","pathname","startsWith","slice","length","method","toUpperCase","runPromise","gen","stubs","get","stubsRef","requestCount","requestLogger","getCount","id","recentRequests","getEntries","limit","config","stubCount","reverse","value","formData","predicatesRaw","responsesRaw","responseMode","predicates","responses","JSON","parse","Array","isArray","stubId","make","crypto","randomUUID","stub","repo","addStub","pipe","catchAll","void","updated","getStubs","succeed","set","deleteStubId","removeStub","putStubId","updateStub","existing","entries","params","searchParams","opts","methodFilter","pathFilter","statusFilter","Number","testMethod","testPath","testBody","testContentType","testHeadersRaw","line","split","colonIdx","indexOf","trim","startTime","Date","now","testResp","fetch","port","duration","respBody","text","respHeaders","forEach","val","key","err","String","clear","entryId","includes","entry","getEntryById","matchedStub","response","matchedStubId","find","s"],"sources":["../../../src/ui/UiRouter.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,MAAM,EAAEC,GAAG,QAAQ,QAAQ;AAGpC,SAASC,cAAc,QAAQ,mBAAmB;AAGlD,SAASC,aAAa,QAAQ,mBAAmB;AACjD,SAASC,iBAAiB,QAAQ,wBAAwB;AAC1D,SAASC,YAAY,EAAEC,iBAAiB,QAAQ,kBAAkB;AAClE,SAASC,SAAS,QAAQ,eAAe;AACzC,SAASC,YAAY,EAAEC,mBAAmB,EAAEC,eAAe,QAAQ,YAAY;AAW/E,MAAMC,YAAY,GAAGA,CAACC,IAAY,EAAEC,MAAM,GAAG,GAAG,KAC9C,IAAIC,QAAQ,CAACF,IAAI,EAAE;EACjBC,MAAM;EACNE,OAAO,EAAE;IAAE,cAAc,EAAE;EAA0B;CACtD,CAAC;AAEJ,MAAMC,mBAAmB,GAAIC,IAAY,IAAmB;EAC1D,MAAMC,KAAK,GAAGD,IAAI,CAACC,KAAK,CAAC,iBAAiB,CAAC;EAC3C,OAAOA,KAAK,GAAGA,KAAK,CAAC,CAAC,CAAE,GAAG,IAAI;AACjC,CAAC;AAED,OAAO,MAAMC,YAAY,GAAIC,IAAY,IAAK,MAAOC,OAAgB,IAA8B;EACjG,MAAMC,GAAG,GAAG,IAAIC,GAAG,CAACF,OAAO,CAACC,GAAG,CAAC;EAChC,IAAI,CAACA,GAAG,CAACE,QAAQ,CAACC,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,IAAI;EAEpD,MAAMR,IAAI,GAAGK,GAAG,CAACE,QAAQ,CAACE,KAAK,CAAC,SAAS,CAACC,MAAM,CAAC,IAAI,GAAG;EACxD,MAAMC,MAAM,GAAGP,OAAO,CAACO,MAAM,CAACC,WAAW,EAAE;EAE3C;EACA,IAAID,MAAM,KAAK,KAAK,KAAKX,IAAI,KAAK,GAAG,IAAIA,IAAI,KAAK,EAAE,CAAC,EAAE;IACrD,OAAOG,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;MAClB,MAAMC,KAAK,GAAG,OAAO/B,GAAG,CAACgC,GAAG,CAACb,IAAI,CAACc,QAAQ,CAAC;MAC3C,MAAMC,YAAY,GAAG,OAAOf,IAAI,CAACgB,aAAa,CAACC,QAAQ,CAACjB,IAAI,CAACkB,EAAE,CAAC;MAChE,MAAMC,cAAc,GAAG,OAAOnB,IAAI,CAACgB,aAAa,CAACI,UAAU,CAACpB,IAAI,CAACkB,EAAE,EAAE;QAAEG,KAAK,EAAE;MAAE,CAAE,CAAC;MACnF,OAAO9B,YAAY,CACjBR,aAAa,CAAC;QACZuC,MAAM,EAAEtB,IAAI,CAACsB,MAAM;QACnBC,SAAS,EAAEX,KAAK,CAACL,MAAM;QACvBQ,YAAY;QACZI,cAAc,EAAEA,cAAc,CAACb,KAAK,EAAE,CAACkB,OAAO;OAC/C,CAAC,CAACC,KAAK,CACT;IACH,CAAC,CAAC,CACH;EACH;EAEA;EACA,IAAIjB,MAAM,KAAK,KAAK,IAAIX,IAAI,KAAK,QAAQ,EAAE;IACzC,OAAOG,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;MAClB,MAAMC,KAAK,GAAG,OAAO/B,GAAG,CAACgC,GAAG,CAACb,IAAI,CAACc,QAAQ,CAAC;MAC3C,OAAOvB,YAAY,CAACJ,SAAS,CAAC;QAAEmC,MAAM,EAAEtB,IAAI,CAACsB,MAAM;QAAEV;MAAK,CAAE,CAAC,CAACa,KAAK,CAAC;IACtE,CAAC,CAAC,CACH;EACH;EAEA;EACA,IAAIjB,MAAM,KAAK,MAAM,IAAIX,IAAI,KAAK,QAAQ,EAAE;IAC1C,IAAI;MACF,MAAM6B,QAAQ,GAAG,MAAMzB,OAAO,CAACyB,QAAQ,EAAE;MACzC,MAAMC,aAAa,GAAGD,QAAQ,CAACb,GAAG,CAAC,YAAY,CAAkB;MACjE,MAAMe,YAAY,GAAGF,QAAQ,CAACb,GAAG,CAAC,WAAW,CAAkB;MAC/D,MAAMgB,YAAY,GAAIH,QAAQ,CAACb,GAAG,CAAC,cAAc,CAAmB,IAAI,YAAY;MAEpF,IAAI,CAACe,YAAY,EAAE;QACjB,OAAOrC,YAAY,CAACH,YAAY,CAAC,8BAA8B,CAAC,CAACqC,KAAK,EAAE,GAAG,CAAC;MAC9E;MAEA,IAAIK,UAAmB;MACvB,IAAIC,SAAkB;MACtB,IAAI;QACFD,UAAU,GAAGE,IAAI,CAACC,KAAK,CAACN,aAAa,IAAI,IAAI,CAAC;QAC9CI,SAAS,GAAGC,IAAI,CAACC,KAAK,CAACL,YAAY,CAAC;MACtC,CAAC,CAAC,MAAM;QACN,OAAOrC,YAAY,CAACH,YAAY,CAAC,0CAA0C,CAAC,CAACqC,KAAK,EAAE,GAAG,CAAC;MAC1F;MAEA,IAAI,CAACS,KAAK,CAACC,OAAO,CAACJ,SAAS,CAAC,IAAIA,SAAS,CAACxB,MAAM,KAAK,CAAC,EAAE;QACvD,OAAOhB,YAAY,CAACH,YAAY,CAAC,sCAAsC,CAAC,CAACqC,KAAK,EAAE,GAAG,CAAC;MACtF;MAEA,MAAMW,MAAM,GAAGtD,cAAc,CAACuD,IAAI,CAACC,MAAM,CAACC,UAAU,EAAE,CAACjC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;MACnE,MAAMkC,IAAI,GAAS;QACjBtB,EAAE,EAAEkB,MAAM;QACVN,UAAU,EAAEA,UAAgC;QAC5CC,SAAS,EAAEA,SAAyC;QACpDF,YAAY,EAAEA;OACf;MAED,OAAO,MAAM7B,IAAI,CAACU,UAAU,CAC1B9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;QAClB,OAAOX,IAAI,CAACyC,IAAI,CAACC,OAAO,CAAC1C,IAAI,CAACkB,EAAE,EAAEsB,IAAI,CAAC,CAACG,IAAI,CAC1C/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACiE,IAAI,CAAC,CACnC;QACD,MAAMC,OAAO,GAAG,OAAO9C,IAAI,CAACyC,IAAI,CAACM,QAAQ,CAAC/C,IAAI,CAACkB,EAAE,CAAC,CAACyB,IAAI,CACrD/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACoE,OAAO,CAAC,EAAyB,CAAC,CAAC,CACjE;QACD,OAAOnE,GAAG,CAACoE,GAAG,CAACjD,IAAI,CAACc,QAAQ,EAAEgC,OAAO,CAAC;QACtC,OAAOvD,YAAY,CAACD,eAAe,CAACwD,OAAO,CAAC,CAACrB,KAAK,CAAC;MACrD,CAAC,CAAC,CACH;IACH,CAAC,CAAC,MAAM;MACN,OAAOlC,YAAY,CAACH,YAAY,CAAC,4BAA4B,CAAC,CAACqC,KAAK,EAAE,GAAG,CAAC;IAC5E;EACF;EAEA;EACA,MAAMyB,YAAY,GAAG1C,MAAM,KAAK,QAAQ,GAAGZ,mBAAmB,CAACC,IAAI,CAAC,GAAG,IAAI;EAC3E,IAAIqD,YAAY,KAAK,IAAI,EAAE;IACzB,OAAOlD,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;MAClB,OAAOX,IAAI,CAACyC,IAAI,CAACU,UAAU,CAACnD,IAAI,CAACkB,EAAE,EAAEgC,YAAY,CAAC,CAACP,IAAI,CACrD/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACiE,IAAI,CAAC,CACnC;MACD,MAAMC,OAAO,GAAG,OAAO9C,IAAI,CAACyC,IAAI,CAACM,QAAQ,CAAC/C,IAAI,CAACkB,EAAE,CAAC,CAACyB,IAAI,CACrD/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACoE,OAAO,CAAC,EAAyB,CAAC,CAAC,CACjE;MACD,OAAOnE,GAAG,CAACoE,GAAG,CAACjD,IAAI,CAACc,QAAQ,EAAEgC,OAAO,CAAC;MACtC,OAAOvD,YAAY,CAACD,eAAe,CAACwD,OAAO,CAAC,CAACrB,KAAK,CAAC;IACrD,CAAC,CAAC,CACH;EACH;EAEA;EACA,MAAM2B,SAAS,GAAG5C,MAAM,KAAK,KAAK,GAAGZ,mBAAmB,CAACC,IAAI,CAAC,GAAG,IAAI;EACrE,IAAIuD,SAAS,KAAK,IAAI,EAAE;IACtB,IAAI;MACF,MAAM1B,QAAQ,GAAG,MAAMzB,OAAO,CAACyB,QAAQ,EAAE;MACzC,MAAMC,aAAa,GAAGD,QAAQ,CAACb,GAAG,CAAC,YAAY,CAAkB;MACjE,MAAMe,YAAY,GAAGF,QAAQ,CAACb,GAAG,CAAC,WAAW,CAAkB;MAC/D,MAAMgB,YAAY,GAAGH,QAAQ,CAACb,GAAG,CAAC,cAAc,CAAkB;MAElE,OAAO,MAAMb,IAAI,CAACU,UAAU,CAC1B9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;QAClB,OAAOX,IAAI,CAACyC,IAAI,CAACY,UAAU,CAACrD,IAAI,CAACkB,EAAE,EAAEkC,SAAS,EAAGE,QAAQ,KAAM;UAC7D,GAAGA,QAAQ;UACX,IAAI3B,aAAa,GAAG;YAAEG,UAAU,EAAEE,IAAI,CAACC,KAAK,CAACN,aAAa;UAAC,CAAE,GAAG,EAAE,CAAC;UACnE,IAAIC,YAAY,GAAG;YAAEG,SAAS,EAAEC,IAAI,CAACC,KAAK,CAACL,YAAY;UAAC,CAAE,GAAG,EAAE,CAAC;UAChE,IAAIC,YAAY,GAAG;YAAEA,YAAY,EAAEA;UAAoC,CAAE,GAAG,EAAE;SAC/E,CAAC,CAAC,CAACc,IAAI,CAAC/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACiE,IAAI,CAAC,CAAC;QAC5C,MAAMC,OAAO,GAAG,OAAO9C,IAAI,CAACyC,IAAI,CAACM,QAAQ,CAAC/C,IAAI,CAACkB,EAAE,CAAC,CAACyB,IAAI,CACrD/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACoE,OAAO,CAAC,EAAyB,CAAC,CAAC,CACjE;QACD,OAAOnE,GAAG,CAACoE,GAAG,CAACjD,IAAI,CAACc,QAAQ,EAAEgC,OAAO,CAAC;QACtC,OAAOvD,YAAY,CAACD,eAAe,CAACwD,OAAO,CAAC,CAACrB,KAAK,CAAC;MACrD,CAAC,CAAC,CACH;IACH,CAAC,CAAC,MAAM;MACN,OAAOlC,YAAY,CAACH,YAAY,CAAC,4BAA4B,CAAC,CAACqC,KAAK,EAAE,GAAG,CAAC;IAC5E;EACF;EAEA;EACA,IAAIjB,MAAM,KAAK,KAAK,IAAIX,IAAI,KAAK,WAAW,EAAE;IAC5C,OAAOG,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;MAClB,MAAM4C,OAAO,GAAG,OAAOvD,IAAI,CAACgB,aAAa,CAACI,UAAU,CAACpB,IAAI,CAACkB,EAAE,EAAE;QAAEG,KAAK,EAAE;MAAG,CAAE,CAAC;MAC7E,OAAO9B,YAAY,CAACN,YAAY,CAAC;QAAEqC,MAAM,EAAEtB,IAAI,CAACsB,MAAM;QAAEiC;MAAO,CAAE,CAAC,CAAC9B,KAAK,CAAC;IAC3E,CAAC,CAAC,CACH;EACH;EAEA;EACA,IAAIjB,MAAM,KAAK,KAAK,IAAIX,IAAI,KAAK,gBAAgB,EAAE;IACjD,MAAM2D,MAAM,GAAGtD,GAAG,CAACuD,YAAY;IAC/B,OAAOzD,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;MAClB,MAAM+C,IAAI,GAAwE;QAAErC,KAAK,EAAE;MAAG,CAAE;MAChG,MAAMsC,YAAY,GAAGH,MAAM,CAAC3C,GAAG,CAAC,QAAQ,CAAC;MACzC,IAAI8C,YAAY,EAAED,IAAI,CAAClD,MAAM,GAAGmD,YAAY;MAC5C,MAAMC,UAAU,GAAGJ,MAAM,CAAC3C,GAAG,CAAC,MAAM,CAAC;MACrC,IAAI+C,UAAU,EAAEF,IAAI,CAAC7D,IAAI,GAAG+D,UAAU;MACtC,MAAMC,YAAY,GAAGL,MAAM,CAAC3C,GAAG,CAAC,QAAQ,CAAC;MACzC,IAAIgD,YAAY,EAAEH,IAAI,CAACjE,MAAM,GAAGqE,MAAM,CAACD,YAAY,CAAC;MACpD,MAAMN,OAAO,GAAG,OAAOvD,IAAI,CAACgB,aAAa,CAACI,UAAU,CAACpB,IAAI,CAACkB,EAAE,EAAEwC,IAAI,CAAC;MACnE,OAAOnE,YAAY,CAACF,mBAAmB,CAACkE,OAAO,CAACjD,KAAK,EAAE,CAACkB,OAAO,EAAE,CAAC,CAACC,KAAK,CAAC;IAC3E,CAAC,CAAC,CACH;EACH;EAEA;EACA,IAAIjB,MAAM,KAAK,MAAM,IAAIX,IAAI,KAAK,gBAAgB,EAAE;IAClD,IAAI;MACF,MAAM6B,QAAQ,GAAG,MAAMzB,OAAO,CAACyB,QAAQ,EAAE;MACzC,MAAMqC,UAAU,GAAIrC,QAAQ,CAACb,GAAG,CAAC,QAAQ,CAAY,IAAI,KAAK;MAC9D,MAAMmD,QAAQ,GAAItC,QAAQ,CAACb,GAAG,CAAC,MAAM,CAAY,IAAI,GAAG;MACxD,MAAMoD,QAAQ,GAAGvC,QAAQ,CAACb,GAAG,CAAC,MAAM,CAAkB;MACtD,MAAMqD,eAAe,GAAIxC,QAAQ,CAACb,GAAG,CAAC,aAAa,CAAY,IAAI,kBAAkB;MACrF,MAAMsD,cAAc,GAAIzC,QAAQ,CAACb,GAAG,CAAC,SAAS,CAAY,IAAI,EAAE;MAEhE,MAAMlB,OAAO,GAA2B,EAAE;MAC1C,IAAIuE,eAAe,IAAID,QAAQ,EAAE;QAC/BtE,OAAO,CAAC,cAAc,CAAC,GAAGuE,eAAe;MAC3C;MACA,KAAK,MAAME,IAAI,IAAID,cAAc,CAACE,KAAK,CAAC,IAAI,CAAC,EAAE;QAC7C,MAAMC,QAAQ,GAAGF,IAAI,CAACG,OAAO,CAAC,GAAG,CAAC;QAClC,IAAID,QAAQ,GAAG,CAAC,EAAE;UAChB3E,OAAO,CAACyE,IAAI,CAAC9D,KAAK,CAAC,CAAC,EAAEgE,QAAQ,CAAC,CAACE,IAAI,EAAE,CAAC,GAAGJ,IAAI,CAAC9D,KAAK,CAACgE,QAAQ,GAAG,CAAC,CAAC,CAACE,IAAI,EAAE;QAC3E;MACF;MAEA,MAAMC,SAAS,GAAGC,IAAI,CAACC,GAAG,EAAE;MAC5B,MAAMC,QAAQ,GAAG,MAAMC,KAAK,CAAC,oBAAoB7E,IAAI,CAACsB,MAAM,CAACwD,IAAI,GAAGd,QAAQ,EAAE,EAAE;QAC9ExD,MAAM,EAAEuD,UAAU;QAClBpE,OAAO;QACP,IAAIsE,QAAQ,IAAIF,UAAU,KAAK,KAAK,IAAIA,UAAU,KAAK,MAAM,GAAG;UAAEvE,IAAI,EAAEyE;QAAQ,CAAE,GAAG,EAAE;OACxF,CAAC;MACF,MAAMc,QAAQ,GAAGL,IAAI,CAACC,GAAG,EAAE,GAAGF,SAAS;MAEvC,MAAMO,QAAQ,GAAG,MAAMJ,QAAQ,CAACK,IAAI,EAAE;MACtC,MAAMC,WAAW,GAA2B,EAAE;MAC9CN,QAAQ,CAACjF,OAAO,CAACwF,OAAO,CAAC,CAACC,GAAG,EAAEC,GAAG,KAAI;QACpCH,WAAW,CAACG,GAAG,CAAC,GAAGD,GAAG;MACxB,CAAC,CAAC;MAEF,OAAO7F,YAAY,CACjBL,iBAAiB,CAAC;QAAEO,MAAM,EAAEmF,QAAQ,CAACnF,MAAM;QAAEE,OAAO,EAAEuF,WAAW;QAAE1F,IAAI,EAAEwF,QAAQ;QAAED;MAAQ,CAAE,CAAC,CAACtD,KAAK,CACrG;IACH,CAAC,CAAC,OAAO6D,GAAG,EAAE;MACZ,OAAO/F,YAAY,CACjB,yFAAyFgG,MAAM,CAACD,GAAG,CAAC,QAAQ,CAC7G;IACH;EACF;EAEA;EACA,IAAI9E,MAAM,KAAK,QAAQ,IAAIX,IAAI,KAAK,WAAW,EAAE;IAC/C,OAAOG,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;MAClB,OAAOX,IAAI,CAACgB,aAAa,CAACwE,KAAK,CAACxF,IAAI,CAACkB,EAAE,CAAC;MACxC,OAAO3B,YAAY,CAACF,mBAAmB,CAAC,EAAE,CAAC,CAACoC,KAAK,CAAC;IACpD,CAAC,CAAC,CACH;EACH;EAEA;EACA,IAAIjB,MAAM,KAAK,KAAK,IAAIX,IAAI,CAACQ,UAAU,CAAC,YAAY,CAAC,EAAE;IACrD,MAAMoF,OAAO,GAAG5F,IAAI,CAACS,KAAK,CAAC,YAAY,CAACC,MAAM,CAAC;IAC/C,IAAIkF,OAAO,IAAI,CAACA,OAAO,CAACC,QAAQ,CAAC,GAAG,CAAC,EAAE;MACrC,OAAO1F,IAAI,CAACU,UAAU,CACpB9B,MAAM,CAAC+B,GAAG,CAAC,aAAS;QAClB,MAAMgF,KAAK,GAAG,OAAO3F,IAAI,CAACgB,aAAa,CAAC4E,YAAY,CAAC5F,IAAI,CAACkB,EAAE,EAAEuE,OAAO,CAAC;QACtE,IAAIE,KAAK,KAAK,IAAI,EAAE;UAClB,OAAOpG,YAAY,CAAC,4BAA4B,EAAE,GAAG,CAAC;QACxD;QACA;QACA,IAAIsG,WAAW,GAAgB,IAAI;QACnC,IAAIF,KAAK,CAACG,QAAQ,CAACC,aAAa,EAAE;UAChC,IAAI;YACF,MAAMnF,KAAK,GAAG,OAAOZ,IAAI,CAACyC,IAAI,CAACM,QAAQ,CAAC/C,IAAI,CAACkB,EAAE,CAAC,CAACyB,IAAI,CACnD/D,MAAM,CAACgE,QAAQ,CAAC,MAAMhE,MAAM,CAACoE,OAAO,CAAC,EAAyB,CAAC,CAAC,CACjE;YACD6C,WAAW,GAAGjF,KAAK,CAACoF,IAAI,CAAEC,CAAC,IAAKA,CAAC,CAAC/E,EAAE,KAAKyE,KAAK,CAACG,QAAQ,CAACC,aAAa,CAAC,IAAI,IAAI;UAChF,CAAC,CAAC,MAAM;YACN;UAAA;QAEJ;QACA,OAAOxG,YAAY,CAACP,iBAAiB,CAAC;UAAEsC,MAAM,EAAEtB,IAAI,CAACsB,MAAM;UAAEqE,KAAK;UAAEE;QAAW,CAAE,CAAC,CAACpE,KAAK,CAAC;MAC3F,CAAC,CAAC,CACH;IACH;EACF;EAEA;EACA,OAAOlC,YAAY,CAAC,oBAAoB,EAAE,GAAG,CAAC;AAChD,CAAC","ignoreList":[]}
@@ -0,0 +1,29 @@
1
+ import { html, raw } from "../html";
2
+ export const adminLayout = (opts, content) => html`<!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <title>${opts.title}</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://unpkg.com/htmx.org@2.0.4"></script>
10
+ </head>
11
+ <body class="bg-gray-50 min-h-screen">
12
+ <nav class="bg-gray-800 text-white shadow-md">
13
+ <div class="max-w-6xl mx-auto px-4 py-3 flex items-center justify-between">
14
+ <div class="flex items-center gap-3">
15
+ <span class="text-lg font-bold">Imposters</span>
16
+ <span class="text-gray-400 text-sm">Admin</span>
17
+ </div>
18
+ <div class="flex gap-3 items-center">
19
+ <a href="/_ui" class="px-3 py-1.5 bg-gray-700 text-white rounded text-sm font-medium hover:bg-gray-600">Dashboard</a>
20
+ <a href="/docs" class="text-gray-400 hover:text-white text-sm">API Docs</a>
21
+ </div>
22
+ </div>
23
+ </nav>
24
+ <main class="max-w-6xl mx-auto px-4 py-6">
25
+ ${raw(content.value)}
26
+ </main>
27
+ </body>
28
+ </html>`;
29
+ //# sourceMappingURL=AdminLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminLayout.js","names":["html","raw","adminLayout","opts","content","title","value"],"sources":["../../../../src/ui/admin/AdminLayout.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,IAAI,EAAEC,GAAG,QAAQ,SAAS;AAQnC,OAAO,MAAMC,WAAW,GAAGA,CAACC,IAAqB,EAAEC,OAAiB,KAClEJ,IAAI;;;;;WAKKG,IAAI,CAACE,KAAK;;;;;;;;;;;;;;;;;;MAkBfJ,GAAG,CAACG,OAAO,CAACE,KAAK,CAAC;;;QAGhB","ignoreList":[]}
@@ -0,0 +1,148 @@
1
+ import { adminDashboardPage } from "./pages/AdminDashboard";
2
+ import { adminErrorPartial, imposterListPartial, imposterRowPartial } from "./partials";
3
+ const htmlResponse = (body, status = 200) => new Response(body, {
4
+ status,
5
+ headers: {
6
+ "content-type": "text/html; charset=utf-8"
7
+ }
8
+ });
9
+ const toAdminData = imp => ({
10
+ id: imp.id,
11
+ name: imp.name ?? `imposter-${imp.id}`,
12
+ port: imp.port,
13
+ status: imp.status,
14
+ protocol: imp.protocol ?? "HTTP",
15
+ stubCount: imp.stubs?.length ?? imp.endpointCount ?? imp.stubCount ?? 0
16
+ });
17
+ const fetchImposters = async apiHandler => {
18
+ const resp = await apiHandler(new Request("http://localhost/imposters?limit=50", {
19
+ method: "GET"
20
+ }));
21
+ if (!resp.ok) return [];
22
+ const data = await resp.json();
23
+ const items = Array.isArray(data) ? data : data.imposters ?? data.items ?? [];
24
+ return items.map(toAdminData);
25
+ };
26
+ const fetchImposter = async (apiHandler, id) => {
27
+ const resp = await apiHandler(new Request(`http://localhost/imposters/${id}`, {
28
+ method: "GET"
29
+ }));
30
+ if (!resp.ok) return null;
31
+ const imp = await resp.json();
32
+ return toAdminData(imp);
33
+ };
34
+ export const makeAdminUiRouter = deps => async request => {
35
+ const url = new URL(request.url);
36
+ if (!url.pathname.startsWith("/_ui")) return null;
37
+ const path = url.pathname.slice("/_ui".length) || "/";
38
+ const method = request.method.toUpperCase();
39
+ // GET / — dashboard
40
+ if (method === "GET" && (path === "/" || path === "")) {
41
+ const imposters = await fetchImposters(deps.apiHandler);
42
+ return htmlResponse(adminDashboardPage({
43
+ imposters
44
+ }).value);
45
+ }
46
+ // GET /imposters — HTMX partial (imposter list)
47
+ if (method === "GET" && path === "/imposters") {
48
+ const imposters = await fetchImposters(deps.apiHandler);
49
+ return htmlResponse(imposterListPartial(imposters).value);
50
+ }
51
+ // POST /imposters — create imposter from form
52
+ if (method === "POST" && path === "/imposters") {
53
+ try {
54
+ const formData = await request.formData();
55
+ const name = formData.get("name");
56
+ const portStr = formData.get("port");
57
+ const autoStart = formData.get("autoStart") === "on";
58
+ const payload = {
59
+ protocol: "HTTP"
60
+ };
61
+ if (name && name.trim()) payload.name = name.trim();
62
+ if (portStr && portStr.trim()) payload.port = Number(portStr.trim());
63
+ const createResp = await deps.apiHandler(new Request("http://localhost/imposters", {
64
+ method: "POST",
65
+ headers: {
66
+ "content-type": "application/json"
67
+ },
68
+ body: JSON.stringify(payload)
69
+ }));
70
+ if (!createResp.ok) {
71
+ const errBody = await createResp.text();
72
+ const imposters = await fetchImposters(deps.apiHandler);
73
+ return htmlResponse(adminErrorPartial(`Failed to create imposter: ${errBody}`).value + imposterListPartial(imposters).value);
74
+ }
75
+ const created = await createResp.json();
76
+ // Auto-start if requested
77
+ if (autoStart) {
78
+ await deps.apiHandler(new Request(`http://localhost/imposters/${created.id}`, {
79
+ method: "PATCH",
80
+ headers: {
81
+ "content-type": "application/json"
82
+ },
83
+ body: JSON.stringify({
84
+ status: "running"
85
+ })
86
+ }));
87
+ }
88
+ const imposters = await fetchImposters(deps.apiHandler);
89
+ return htmlResponse(imposterListPartial(imposters).value);
90
+ } catch (err) {
91
+ const imposters = await fetchImposters(deps.apiHandler);
92
+ return htmlResponse(adminErrorPartial(`Error: ${String(err)}`).value + imposterListPartial(imposters).value);
93
+ }
94
+ }
95
+ // POST /imposters/:id/start
96
+ const startMatch = path.match(/^\/imposters\/([^/]+)\/start$/);
97
+ if (method === "POST" && startMatch) {
98
+ const id = startMatch[1];
99
+ await deps.apiHandler(new Request(`http://localhost/imposters/${id}`, {
100
+ method: "PATCH",
101
+ headers: {
102
+ "content-type": "application/json"
103
+ },
104
+ body: JSON.stringify({
105
+ status: "running"
106
+ })
107
+ }));
108
+ // Small delay for the server to start
109
+ await new Promise(r => setTimeout(r, 100));
110
+ const imp = await fetchImposter(deps.apiHandler, id);
111
+ if (!imp) {
112
+ return htmlResponse(adminErrorPartial("Imposter not found").value, 404);
113
+ }
114
+ return htmlResponse(imposterRowPartial(imp).value);
115
+ }
116
+ // POST /imposters/:id/stop
117
+ const stopMatch = path.match(/^\/imposters\/([^/]+)\/stop$/);
118
+ if (method === "POST" && stopMatch) {
119
+ const id = stopMatch[1];
120
+ await deps.apiHandler(new Request(`http://localhost/imposters/${id}`, {
121
+ method: "PATCH",
122
+ headers: {
123
+ "content-type": "application/json"
124
+ },
125
+ body: JSON.stringify({
126
+ status: "stopped"
127
+ })
128
+ }));
129
+ await new Promise(r => setTimeout(r, 100));
130
+ const imp = await fetchImposter(deps.apiHandler, id);
131
+ if (!imp) {
132
+ return htmlResponse(adminErrorPartial("Imposter not found").value, 404);
133
+ }
134
+ return htmlResponse(imposterRowPartial(imp).value);
135
+ }
136
+ // DELETE /imposters/:id
137
+ const deleteMatch = path.match(/^\/imposters\/([^/]+)$/);
138
+ if (method === "DELETE" && deleteMatch) {
139
+ const id = deleteMatch[1];
140
+ await deps.apiHandler(new Request(`http://localhost/imposters/${id}?force=true`, {
141
+ method: "DELETE"
142
+ }));
143
+ const imposters = await fetchImposters(deps.apiHandler);
144
+ return htmlResponse(imposterListPartial(imposters).value);
145
+ }
146
+ return null;
147
+ };
148
+ //# sourceMappingURL=AdminUiRouter.js.map