@qase/mcp-server 1.1.8 → 2.0.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 (284) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +75 -542
  3. package/build/auth/client-context.d.ts +12 -0
  4. package/build/auth/client-context.d.ts.map +1 -0
  5. package/build/auth/client-context.js +12 -0
  6. package/build/auth/client-context.js.map +1 -0
  7. package/build/auth/jwks-verifier.d.ts +15 -0
  8. package/build/auth/jwks-verifier.d.ts.map +1 -0
  9. package/build/auth/jwks-verifier.js +31 -0
  10. package/build/auth/jwks-verifier.js.map +1 -0
  11. package/build/auth/mcp-guard.d.ts +15 -0
  12. package/build/auth/mcp-guard.d.ts.map +1 -0
  13. package/build/auth/mcp-guard.js +44 -0
  14. package/build/auth/mcp-guard.js.map +1 -0
  15. package/build/auth/oauth-config.d.ts +40 -0
  16. package/build/auth/oauth-config.d.ts.map +1 -0
  17. package/build/auth/oauth-config.js +34 -0
  18. package/build/auth/oauth-config.js.map +1 -0
  19. package/build/auth/proxy-provider.d.ts +31 -0
  20. package/build/auth/proxy-provider.d.ts.map +1 -0
  21. package/build/auth/proxy-provider.js +87 -0
  22. package/build/auth/proxy-provider.js.map +1 -0
  23. package/build/auth/token-type.d.ts +7 -0
  24. package/build/auth/token-type.d.ts.map +1 -0
  25. package/build/auth/token-type.js +10 -0
  26. package/build/auth/token-type.js.map +1 -0
  27. package/build/cache/circuit-breaker.d.ts +33 -0
  28. package/build/cache/circuit-breaker.d.ts.map +1 -0
  29. package/build/cache/circuit-breaker.js +68 -0
  30. package/build/cache/circuit-breaker.js.map +1 -0
  31. package/build/cache/index.d.ts +24 -0
  32. package/build/cache/index.d.ts.map +1 -0
  33. package/build/cache/index.js +86 -0
  34. package/build/cache/index.js.map +1 -0
  35. package/build/cache/keys.d.ts +25 -0
  36. package/build/cache/keys.d.ts.map +1 -0
  37. package/build/cache/keys.js +36 -0
  38. package/build/cache/keys.js.map +1 -0
  39. package/build/cache/layered.d.ts +31 -0
  40. package/build/cache/layered.d.ts.map +1 -0
  41. package/build/cache/layered.js +88 -0
  42. package/build/cache/layered.js.map +1 -0
  43. package/build/cache/memory.d.ts +32 -0
  44. package/build/cache/memory.d.ts.map +1 -0
  45. package/build/cache/memory.js +108 -0
  46. package/build/cache/memory.js.map +1 -0
  47. package/build/cache/metrics.d.ts +31 -0
  48. package/build/cache/metrics.d.ts.map +1 -0
  49. package/build/cache/metrics.js +95 -0
  50. package/build/cache/metrics.js.map +1 -0
  51. package/build/cache/prom-format.d.ts +7 -0
  52. package/build/cache/prom-format.d.ts.map +1 -0
  53. package/build/cache/prom-format.js +16 -0
  54. package/build/cache/prom-format.js.map +1 -0
  55. package/build/cache/redis-bus.d.ts +29 -0
  56. package/build/cache/redis-bus.d.ts.map +1 -0
  57. package/build/cache/redis-bus.js +50 -0
  58. package/build/cache/redis-bus.js.map +1 -0
  59. package/build/cache/redis.d.ts +32 -0
  60. package/build/cache/redis.d.ts.map +1 -0
  61. package/build/cache/redis.js +89 -0
  62. package/build/cache/redis.js.map +1 -0
  63. package/build/cache/types.d.ts +38 -0
  64. package/build/cache/types.d.ts.map +1 -0
  65. package/build/cache/types.js +2 -0
  66. package/build/cache/types.js.map +1 -0
  67. package/build/client/index.d.ts +10 -3
  68. package/build/client/index.d.ts.map +1 -1
  69. package/build/client/index.js +75 -50
  70. package/build/client/index.js.map +1 -1
  71. package/build/http/agent.d.ts +16 -0
  72. package/build/http/agent.d.ts.map +1 -0
  73. package/build/http/agent.js +16 -0
  74. package/build/http/agent.js.map +1 -0
  75. package/build/http/dedupe.d.ts +14 -0
  76. package/build/http/dedupe.d.ts.map +1 -0
  77. package/build/http/dedupe.js +69 -0
  78. package/build/http/dedupe.js.map +1 -0
  79. package/build/http/index.d.ts +6 -0
  80. package/build/http/index.d.ts.map +1 -0
  81. package/build/http/index.js +4 -0
  82. package/build/http/index.js.map +1 -0
  83. package/build/http/retry.d.ts +18 -0
  84. package/build/http/retry.d.ts.map +1 -0
  85. package/build/http/retry.js +52 -0
  86. package/build/http/retry.js.map +1 -0
  87. package/build/index.d.ts +1 -18
  88. package/build/index.d.ts.map +1 -1
  89. package/build/index.js +95 -63
  90. package/build/index.js.map +1 -1
  91. package/build/operations-v2/composites/ci-report.d.ts +2 -0
  92. package/build/operations-v2/composites/ci-report.d.ts.map +1 -0
  93. package/build/operations-v2/composites/ci-report.js +99 -0
  94. package/build/operations-v2/composites/ci-report.js.map +1 -0
  95. package/build/operations-v2/composites/regression-run.d.ts +2 -0
  96. package/build/operations-v2/composites/regression-run.d.ts.map +1 -0
  97. package/build/operations-v2/composites/regression-run.js +81 -0
  98. package/build/operations-v2/composites/regression-run.js.map +1 -0
  99. package/build/operations-v2/composites/triage-defect.d.ts +2 -0
  100. package/build/operations-v2/composites/triage-defect.d.ts.map +1 -0
  101. package/build/operations-v2/composites/triage-defect.js +67 -0
  102. package/build/operations-v2/composites/triage-defect.js.map +1 -0
  103. package/build/operations-v2/escape/api.d.ts +2 -0
  104. package/build/operations-v2/escape/api.d.ts.map +1 -0
  105. package/build/operations-v2/escape/api.js +34 -0
  106. package/build/operations-v2/escape/api.js.map +1 -0
  107. package/build/operations-v2/index.d.ts +19 -0
  108. package/build/operations-v2/index.d.ts.map +1 -0
  109. package/build/operations-v2/index.js +25 -0
  110. package/build/operations-v2/index.js.map +1 -0
  111. package/build/operations-v2/meta/discover.d.ts +9 -0
  112. package/build/operations-v2/meta/discover.d.ts.map +1 -0
  113. package/build/operations-v2/meta/discover.js +76 -0
  114. package/build/operations-v2/meta/discover.js.map +1 -0
  115. package/build/{operations/search.d.ts → operations-v2/qql/index.d.ts} +1 -1
  116. package/build/operations-v2/qql/index.d.ts.map +1 -0
  117. package/build/{operations/search.js → operations-v2/qql/index.js} +34 -9
  118. package/build/operations-v2/qql/index.js.map +1 -0
  119. package/build/operations-v2/read/get.d.ts +2 -0
  120. package/build/operations-v2/read/get.d.ts.map +1 -0
  121. package/build/operations-v2/read/get.js +91 -0
  122. package/build/operations-v2/read/get.js.map +1 -0
  123. package/build/operations-v2/read/project-context.d.ts +2 -0
  124. package/build/operations-v2/read/project-context.d.ts.map +1 -0
  125. package/build/operations-v2/read/project-context.js +102 -0
  126. package/build/operations-v2/read/project-context.js.map +1 -0
  127. package/build/operations-v2/write/attachments.d.ts +2 -0
  128. package/build/operations-v2/write/attachments.d.ts.map +1 -0
  129. package/build/operations-v2/write/attachments.js +58 -0
  130. package/build/operations-v2/write/attachments.js.map +1 -0
  131. package/build/operations-v2/write/cases.d.ts +2 -0
  132. package/build/operations-v2/write/cases.d.ts.map +1 -0
  133. package/build/operations-v2/write/cases.js +121 -0
  134. package/build/operations-v2/write/cases.js.map +1 -0
  135. package/build/operations-v2/write/defects.d.ts +2 -0
  136. package/build/operations-v2/write/defects.d.ts.map +1 -0
  137. package/build/operations-v2/write/defects.js +81 -0
  138. package/build/operations-v2/write/defects.js.map +1 -0
  139. package/build/operations-v2/write/environments.d.ts +2 -0
  140. package/build/operations-v2/write/environments.d.ts.map +1 -0
  141. package/build/operations-v2/write/environments.js +56 -0
  142. package/build/operations-v2/write/environments.js.map +1 -0
  143. package/build/operations-v2/write/milestones.d.ts +2 -0
  144. package/build/operations-v2/write/milestones.d.ts.map +1 -0
  145. package/build/operations-v2/write/milestones.js +56 -0
  146. package/build/operations-v2/write/milestones.js.map +1 -0
  147. package/build/operations-v2/write/plans.d.ts +2 -0
  148. package/build/operations-v2/write/plans.d.ts.map +1 -0
  149. package/build/operations-v2/write/plans.js +55 -0
  150. package/build/operations-v2/write/plans.js.map +1 -0
  151. package/build/operations-v2/write/results.d.ts +2 -0
  152. package/build/operations-v2/write/results.d.ts.map +1 -0
  153. package/build/operations-v2/write/results.js +72 -0
  154. package/build/operations-v2/write/results.js.map +1 -0
  155. package/build/operations-v2/write/runs.d.ts +2 -0
  156. package/build/operations-v2/write/runs.d.ts.map +1 -0
  157. package/build/operations-v2/write/runs.js +84 -0
  158. package/build/operations-v2/write/runs.js.map +1 -0
  159. package/build/operations-v2/write/shared-steps.d.ts +2 -0
  160. package/build/operations-v2/write/shared-steps.d.ts.map +1 -0
  161. package/build/operations-v2/write/shared-steps.js +60 -0
  162. package/build/operations-v2/write/shared-steps.js.map +1 -0
  163. package/build/operations-v2/write/suites.d.ts +2 -0
  164. package/build/operations-v2/write/suites.d.ts.map +1 -0
  165. package/build/operations-v2/write/suites.js +63 -0
  166. package/build/operations-v2/write/suites.js.map +1 -0
  167. package/build/prompts/index.d.ts +31 -0
  168. package/build/prompts/index.d.ts.map +1 -0
  169. package/build/prompts/index.js +229 -0
  170. package/build/prompts/index.js.map +1 -0
  171. package/build/transports/sse.d.ts.map +1 -1
  172. package/build/transports/sse.js +6 -0
  173. package/build/transports/sse.js.map +1 -1
  174. package/build/transports/streamableHttp.d.ts +6 -1
  175. package/build/transports/streamableHttp.d.ts.map +1 -1
  176. package/build/transports/streamableHttp.js +128 -16
  177. package/build/transports/streamableHttp.js.map +1 -1
  178. package/build/utils/auth-context.d.ts +8 -0
  179. package/build/utils/auth-context.d.ts.map +1 -1
  180. package/build/utils/auth-context.js +18 -0
  181. package/build/utils/auth-context.js.map +1 -1
  182. package/build/utils/case-enums.d.ts +5 -3
  183. package/build/utils/case-enums.d.ts.map +1 -1
  184. package/build/utils/case-enums.js +77 -59
  185. package/build/utils/case-enums.js.map +1 -1
  186. package/build/utils/output-schemas.d.ts +16 -0
  187. package/build/utils/output-schemas.d.ts.map +1 -0
  188. package/build/utils/output-schemas.js +82 -0
  189. package/build/utils/output-schemas.js.map +1 -0
  190. package/build/utils/registry.d.ts +42 -9
  191. package/build/utils/registry.d.ts.map +1 -1
  192. package/build/utils/registry.js +64 -11
  193. package/build/utils/registry.js.map +1 -1
  194. package/build/utils/response-shape.d.ts +23 -0
  195. package/build/utils/response-shape.d.ts.map +1 -0
  196. package/build/utils/response-shape.js +73 -0
  197. package/build/utils/response-shape.js.map +1 -0
  198. package/build/utils/rich-response.d.ts +58 -0
  199. package/build/utils/rich-response.d.ts.map +1 -0
  200. package/build/utils/rich-response.js +93 -0
  201. package/build/utils/rich-response.js.map +1 -0
  202. package/build/utils/server-context.d.ts +65 -0
  203. package/build/utils/server-context.d.ts.map +1 -0
  204. package/build/utils/server-context.js +67 -0
  205. package/build/utils/server-context.js.map +1 -0
  206. package/build/version.d.ts +1 -1
  207. package/build/version.js +1 -1
  208. package/docs/connect.md +81 -0
  209. package/docs/migration.md +351 -0
  210. package/docs/self-run.md +270 -0
  211. package/docs/tools.md +109 -0
  212. package/docs/troubleshooting.md +144 -0
  213. package/package.json +11 -2
  214. package/server.json +8 -2
  215. package/build/operations/attachments.d.ts +0 -8
  216. package/build/operations/attachments.d.ts.map +0 -1
  217. package/build/operations/attachments.js +0 -146
  218. package/build/operations/attachments.js.map +0 -1
  219. package/build/operations/authors.d.ts +0 -8
  220. package/build/operations/authors.d.ts.map +0 -1
  221. package/build/operations/authors.js +0 -70
  222. package/build/operations/authors.js.map +0 -1
  223. package/build/operations/cases.d.ts +0 -8
  224. package/build/operations/cases.d.ts.map +0 -1
  225. package/build/operations/cases.js +0 -370
  226. package/build/operations/cases.js.map +0 -1
  227. package/build/operations/configurations.d.ts +0 -10
  228. package/build/operations/configurations.d.ts.map +0 -1
  229. package/build/operations/configurations.js +0 -125
  230. package/build/operations/configurations.js.map +0 -1
  231. package/build/operations/custom-fields.d.ts +0 -8
  232. package/build/operations/custom-fields.d.ts.map +0 -1
  233. package/build/operations/custom-fields.js +0 -172
  234. package/build/operations/custom-fields.js.map +0 -1
  235. package/build/operations/defects.d.ts +0 -8
  236. package/build/operations/defects.d.ts.map +0 -1
  237. package/build/operations/defects.js +0 -256
  238. package/build/operations/defects.js.map +0 -1
  239. package/build/operations/environments.d.ts +0 -8
  240. package/build/operations/environments.d.ts.map +0 -1
  241. package/build/operations/environments.js +0 -154
  242. package/build/operations/environments.js.map +0 -1
  243. package/build/operations/milestones.d.ts +0 -8
  244. package/build/operations/milestones.d.ts.map +0 -1
  245. package/build/operations/milestones.js +0 -155
  246. package/build/operations/milestones.js.map +0 -1
  247. package/build/operations/plans.d.ts +0 -8
  248. package/build/operations/plans.d.ts.map +0 -1
  249. package/build/operations/plans.js +0 -158
  250. package/build/operations/plans.js.map +0 -1
  251. package/build/operations/projects.d.ts +0 -8
  252. package/build/operations/projects.d.ts.map +0 -1
  253. package/build/operations/projects.js +0 -192
  254. package/build/operations/projects.js.map +0 -1
  255. package/build/operations/results.d.ts +0 -8
  256. package/build/operations/results.d.ts.map +0 -1
  257. package/build/operations/results.js +0 -214
  258. package/build/operations/results.js.map +0 -1
  259. package/build/operations/runs.d.ts +0 -8
  260. package/build/operations/runs.d.ts.map +0 -1
  261. package/build/operations/runs.js +0 -224
  262. package/build/operations/runs.js.map +0 -1
  263. package/build/operations/search.d.ts.map +0 -1
  264. package/build/operations/search.js.map +0 -1
  265. package/build/operations/shared-parameters.d.ts +0 -10
  266. package/build/operations/shared-parameters.d.ts.map +0 -1
  267. package/build/operations/shared-parameters.js +0 -93
  268. package/build/operations/shared-parameters.js.map +0 -1
  269. package/build/operations/shared-steps.d.ts +0 -8
  270. package/build/operations/shared-steps.d.ts.map +0 -1
  271. package/build/operations/shared-steps.js +0 -160
  272. package/build/operations/shared-steps.js.map +0 -1
  273. package/build/operations/suites.d.ts +0 -8
  274. package/build/operations/suites.d.ts.map +0 -1
  275. package/build/operations/suites.js +0 -169
  276. package/build/operations/suites.js.map +0 -1
  277. package/build/operations/system-fields.d.ts +0 -10
  278. package/build/operations/system-fields.d.ts.map +0 -1
  279. package/build/operations/system-fields.js +0 -47
  280. package/build/operations/system-fields.js.map +0 -1
  281. package/build/operations/users.d.ts +0 -10
  282. package/build/operations/users.d.ts.map +0 -1
  283. package/build/operations/users.js +0 -78
  284. package/build/operations/users.js.map +0 -1
@@ -0,0 +1,32 @@
1
+ import { CacheBackend } from './types.js';
2
+ import { CircuitBreaker } from './circuit-breaker.js';
3
+ export interface RedisLikeClient {
4
+ get(key: string): Promise<string | null>;
5
+ set(key: string, value: string, mode: 'PX', ttlMs: number): Promise<'OK' | null>;
6
+ del(...keys: string[]): Promise<number>;
7
+ scan(cursor: string, matchKey: 'MATCH', pattern: string, countKey: 'COUNT', count: number): Promise<[string, string[]]>;
8
+ unlink(...keys: string[]): Promise<number>;
9
+ quit(): Promise<'OK'>;
10
+ }
11
+ export interface RedisCacheOptions {
12
+ circuitBreaker?: CircuitBreaker;
13
+ }
14
+ /**
15
+ * Redis-backed CacheBackend with graceful degradation.
16
+ *
17
+ * All upstream calls run through an optional circuit breaker. On any failure
18
+ * the breaker records it, the qase_mcp_cache_errors_total{tier="l2"} counter
19
+ * increments, and the read path returns undefined (miss). Write paths swallow
20
+ * errors so the caller is never blocked on a Redis outage.
21
+ */
22
+ export declare class RedisCache implements CacheBackend {
23
+ private readonly client;
24
+ private readonly cb;
25
+ constructor(client: RedisLikeClient, opts?: RedisCacheOptions);
26
+ get<T>(key: string): Promise<T | undefined>;
27
+ set<T>(key: string, value: T, ttlMs: number): Promise<void>;
28
+ delete(key: string): Promise<void>;
29
+ deleteByPrefix(prefix: string): Promise<void>;
30
+ close(): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/cache/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACjF,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CACF,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,qBAAa,UAAW,YAAW,YAAY;IAI3C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;gBAGjB,MAAM,EAAE,eAAe,EACxC,IAAI,GAAE,iBAAsB;IAiBxB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAqB3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3D,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
@@ -0,0 +1,89 @@
1
+ import { CircuitBreaker } from './circuit-breaker.js';
2
+ import { getMetrics } from './metrics.js';
3
+ /**
4
+ * Redis-backed CacheBackend with graceful degradation.
5
+ *
6
+ * All upstream calls run through an optional circuit breaker. On any failure
7
+ * the breaker records it, the qase_mcp_cache_errors_total{tier="l2"} counter
8
+ * increments, and the read path returns undefined (miss). Write paths swallow
9
+ * errors so the caller is never blocked on a Redis outage.
10
+ */
11
+ export class RedisCache {
12
+ client;
13
+ cb;
14
+ constructor(client, opts = {}) {
15
+ this.client = client;
16
+ this.cb =
17
+ opts.circuitBreaker ??
18
+ new CircuitBreaker({
19
+ name: 'redis',
20
+ failureThreshold: 5,
21
+ openDurationMs: 30_000,
22
+ onStateChange: (s) => getMetrics().setGauge('qase_mcp_circuit_breaker_state', { name: 'redis' }, s === 'closed' ? 0 : s === 'half_open' ? 1 : 2),
23
+ });
24
+ }
25
+ async get(key) {
26
+ try {
27
+ const raw = await this.cb.exec(() => this.client.get(key));
28
+ if (raw === null) {
29
+ getMetrics().incCounter('qase_mcp_cache_misses_total', { tier: 'l2' });
30
+ return undefined;
31
+ }
32
+ try {
33
+ const v = JSON.parse(raw);
34
+ getMetrics().incCounter('qase_mcp_cache_hits_total', { tier: 'l2' });
35
+ return v;
36
+ }
37
+ catch {
38
+ getMetrics().incCounter('qase_mcp_cache_misses_total', { tier: 'l2' });
39
+ return undefined;
40
+ }
41
+ }
42
+ catch {
43
+ getMetrics().incCounter('qase_mcp_cache_errors_total', { tier: 'l2' });
44
+ return undefined;
45
+ }
46
+ }
47
+ async set(key, value, ttlMs) {
48
+ try {
49
+ await this.cb.exec(() => this.client.set(key, JSON.stringify(value), 'PX', ttlMs));
50
+ }
51
+ catch {
52
+ getMetrics().incCounter('qase_mcp_cache_errors_total', { tier: 'l2' });
53
+ }
54
+ }
55
+ async delete(key) {
56
+ try {
57
+ await this.cb.exec(() => this.client.del(key).then(() => undefined));
58
+ }
59
+ catch {
60
+ getMetrics().incCounter('qase_mcp_cache_errors_total', { tier: 'l2' });
61
+ }
62
+ }
63
+ async deleteByPrefix(prefix) {
64
+ try {
65
+ await this.cb.exec(async () => {
66
+ const pattern = `${prefix}*`;
67
+ let cursor = '0';
68
+ do {
69
+ const [next, keys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 200);
70
+ if (keys.length > 0)
71
+ await this.client.unlink(...keys);
72
+ cursor = next;
73
+ } while (cursor !== '0');
74
+ });
75
+ }
76
+ catch {
77
+ getMetrics().incCounter('qase_mcp_cache_errors_total', { tier: 'l2' });
78
+ }
79
+ }
80
+ async close() {
81
+ try {
82
+ await this.client.quit();
83
+ }
84
+ catch {
85
+ // best-effort on shutdown
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/cache/redis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Cache abstraction. Implementations: InMemoryCache (Plan 1),
3
+ * LayeredCache wrapping an optional RedisCache (Plan 2).
4
+ */
5
+ export interface CacheBackend {
6
+ /**
7
+ * Look up a cached value. Returns undefined on miss or expiration.
8
+ * Must never cross tenant boundaries — all isolation happens through the key.
9
+ */
10
+ get<T>(key: string): Promise<T | undefined>;
11
+ /**
12
+ * Write a value with a TTL in milliseconds. Overwrites any existing entry.
13
+ */
14
+ set<T>(key: string, value: T, ttlMs: number): Promise<void>;
15
+ /**
16
+ * Remove a single entry. Silently no-op if key is absent.
17
+ */
18
+ delete(key: string): Promise<void>;
19
+ /**
20
+ * Remove every entry whose key starts with the given prefix.
21
+ * Used for tenant-scoped invalidation and schema-version rollovers.
22
+ */
23
+ deleteByPrefix(prefix: string): Promise<void>;
24
+ /**
25
+ * Release underlying resources (timers, network connections).
26
+ */
27
+ close(): Promise<void>;
28
+ }
29
+ /**
30
+ * Cross-instance invalidation bus. Implemented in Plan 2 with Redis Pub/Sub;
31
+ * unused in Plan 1.
32
+ */
33
+ export interface InvalidationBus {
34
+ publish(prefix: string): Promise<void>;
35
+ subscribe(handler: (prefix: string) => void): Promise<void>;
36
+ close(): Promise<void>;
37
+ }
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAE5C;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5D;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,SAAS,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":""}
@@ -8,7 +8,13 @@
8
8
  * - Environment-based configuration
9
9
  */
10
10
  import { ProjectsApi, CasesApi, SuitesApi, RunsApi, ResultsApi, PlansApi, MilestonesApi, DefectsApi, EnvironmentsApi, AttachmentsApi, SharedStepsApi, AuthorsApi, CustomFieldsApi, SearchApi, ConfigurationsApi, SystemFieldsApi, UsersApi, SharedParametersApi } from 'qase-api-client';
11
- import { AxiosRequestConfig } from 'axios';
11
+ import { AxiosInstance, AxiosRequestConfig } from 'axios';
12
+ /**
13
+ * Build the User-Agent / source string sent to the Qase API. Qase uses this to
14
+ * attribute the request source. Defaults to `qase-mcp`; the hosted deployment
15
+ * sets `QASE_MCP_SOURCE=qase-mcp-hosted` to distinguish it from the self-run CLI.
16
+ */
17
+ export declare function getUserAgent(): string;
12
18
  /**
13
19
  * Configuration for the Qase API client
14
20
  */
@@ -40,7 +46,8 @@ declare class QaseApiClient {
40
46
  readonly sharedParameters: SharedParametersApi;
41
47
  private readonly token;
42
48
  private readonly host;
43
- constructor(config: ApiClientConfig);
49
+ private readonly axiosInstance;
50
+ constructor(config: ApiClientConfig, axiosInstance?: AxiosInstance);
44
51
  /**
45
52
  * Make a direct API call for endpoints not fully covered by the SDK.
46
53
  */
@@ -63,5 +70,5 @@ export declare function getApiClient(): QaseApiClient;
63
70
  * @internal
64
71
  */
65
72
  export declare function resetClientInstance(): void;
66
- export type { QaseApiClient };
73
+ export { QaseApiClient };
67
74
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,WAAW,EACX,QAAQ,EACR,SAAS,EACT,OAAO,EACP,UAAU,EACV,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,UAAU,EACV,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAc,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAOlD;;GAEG;AACH,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,cAAM,aAAa;IACjB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;IAE/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,MAAM,EAAE,eAAe;IAiCnC;;OAEG;IACG,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,CAAC,CAAC;CAenF;AAqDD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,IAAI,aAAa,CAY5C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,YAAY,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,WAAW,EACX,QAAQ,EACR,SAAS,EACT,OAAO,EACP,UAAU,EACV,QAAQ,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,UAAU,EACV,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAQjE;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;GAEG;AACH,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,cAAM,aAAa;IACjB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;IAE/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;gBAElC,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,EAAE,aAAa;IAkElE;;OAEG;IACG,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,CAAC,CAAC;CAoBnF;AA8BD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,IAAI,aAAa,CAY5C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -9,10 +9,21 @@
9
9
  */
10
10
  import { Configuration, ProjectsApi, CasesApi, SuitesApi, RunsApi, ResultsApi, PlansApi, MilestonesApi, DefectsApi, EnvironmentsApi, AttachmentsApi, SharedStepsApi, AuthorsApi, CustomFieldsApi, SearchApi, ConfigurationsApi, SystemFieldsApi, UsersApi, SharedParametersApi, } from 'qase-api-client';
11
11
  import axios from 'axios';
12
+ import { createKeepAliveAgent, attachRetry, attachInflightDedupe } from '../http/index.js';
13
+ import { isJwt } from '../auth/token-type.js';
12
14
  import FormData from 'form-data';
13
- import { requestTokenStorage } from '../utils/auth-context.js';
15
+ import { requestTokenStorage, getEffectiveToken } from '../utils/auth-context.js';
16
+ import { getServer } from '../utils/server-context.js';
14
17
  import { VERSION } from '../version.js';
15
- const USER_AGENT = `qase-mcp/${VERSION}`;
18
+ /**
19
+ * Build the User-Agent / source string sent to the Qase API. Qase uses this to
20
+ * attribute the request source. Defaults to `qase-mcp`; the hosted deployment
21
+ * sets `QASE_MCP_SOURCE=qase-mcp-hosted` to distinguish it from the self-run CLI.
22
+ */
23
+ export function getUserAgent() {
24
+ const source = process.env.QASE_MCP_SOURCE?.trim() || 'qase-mcp';
25
+ return `${source}/${VERSION}`;
26
+ }
16
27
  /**
17
28
  * Wrapper around qase-api-client that preserves the `client.resource.method()` interface.
18
29
  */
@@ -37,50 +48,82 @@ class QaseApiClient {
37
48
  sharedParameters;
38
49
  token;
39
50
  host;
40
- constructor(config) {
51
+ axiosInstance;
52
+ constructor(config, axiosInstance) {
41
53
  this.token = config.token;
42
54
  this.host = config.host;
55
+ const jwtToken = isJwt(config.token);
56
+ const agent = createKeepAliveAgent({ maxSockets: 20 });
57
+ this.axiosInstance =
58
+ axiosInstance ??
59
+ axios.create({ httpsAgent: agent, headers: { 'User-Agent': getUserAgent() } });
60
+ // For JWTs, forward verbatim as Authorization: Bearer on every request.
61
+ // Opaque tokens keep using the Qase `Token` header via Configuration.apiKey.
62
+ if (jwtToken) {
63
+ this.axiosInstance.interceptors.request.use((req) => {
64
+ req.headers = req.headers ?? {};
65
+ req.headers['Authorization'] = `Bearer ${config.token}`;
66
+ return req;
67
+ });
68
+ }
69
+ // Tag each Qase API request with the MCP client identity (which AI host/model
70
+ // is using the connector) for backend metrics. Sourced per-request from the
71
+ // MCP `initialize` clientInfo, read via serverStorage during tool execution.
72
+ this.axiosInstance.interceptors.request.use((req) => {
73
+ const client = getServer()?.getClientVersion();
74
+ if (client?.name) {
75
+ req.headers = req.headers ?? {};
76
+ req.headers['X-MCP-Client-Name'] = client.name;
77
+ if (client.version) {
78
+ req.headers['X-MCP-Client-Version'] = client.version;
79
+ }
80
+ }
81
+ return req;
82
+ });
83
+ attachRetry(this.axiosInstance);
84
+ attachInflightDedupe(this.axiosInstance);
85
+ const basePath = `${config.host}/v1`;
43
86
  const cfg = new Configuration({
44
- apiKey: config.token,
45
- basePath: `${config.host}/v1`,
87
+ ...(jwtToken ? {} : { apiKey: config.token }),
88
+ basePath,
46
89
  formDataCtor: FormData,
47
- baseOptions: {
48
- headers: { 'User-Agent': USER_AGENT },
49
- },
50
90
  });
51
- this.projects = new ProjectsApi(cfg);
52
- this.cases = new CasesApi(cfg);
53
- this.suites = new SuitesApi(cfg);
54
- this.runs = new RunsApi(cfg);
55
- this.results = new ResultsApi(cfg);
56
- this.plans = new PlansApi(cfg);
57
- this.milestones = new MilestonesApi(cfg);
58
- this.defects = new DefectsApi(cfg);
59
- this.environment = new EnvironmentsApi(cfg);
60
- this.attachments = new AttachmentsApi(cfg);
61
- this.sharedSteps = new SharedStepsApi(cfg);
62
- this.authors = new AuthorsApi(cfg);
63
- this.customFields = new CustomFieldsApi(cfg);
64
- this.search = new SearchApi(cfg);
65
- this.configurations = new ConfigurationsApi(cfg);
66
- this.systemFields = new SystemFieldsApi(cfg);
67
- this.users = new UsersApi(cfg);
68
- this.sharedParameters = new SharedParametersApi(cfg);
91
+ this.projects = new ProjectsApi(cfg, basePath, this.axiosInstance);
92
+ this.cases = new CasesApi(cfg, basePath, this.axiosInstance);
93
+ this.suites = new SuitesApi(cfg, basePath, this.axiosInstance);
94
+ this.runs = new RunsApi(cfg, basePath, this.axiosInstance);
95
+ this.results = new ResultsApi(cfg, basePath, this.axiosInstance);
96
+ this.plans = new PlansApi(cfg, basePath, this.axiosInstance);
97
+ this.milestones = new MilestonesApi(cfg, basePath, this.axiosInstance);
98
+ this.defects = new DefectsApi(cfg, basePath, this.axiosInstance);
99
+ this.environment = new EnvironmentsApi(cfg, basePath, this.axiosInstance);
100
+ this.attachments = new AttachmentsApi(cfg, basePath, this.axiosInstance);
101
+ this.sharedSteps = new SharedStepsApi(cfg, basePath, this.axiosInstance);
102
+ this.authors = new AuthorsApi(cfg, basePath, this.axiosInstance);
103
+ this.customFields = new CustomFieldsApi(cfg, basePath, this.axiosInstance);
104
+ this.search = new SearchApi(cfg, basePath, this.axiosInstance);
105
+ this.configurations = new ConfigurationsApi(cfg, basePath, this.axiosInstance);
106
+ this.systemFields = new SystemFieldsApi(cfg, basePath, this.axiosInstance);
107
+ this.users = new UsersApi(cfg, basePath, this.axiosInstance);
108
+ this.sharedParameters = new SharedParametersApi(cfg, basePath, this.axiosInstance);
69
109
  }
70
110
  /**
71
111
  * Make a direct API call for endpoints not fully covered by the SDK.
72
112
  */
73
113
  async request(path, options = {}) {
74
- const response = await axios({
114
+ const authHeaders = isJwt(this.token)
115
+ ? { Authorization: `Bearer ${this.token}` }
116
+ : { Token: this.token };
117
+ const { headers: optionHeaders, ...restOptions } = options;
118
+ const response = await this.axiosInstance.request({
75
119
  method: options.method || 'GET',
76
120
  url: `${this.host}${path}`,
77
121
  headers: {
78
- Token: this.token,
122
+ ...authHeaders,
79
123
  'Content-Type': 'application/json',
80
- 'User-Agent': USER_AGENT,
81
- ...options.headers,
124
+ ...optionHeaders,
82
125
  },
83
- ...options,
126
+ ...restOptions,
84
127
  });
85
128
  return response.data;
86
129
  }
@@ -96,25 +139,6 @@ function getHost() {
96
139
  }
97
140
  return `https://${domain}`;
98
141
  }
99
- /**
100
- * Get the effective API token for the current request.
101
- *
102
- * Priority:
103
- * 1. Per-request Bearer token from Authorization header (AsyncLocalStorage)
104
- * 2. Shared QASE_API_TOKEN environment variable
105
- */
106
- function getEffectiveToken() {
107
- const requestToken = requestTokenStorage.getStore();
108
- if (requestToken) {
109
- return requestToken;
110
- }
111
- const envToken = process.env.QASE_API_TOKEN;
112
- if (!envToken) {
113
- throw new Error('QASE_API_TOKEN environment variable is required. ' +
114
- 'Get your token from: https://app.qase.io/user/api/token');
115
- }
116
- return envToken;
117
- }
118
142
  /**
119
143
  * Get full API client config (token + host).
120
144
  */
@@ -154,4 +178,5 @@ export function getApiClient() {
154
178
  export function resetClientInstance() {
155
179
  clientInstance = null;
156
180
  }
181
+ export { QaseApiClient };
157
182
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import * as https from 'https';
2
+ export interface KeepAliveAgentOptions {
3
+ /** Max concurrent sockets per host. Default: 20. */
4
+ maxSockets?: number;
5
+ /** Idle timeout before closing an unused connection. Default: 60s. */
6
+ keepAliveMsecs?: number;
7
+ }
8
+ /**
9
+ * Create an https.Agent with connection pooling enabled.
10
+ *
11
+ * Removes the TLS handshake (~50–150ms per request) from every call after
12
+ * the first, which is the single biggest source of per-request latency when
13
+ * talking to api.qase.io.
14
+ */
15
+ export declare function createKeepAliveAgent(opts?: KeepAliveAgentOptions): https.Agent;
16
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/http/agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,qBAAqB;IACpC,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,qBAA0B,GAAG,KAAK,CAAC,KAAK,CAMlF"}
@@ -0,0 +1,16 @@
1
+ import * as https from 'https';
2
+ /**
3
+ * Create an https.Agent with connection pooling enabled.
4
+ *
5
+ * Removes the TLS handshake (~50–150ms per request) from every call after
6
+ * the first, which is the single biggest source of per-request latency when
7
+ * talking to api.qase.io.
8
+ */
9
+ export function createKeepAliveAgent(opts = {}) {
10
+ return new https.Agent({
11
+ keepAlive: true,
12
+ keepAliveMsecs: opts.keepAliveMsecs ?? 60_000,
13
+ maxSockets: opts.maxSockets ?? 20,
14
+ });
15
+ }
16
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/http/agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA8B,EAAE;IACnE,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC;QACrB,SAAS,EAAE,IAAI;QACf,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,MAAM;QAC7C,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;KAClC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { AxiosInstance } from 'axios';
2
+ /**
3
+ * Attach an in-flight deduplication adapter.
4
+ *
5
+ * When two concurrent GETs have the same URL + sorted query, the second
6
+ * caller piggy-backs on the first request's promise instead of issuing a new
7
+ * network call. Applied per-axios-instance — each tenant gets its own
8
+ * instance in `getApiClient()`, so dedup never crosses tenants.
9
+ *
10
+ * Mutating requests (POST/PATCH/PUT/DELETE) are never deduped — they are
11
+ * not safe to collapse and may have different bodies.
12
+ */
13
+ export declare function attachInflightDedupe(instance: AxiosInstance): void;
14
+ //# sourceMappingURL=dedupe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe.d.ts","sourceRoot":"","sources":["../../src/http/dedupe.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,aAAa,EAAqC,MAAM,OAAO,CAAC;AAEhF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAwClE"}
@@ -0,0 +1,69 @@
1
+ import axios from 'axios';
2
+ /**
3
+ * Attach an in-flight deduplication adapter.
4
+ *
5
+ * When two concurrent GETs have the same URL + sorted query, the second
6
+ * caller piggy-backs on the first request's promise instead of issuing a new
7
+ * network call. Applied per-axios-instance — each tenant gets its own
8
+ * instance in `getApiClient()`, so dedup never crosses tenants.
9
+ *
10
+ * Mutating requests (POST/PATCH/PUT/DELETE) are never deduped — they are
11
+ * not safe to collapse and may have different bodies.
12
+ */
13
+ export function attachInflightDedupe(instance) {
14
+ const inflight = new Map();
15
+ // Capture whatever adapter was set on the instance at attach time.
16
+ // - If MockAdapter is installed first → capturedAdapter is the mock function.
17
+ // - If nothing was set (fresh axios.create()) → capturedAdapter is undefined;
18
+ // we fall back to axios's built-in http adapter via getAdapter.
19
+ const capturedAdapter = instance.defaults.adapter;
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ let resolvedAdapter;
22
+ if (typeof capturedAdapter === 'function') {
23
+ resolvedAdapter = capturedAdapter;
24
+ }
25
+ else {
26
+ // axios ≥1.7 exposes getAdapter('http') which returns the actual function.
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ resolvedAdapter = axios.getAdapter?.('http');
29
+ if (typeof resolvedAdapter !== 'function') {
30
+ // Last-resort fallback: skip dedup rather than crash the server.
31
+ console.error('[dedupe] WARNING: could not resolve HTTP adapter; in-flight deduplication disabled.');
32
+ return;
33
+ }
34
+ }
35
+ instance.defaults.adapter = (config) => {
36
+ if (!isDedupable(config)) {
37
+ return resolvedAdapter(config);
38
+ }
39
+ const key = dedupeKey(config);
40
+ const existing = inflight.get(key);
41
+ if (existing)
42
+ return existing;
43
+ const promise = resolvedAdapter(config).finally(() => {
44
+ inflight.delete(key);
45
+ });
46
+ inflight.set(key, promise);
47
+ return promise;
48
+ };
49
+ }
50
+ function isDedupable(config) {
51
+ const method = (config.method ?? 'get').toLowerCase();
52
+ return method === 'get' || method === 'head';
53
+ }
54
+ function dedupeKey(config) {
55
+ const url = config.url ?? '';
56
+ const base = config.baseURL ?? '';
57
+ const params = config.params ? stableStringify(config.params) : '';
58
+ return `${config.method ?? 'get'}|${base}|${url}|${params}`;
59
+ }
60
+ function stableStringify(obj) {
61
+ if (obj === null || typeof obj !== 'object')
62
+ return JSON.stringify(obj);
63
+ if (Array.isArray(obj))
64
+ return `[${obj.map(stableStringify).join(',')}]`;
65
+ const record = obj;
66
+ const keys = Object.keys(record).sort();
67
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(record[k])}`).join(',')}}`;
68
+ }
69
+ //# sourceMappingURL=dedupe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../../src/http/dedupe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { createKeepAliveAgent } from './agent.js';
2
+ export type { KeepAliveAgentOptions } from './agent.js';
3
+ export { attachRetry } from './retry.js';
4
+ export type { RetryOptions } from './retry.js';
5
+ export { attachInflightDedupe } from './dedupe.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { createKeepAliveAgent } from './agent.js';
2
+ export { attachRetry } from './retry.js';
3
+ export { attachInflightDedupe } from './dedupe.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { AxiosInstance } from 'axios';
2
+ export interface RetryOptions {
3
+ /** Maximum retry attempts (does not count the initial attempt). Default: 3. */
4
+ maxRetries?: number;
5
+ /** Base delay for exponential backoff in ms. Default: 200. */
6
+ baseDelayMs?: number;
7
+ /** Max jitter in ms added to each backoff delay. Default: 100. */
8
+ maxJitterMs?: number;
9
+ }
10
+ /**
11
+ * Attach a retry interceptor with jittered exponential backoff.
12
+ *
13
+ * Policy (from ADR-0001, Decision → Special Mentions → Infrastructure):
14
+ * - Idempotent (GET/HEAD/OPTIONS/DELETE): retry 429/502/503/504 + network errors
15
+ * - Mutating (POST/PATCH/PUT): retry only 429 + pre-send timeouts
16
+ */
17
+ export declare function attachRetry(instance: AxiosInstance, opts?: RetryOptions): void;
18
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/http/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkC,MAAM,OAAO,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAWD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,GAAE,YAAiB,GAAG,IAAI,CAqBlF"}