@copilotkit/aimock 1.42.1 → 1.44.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 (442) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +65 -0
  4. package/README.md +108 -16
  5. package/dist/agui-handler.d.ts.map +1 -1
  6. package/dist/agui-mock.cjs +1 -1
  7. package/dist/agui-mock.cjs.map +1 -1
  8. package/dist/agui-mock.d.cts.map +1 -1
  9. package/dist/agui-mock.d.ts.map +1 -1
  10. package/dist/agui-mock.js +1 -1
  11. package/dist/agui-mock.js.map +1 -1
  12. package/dist/agui-recorder.cjs +33 -11
  13. package/dist/agui-recorder.cjs.map +1 -1
  14. package/dist/agui-recorder.d.cts +10 -1
  15. package/dist/agui-recorder.d.cts.map +1 -1
  16. package/dist/agui-recorder.d.ts +10 -1
  17. package/dist/agui-recorder.d.ts.map +1 -1
  18. package/dist/agui-recorder.js +33 -11
  19. package/dist/agui-recorder.js.map +1 -1
  20. package/dist/agui-types.d.cts +1 -0
  21. package/dist/agui-types.d.cts.map +1 -1
  22. package/dist/agui-types.d.ts +1 -0
  23. package/dist/agui-types.d.ts.map +1 -1
  24. package/dist/aimock-cli.cjs +38 -10
  25. package/dist/aimock-cli.cjs.map +1 -1
  26. package/dist/aimock-cli.d.cts +5 -0
  27. package/dist/aimock-cli.d.cts.map +1 -1
  28. package/dist/aimock-cli.d.ts +5 -0
  29. package/dist/aimock-cli.d.ts.map +1 -1
  30. package/dist/aimock-cli.js +38 -10
  31. package/dist/aimock-cli.js.map +1 -1
  32. package/dist/batches.cjs +458 -0
  33. package/dist/batches.cjs.map +1 -0
  34. package/dist/batches.d.cts +57 -0
  35. package/dist/batches.d.cts.map +1 -0
  36. package/dist/batches.d.ts +57 -0
  37. package/dist/batches.d.ts.map +1 -0
  38. package/dist/batches.js +453 -0
  39. package/dist/batches.js.map +1 -0
  40. package/dist/bedrock-converse.cjs +44 -12
  41. package/dist/bedrock-converse.cjs.map +1 -1
  42. package/dist/bedrock-converse.d.cts.map +1 -1
  43. package/dist/bedrock-converse.d.ts.map +1 -1
  44. package/dist/bedrock-converse.js +46 -14
  45. package/dist/bedrock-converse.js.map +1 -1
  46. package/dist/bedrock.cjs +10 -8
  47. package/dist/bedrock.cjs.map +1 -1
  48. package/dist/bedrock.d.cts.map +1 -1
  49. package/dist/bedrock.d.ts.map +1 -1
  50. package/dist/bedrock.js +12 -10
  51. package/dist/bedrock.js.map +1 -1
  52. package/dist/byteplus-video.cjs +3 -3
  53. package/dist/byteplus-video.cjs.map +1 -1
  54. package/dist/byteplus-video.js +4 -4
  55. package/dist/byteplus-video.js.map +1 -1
  56. package/dist/chaos.cjs +625 -72
  57. package/dist/chaos.cjs.map +1 -1
  58. package/dist/chaos.d.cts +164 -7
  59. package/dist/chaos.d.cts.map +1 -1
  60. package/dist/chaos.d.ts +164 -7
  61. package/dist/chaos.d.ts.map +1 -1
  62. package/dist/chaos.js +616 -74
  63. package/dist/chaos.js.map +1 -1
  64. package/dist/cli.cjs +131 -30
  65. package/dist/cli.cjs.map +1 -1
  66. package/dist/cli.js +132 -31
  67. package/dist/cli.js.map +1 -1
  68. package/dist/cohere.cjs +37 -9
  69. package/dist/cohere.cjs.map +1 -1
  70. package/dist/cohere.d.cts.map +1 -1
  71. package/dist/cohere.d.ts.map +1 -1
  72. package/dist/cohere.js +39 -11
  73. package/dist/cohere.js.map +1 -1
  74. package/dist/config-loader.cjs +1 -1
  75. package/dist/config-loader.js +1 -1
  76. package/dist/constants.cjs +8 -0
  77. package/dist/constants.cjs.map +1 -1
  78. package/dist/constants.d.cts +6 -2
  79. package/dist/constants.d.ts +6 -2
  80. package/dist/constants.js +8 -1
  81. package/dist/constants.js.map +1 -1
  82. package/dist/convert.cjs +1 -1
  83. package/dist/convert.cjs.map +1 -1
  84. package/dist/convert.js +1 -1
  85. package/dist/convert.js.map +1 -1
  86. package/dist/echo-text.cjs +65 -0
  87. package/dist/echo-text.cjs.map +1 -0
  88. package/dist/echo-text.d.cts +22 -0
  89. package/dist/echo-text.d.cts.map +1 -0
  90. package/dist/echo-text.d.ts +22 -0
  91. package/dist/echo-text.d.ts.map +1 -0
  92. package/dist/echo-text.js +65 -0
  93. package/dist/echo-text.js.map +1 -0
  94. package/dist/elevenlabs-audio.cjs +3 -3
  95. package/dist/elevenlabs-audio.cjs.map +1 -1
  96. package/dist/elevenlabs-audio.js +4 -4
  97. package/dist/elevenlabs-audio.js.map +1 -1
  98. package/dist/elevenlabs-voice.cjs +1053 -0
  99. package/dist/elevenlabs-voice.cjs.map +1 -0
  100. package/dist/elevenlabs-voice.d.cts +72 -0
  101. package/dist/elevenlabs-voice.d.cts.map +1 -0
  102. package/dist/elevenlabs-voice.d.ts +72 -0
  103. package/dist/elevenlabs-voice.d.ts.map +1 -0
  104. package/dist/elevenlabs-voice.js +1048 -0
  105. package/dist/elevenlabs-voice.js.map +1 -0
  106. package/dist/embeddings.cjs +26 -5
  107. package/dist/embeddings.cjs.map +1 -1
  108. package/dist/embeddings.d.cts +1 -1
  109. package/dist/embeddings.d.cts.map +1 -1
  110. package/dist/embeddings.d.ts +1 -1
  111. package/dist/embeddings.d.ts.map +1 -1
  112. package/dist/embeddings.js +27 -6
  113. package/dist/embeddings.js.map +1 -1
  114. package/dist/fal-audio.cjs +3 -3
  115. package/dist/fal-audio.cjs.map +1 -1
  116. package/dist/fal-audio.js +4 -4
  117. package/dist/fal-audio.js.map +1 -1
  118. package/dist/fal.cjs +28 -4
  119. package/dist/fal.cjs.map +1 -1
  120. package/dist/fal.d.cts +16 -1
  121. package/dist/fal.d.cts.map +1 -1
  122. package/dist/fal.d.ts +16 -1
  123. package/dist/fal.d.ts.map +1 -1
  124. package/dist/fal.js +28 -5
  125. package/dist/fal.js.map +1 -1
  126. package/dist/files.cjs +1069 -0
  127. package/dist/files.cjs.map +1 -0
  128. package/dist/files.d.cts +68 -0
  129. package/dist/files.d.cts.map +1 -0
  130. package/dist/files.d.ts +68 -0
  131. package/dist/files.d.ts.map +1 -0
  132. package/dist/files.js +1056 -0
  133. package/dist/files.js.map +1 -0
  134. package/dist/fine-tuning.cjs +1033 -0
  135. package/dist/fine-tuning.cjs.map +1 -0
  136. package/dist/fine-tuning.d.cts +96 -0
  137. package/dist/fine-tuning.d.cts.map +1 -0
  138. package/dist/fine-tuning.d.ts +96 -0
  139. package/dist/fine-tuning.d.ts.map +1 -0
  140. package/dist/fine-tuning.js +1026 -0
  141. package/dist/fine-tuning.js.map +1 -0
  142. package/dist/fixture-loader-services.cjs +116 -0
  143. package/dist/fixture-loader-services.cjs.map +1 -0
  144. package/dist/fixture-loader-services.d.cts +48 -0
  145. package/dist/fixture-loader-services.d.cts.map +1 -0
  146. package/dist/fixture-loader-services.d.ts +48 -0
  147. package/dist/fixture-loader-services.d.ts.map +1 -0
  148. package/dist/fixture-loader-services.js +114 -0
  149. package/dist/fixture-loader-services.js.map +1 -0
  150. package/dist/fixture-loader.cjs +0 -0
  151. package/dist/fixture-loader.cjs.map +1 -1
  152. package/dist/fixture-loader.d.cts +131 -5
  153. package/dist/fixture-loader.d.cts.map +1 -1
  154. package/dist/fixture-loader.d.ts +131 -5
  155. package/dist/fixture-loader.d.ts.map +1 -1
  156. package/dist/fixture-loader.js +0 -0
  157. package/dist/fixture-loader.js.map +1 -1
  158. package/dist/gemini-embeddings.cjs +44 -4
  159. package/dist/gemini-embeddings.cjs.map +1 -1
  160. package/dist/gemini-embeddings.js +46 -6
  161. package/dist/gemini-embeddings.js.map +1 -1
  162. package/dist/gemini-interactions.cjs +51 -7
  163. package/dist/gemini-interactions.cjs.map +1 -1
  164. package/dist/gemini-interactions.d.cts.map +1 -1
  165. package/dist/gemini-interactions.d.ts.map +1 -1
  166. package/dist/gemini-interactions.js +53 -9
  167. package/dist/gemini-interactions.js.map +1 -1
  168. package/dist/gemini.cjs +19 -8
  169. package/dist/gemini.cjs.map +1 -1
  170. package/dist/gemini.d.cts.map +1 -1
  171. package/dist/gemini.d.ts.map +1 -1
  172. package/dist/gemini.js +21 -10
  173. package/dist/gemini.js.map +1 -1
  174. package/dist/grok-video.cjs +14 -14
  175. package/dist/grok-video.cjs.map +1 -1
  176. package/dist/grok-video.js +15 -15
  177. package/dist/grok-video.js.map +1 -1
  178. package/dist/helpers.cjs +497 -10
  179. package/dist/helpers.cjs.map +1 -1
  180. package/dist/helpers.d.cts +38 -2
  181. package/dist/helpers.d.cts.map +1 -1
  182. package/dist/helpers.d.ts +38 -2
  183. package/dist/helpers.d.ts.map +1 -1
  184. package/dist/helpers.js +487 -12
  185. package/dist/helpers.js.map +1 -1
  186. package/dist/images.cjs +57 -125
  187. package/dist/images.cjs.map +1 -1
  188. package/dist/images.d.cts.map +1 -1
  189. package/dist/images.d.ts.map +1 -1
  190. package/dist/images.js +58 -126
  191. package/dist/images.js.map +1 -1
  192. package/dist/index.cjs +71 -9
  193. package/dist/index.d.cts +17 -7
  194. package/dist/index.d.ts +17 -7
  195. package/dist/index.js +21 -11
  196. package/dist/jest.cjs +24 -12
  197. package/dist/jest.cjs.map +1 -1
  198. package/dist/jest.d.cts +6 -3
  199. package/dist/jest.d.cts.map +1 -1
  200. package/dist/jest.d.ts +6 -3
  201. package/dist/jest.d.ts.map +1 -1
  202. package/dist/jest.js +25 -13
  203. package/dist/jest.js.map +1 -1
  204. package/dist/journal.cjs +61 -4
  205. package/dist/journal.cjs.map +1 -1
  206. package/dist/journal.d.cts +60 -3
  207. package/dist/journal.d.cts.map +1 -1
  208. package/dist/journal.d.ts +60 -3
  209. package/dist/journal.d.ts.map +1 -1
  210. package/dist/journal.js +61 -5
  211. package/dist/journal.js.map +1 -1
  212. package/dist/live-fixture.cjs +1192 -0
  213. package/dist/live-fixture.cjs.map +1 -0
  214. package/dist/live-fixture.js +1187 -0
  215. package/dist/live-fixture.js.map +1 -0
  216. package/dist/live-recorder.cjs +256 -0
  217. package/dist/live-recorder.cjs.map +1 -0
  218. package/dist/live-recorder.js +254 -0
  219. package/dist/live-recorder.js.map +1 -0
  220. package/dist/live-replay.cjs +286 -0
  221. package/dist/live-replay.cjs.map +1 -0
  222. package/dist/live-replay.js +285 -0
  223. package/dist/live-replay.js.map +1 -0
  224. package/dist/live-sanitize.cjs +196 -0
  225. package/dist/live-sanitize.cjs.map +1 -0
  226. package/dist/live-sanitize.js +196 -0
  227. package/dist/live-sanitize.js.map +1 -0
  228. package/dist/live-types.d.cts +71 -0
  229. package/dist/live-types.d.cts.map +1 -0
  230. package/dist/live-types.d.ts +71 -0
  231. package/dist/live-types.d.ts.map +1 -0
  232. package/dist/llmock.cjs +132 -49
  233. package/dist/llmock.cjs.map +1 -1
  234. package/dist/llmock.d.cts +51 -5
  235. package/dist/llmock.d.cts.map +1 -1
  236. package/dist/llmock.d.ts +51 -5
  237. package/dist/llmock.d.ts.map +1 -1
  238. package/dist/llmock.js +133 -50
  239. package/dist/llmock.js.map +1 -1
  240. package/dist/mcp-fakes-mount.cjs +216 -0
  241. package/dist/mcp-fakes-mount.cjs.map +1 -0
  242. package/dist/mcp-fakes-mount.js +210 -0
  243. package/dist/mcp-fakes-mount.js.map +1 -0
  244. package/dist/mcp-fakes.cjs +1619 -0
  245. package/dist/mcp-fakes.cjs.map +1 -0
  246. package/dist/mcp-fakes.d.cts +101 -0
  247. package/dist/mcp-fakes.d.cts.map +1 -0
  248. package/dist/mcp-fakes.d.ts +101 -0
  249. package/dist/mcp-fakes.d.ts.map +1 -0
  250. package/dist/mcp-fakes.js +1614 -0
  251. package/dist/mcp-fakes.js.map +1 -0
  252. package/dist/mcp-handler.cjs +331 -17
  253. package/dist/mcp-handler.cjs.map +1 -1
  254. package/dist/mcp-handler.js +330 -18
  255. package/dist/mcp-handler.js.map +1 -1
  256. package/dist/mcp-mock.cjs +217 -49
  257. package/dist/mcp-mock.cjs.map +1 -1
  258. package/dist/mcp-mock.d.cts +66 -1
  259. package/dist/mcp-mock.d.cts.map +1 -1
  260. package/dist/mcp-mock.d.ts +66 -1
  261. package/dist/mcp-mock.d.ts.map +1 -1
  262. package/dist/mcp-mock.js +218 -50
  263. package/dist/mcp-mock.js.map +1 -1
  264. package/dist/mcp-stub.cjs +5 -1
  265. package/dist/mcp-stub.d.cts +3 -1
  266. package/dist/mcp-stub.d.ts +3 -1
  267. package/dist/mcp-stub.js +3 -1
  268. package/dist/mcp-types.d.cts +6 -0
  269. package/dist/mcp-types.d.ts +6 -0
  270. package/dist/message-text.cjs +192 -0
  271. package/dist/message-text.cjs.map +1 -0
  272. package/dist/message-text.d.cts +31 -0
  273. package/dist/message-text.d.cts.map +1 -0
  274. package/dist/message-text.d.ts +31 -0
  275. package/dist/message-text.d.ts.map +1 -0
  276. package/dist/message-text.js +184 -0
  277. package/dist/message-text.js.map +1 -0
  278. package/dist/messages.cjs +49 -7
  279. package/dist/messages.cjs.map +1 -1
  280. package/dist/messages.d.cts.map +1 -1
  281. package/dist/messages.d.ts.map +1 -1
  282. package/dist/messages.js +51 -9
  283. package/dist/messages.js.map +1 -1
  284. package/dist/metrics.cjs +278 -45
  285. package/dist/metrics.cjs.map +1 -1
  286. package/dist/metrics.d.cts +17 -7
  287. package/dist/metrics.d.cts.map +1 -1
  288. package/dist/metrics.d.ts +17 -7
  289. package/dist/metrics.d.ts.map +1 -1
  290. package/dist/metrics.js +270 -29
  291. package/dist/metrics.js.map +1 -1
  292. package/dist/moderation.cjs +10 -1
  293. package/dist/moderation.cjs.map +1 -1
  294. package/dist/moderation.d.cts.map +1 -1
  295. package/dist/moderation.d.ts.map +1 -1
  296. package/dist/moderation.js +10 -1
  297. package/dist/moderation.js.map +1 -1
  298. package/dist/ollama.cjs +10 -6
  299. package/dist/ollama.cjs.map +1 -1
  300. package/dist/ollama.d.cts.map +1 -1
  301. package/dist/ollama.d.ts.map +1 -1
  302. package/dist/ollama.js +11 -7
  303. package/dist/ollama.js.map +1 -1
  304. package/dist/openapi.cjs +3405 -0
  305. package/dist/openapi.cjs.map +1 -0
  306. package/dist/openapi.d.cts +30 -0
  307. package/dist/openapi.d.cts.map +1 -0
  308. package/dist/openapi.d.ts +30 -0
  309. package/dist/openapi.d.ts.map +1 -0
  310. package/dist/openapi.js +3404 -0
  311. package/dist/openapi.js.map +1 -0
  312. package/dist/openrouter-video.cjs +9 -9
  313. package/dist/openrouter-video.cjs.map +1 -1
  314. package/dist/openrouter-video.d.cts.map +1 -1
  315. package/dist/openrouter-video.d.ts.map +1 -1
  316. package/dist/openrouter-video.js +10 -10
  317. package/dist/openrouter-video.js.map +1 -1
  318. package/dist/recorder.cjs +54 -10
  319. package/dist/recorder.cjs.map +1 -1
  320. package/dist/recorder.d.cts.map +1 -1
  321. package/dist/recorder.d.ts.map +1 -1
  322. package/dist/recorder.js +52 -12
  323. package/dist/recorder.js.map +1 -1
  324. package/dist/responses.cjs +47 -7
  325. package/dist/responses.cjs.map +1 -1
  326. package/dist/responses.d.cts.map +1 -1
  327. package/dist/responses.d.ts.map +1 -1
  328. package/dist/responses.js +48 -9
  329. package/dist/responses.js.map +1 -1
  330. package/dist/route-registry.cjs +951 -0
  331. package/dist/route-registry.cjs.map +1 -0
  332. package/dist/route-registry.d.cts +33 -0
  333. package/dist/route-registry.d.cts.map +1 -0
  334. package/dist/route-registry.d.ts +33 -0
  335. package/dist/route-registry.d.ts.map +1 -0
  336. package/dist/route-registry.js +866 -0
  337. package/dist/route-registry.js.map +1 -0
  338. package/dist/router.cjs +21 -34
  339. package/dist/router.cjs.map +1 -1
  340. package/dist/router.d.cts +4 -1
  341. package/dist/router.d.cts.map +1 -1
  342. package/dist/router.d.ts +4 -1
  343. package/dist/router.d.ts.map +1 -1
  344. package/dist/router.js +21 -35
  345. package/dist/router.js.map +1 -1
  346. package/dist/server.cjs +1252 -777
  347. package/dist/server.cjs.map +1 -1
  348. package/dist/server.d.cts +5 -1
  349. package/dist/server.d.cts.map +1 -1
  350. package/dist/server.d.ts +5 -1
  351. package/dist/server.d.ts.map +1 -1
  352. package/dist/server.js +1185 -710
  353. package/dist/server.js.map +1 -1
  354. package/dist/speech.cjs +6 -4
  355. package/dist/speech.cjs.map +1 -1
  356. package/dist/speech.js +7 -5
  357. package/dist/speech.js.map +1 -1
  358. package/dist/suite.cjs +1 -1
  359. package/dist/suite.js +1 -1
  360. package/dist/transcription.cjs +6 -6
  361. package/dist/transcription.cjs.map +1 -1
  362. package/dist/transcription.d.cts.map +1 -1
  363. package/dist/transcription.d.ts.map +1 -1
  364. package/dist/transcription.js +7 -7
  365. package/dist/transcription.js.map +1 -1
  366. package/dist/types.cjs +18 -0
  367. package/dist/types.cjs.map +1 -0
  368. package/dist/types.d.cts +320 -17
  369. package/dist/types.d.cts.map +1 -1
  370. package/dist/types.d.ts +320 -17
  371. package/dist/types.d.ts.map +1 -1
  372. package/dist/types.js +17 -0
  373. package/dist/types.js.map +1 -0
  374. package/dist/validate-cli.cjs +983 -0
  375. package/dist/validate-cli.cjs.map +1 -0
  376. package/dist/validate-cli.js +982 -0
  377. package/dist/validate-cli.js.map +1 -0
  378. package/dist/vector-stores.cjs +1180 -0
  379. package/dist/vector-stores.cjs.map +1 -0
  380. package/dist/vector-stores.d.cts +106 -0
  381. package/dist/vector-stores.d.cts.map +1 -0
  382. package/dist/vector-stores.d.ts +106 -0
  383. package/dist/vector-stores.d.ts.map +1 -0
  384. package/dist/vector-stores.js +1164 -0
  385. package/dist/vector-stores.js.map +1 -0
  386. package/dist/vector-types.d.cts.map +1 -1
  387. package/dist/vector-types.d.ts.map +1 -1
  388. package/dist/veo-video.cjs +13 -13
  389. package/dist/veo-video.cjs.map +1 -1
  390. package/dist/veo-video.js +14 -14
  391. package/dist/veo-video.js.map +1 -1
  392. package/dist/video.cjs +23 -4
  393. package/dist/video.cjs.map +1 -1
  394. package/dist/video.d.cts +1 -1
  395. package/dist/video.d.cts.map +1 -1
  396. package/dist/video.d.ts +1 -1
  397. package/dist/video.d.ts.map +1 -1
  398. package/dist/video.js +24 -5
  399. package/dist/video.js.map +1 -1
  400. package/dist/vitest.cjs +23 -11
  401. package/dist/vitest.cjs.map +1 -1
  402. package/dist/vitest.d.cts +5 -2
  403. package/dist/vitest.d.cts.map +1 -1
  404. package/dist/vitest.d.ts +5 -2
  405. package/dist/vitest.d.ts.map +1 -1
  406. package/dist/vitest.js +25 -13
  407. package/dist/vitest.js.map +1 -1
  408. package/dist/watcher.cjs +2 -1
  409. package/dist/watcher.cjs.map +1 -1
  410. package/dist/watcher.js +2 -1
  411. package/dist/watcher.js.map +1 -1
  412. package/dist/ws-framing.cjs +150 -35
  413. package/dist/ws-framing.cjs.map +1 -1
  414. package/dist/ws-framing.d.cts +18 -3
  415. package/dist/ws-framing.d.cts.map +1 -1
  416. package/dist/ws-framing.d.ts +18 -3
  417. package/dist/ws-framing.d.ts.map +1 -1
  418. package/dist/ws-framing.js +151 -36
  419. package/dist/ws-framing.js.map +1 -1
  420. package/dist/ws-gemini-live.cjs +2 -2
  421. package/dist/ws-gemini-live.js +2 -2
  422. package/dist/ws-live.cjs +401 -0
  423. package/dist/ws-live.cjs.map +1 -0
  424. package/dist/ws-live.js +400 -0
  425. package/dist/ws-live.js.map +1 -0
  426. package/dist/ws-realtime.cjs +46 -2
  427. package/dist/ws-realtime.cjs.map +1 -1
  428. package/dist/ws-realtime.d.cts.map +1 -1
  429. package/dist/ws-realtime.d.ts.map +1 -1
  430. package/dist/ws-realtime.js +46 -2
  431. package/dist/ws-realtime.js.map +1 -1
  432. package/dist/ws-responses.cjs +16 -4
  433. package/dist/ws-responses.cjs.map +1 -1
  434. package/dist/ws-responses.js +16 -4
  435. package/dist/ws-responses.js.map +1 -1
  436. package/dist/ws-upstream.cjs +118 -0
  437. package/dist/ws-upstream.cjs.map +1 -0
  438. package/dist/ws-upstream.js +115 -0
  439. package/dist/ws-upstream.js.map +1 -0
  440. package/fixtures/openai-live-client.json +390 -0
  441. package/fixtures/openai-live-managed.json +709 -0
  442. package/package.json +4 -1
package/dist/helpers.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
2
2
  const require_constants = require('./constants.cjs');
3
+ const require_echo_text = require('./echo-text.cjs');
4
+ const require_message_text = require('./message-text.cjs');
3
5
  const require_model_utils = require('./model-utils.cjs');
4
6
  const require_api_key_auth = require('./api-key-auth.cjs');
5
7
  let node_crypto = require("node:crypto");
@@ -26,6 +28,37 @@ function resolveStrictMode(serverDefault, rawHeaders) {
26
28
  }
27
29
  return serverDefault ?? false;
28
30
  }
31
+ const STRICT_INTEGER_RE = /^\d+$/;
32
+ /**
33
+ * Strict decimal-integer grammar shared by the query/list parsers that grew
34
+ * their own local copy on separate branches (files `limit`, fine-tuning
35
+ * `limit`, chaos integer fields): an unsigned digit run and nothing else — no
36
+ * sign, no exponent, no radix prefix, no surrounding whitespace (callers that
37
+ * accept padded input trim before calling).
38
+ *
39
+ * Deliberately narrower than `Number()`, which reads `0x10` as 16, `1e3` as
40
+ * 1000 and strips whitespace and a leading `+`. Returns the value, or `null`
41
+ * when the text is not a safe integer literal. Range checks and error
42
+ * messages stay with the callers — this is the grammar gate only, so sharing
43
+ * it cannot change any surface's accepted range or its 400 text.
44
+ */
45
+ function parseStrictIntegerText(text) {
46
+ if (!STRICT_INTEGER_RE.test(text)) return null;
47
+ const n = Number(text);
48
+ return Number.isSafeInteger(n) ? n : null;
49
+ }
50
+ /**
51
+ * Would a fixture miss on this request have been forwarded upstream? This is
52
+ * the ONE rule behind the no-fixture chaos journal `source` label: "proxy"
53
+ * only when record mode has an upstream for THIS provider and strict mode is
54
+ * not refusing the miss first. `effectiveStrict` is the header-resolved value
55
+ * from {@link resolveStrictMode}. `record.providers` is read guarded — a JS
56
+ * caller can hand over `record: {}`.
57
+ */
58
+ function wouldProxyMiss(effectiveStrict, record, providerKey) {
59
+ if (effectiveStrict || providerKey === void 0) return false;
60
+ return Boolean(record?.providers?.[providerKey]);
61
+ }
29
62
  /**
30
63
  * Returns `true` or `false` when the X-AIMock-Strict header overrides the
31
64
  * server default, or `undefined` when it doesn't. Designed to be spread
@@ -143,6 +176,10 @@ function flattenHeaders(headers) {
143
176
  }
144
177
  return flat;
145
178
  }
179
+ /** Structural discriminator; registration performs full transcript validation. */
180
+ function isLiveResponse(value) {
181
+ return value !== null && typeof value === "object" && !Array.isArray(value) && "live" in value;
182
+ }
146
183
  function isResponseFactory(r) {
147
184
  return typeof r === "function";
148
185
  }
@@ -177,6 +214,57 @@ function normalizeFactoryResponse(raw) {
177
214
  function generateId(prefix = "chatcmpl") {
178
215
  return `${prefix}-${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
179
216
  }
217
+ /**
218
+ * Resolve the request id for this HTTP request.
219
+ *
220
+ * - When the caller sends a well-formed `X-Request-Id` (1-128 chars of
221
+ * `A-Za-z0-9-_.:`), it is echoed verbatim so distributed traces correlate.
222
+ * - Otherwise (absent, empty, too long, or illegal characters) a fresh
223
+ * `req-…` id is generated — never trust an attacker-controlled correlation
224
+ * value to be a valid log key.
225
+ *
226
+ * Returns `{ id, generated }`. The server normalizes
227
+ * `req.headers["x-request-id"]` to the resolved value, so every downstream
228
+ * `flattenHeaders` journal snapshot carries it with zero per-handler edits —
229
+ * which also means a MINTED id would otherwise ride the egress header set to
230
+ * a real provider. The server therefore passes `generated` to
231
+ * `markMintedRequestId` so `buildForwardHeaders` can drop it; a caller's own
232
+ * id still forwards verbatim.
233
+ */
234
+ function resolveRequestId(rawHeaders) {
235
+ const raw = rawHeaders["x-request-id"];
236
+ const first = Array.isArray(raw) ? raw[0] : raw;
237
+ if (typeof first === "string") {
238
+ const trimmed = first.trim();
239
+ if (trimmed.length >= 1 && trimmed.length <= 128 && /^[A-Za-z0-9\-_.:]+$/.test(trimmed)) return {
240
+ id: trimmed,
241
+ generated: false
242
+ };
243
+ }
244
+ return {
245
+ id: generateId("req"),
246
+ generated: true
247
+ };
248
+ }
249
+ /**
250
+ * Requests whose `x-request-id` aimock MINTED (the caller sent none, or sent
251
+ * an unusable one). The normalized header is indistinguishable from a
252
+ * caller-supplied one by inspection, so the provenance is tracked out-of-band
253
+ * and keyed on the request object, exactly like the egress auth marker.
254
+ */
255
+ const mintedRequestIds = /* @__PURE__ */ new WeakSet();
256
+ /** @internal Record that this request's `x-request-id` is aimock's own. */
257
+ function markMintedRequestId(req, generated) {
258
+ if (generated) mintedRequestIds.add(req);
259
+ }
260
+ /**
261
+ * @internal True when `x-request-id` on this request was minted by aimock.
262
+ * Egress paths use it to avoid transmitting an invented correlation id to a
263
+ * real provider.
264
+ */
265
+ function hasMintedRequestId(req) {
266
+ return mintedRequestIds.has(req);
267
+ }
180
268
  function generateToolCallId() {
181
269
  return `call_${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
182
270
  }
@@ -255,6 +343,24 @@ function resolveFixtureBlocks(blocks) {
255
343
  } else throw new Error(`Invalid fixture block at index ${i}: unknown type ${JSON.stringify(b.type)} (expected "text" or "toolCall")`);
256
344
  });
257
345
  }
346
+ /** Project normalized ordered blocks without changing the fixture or generating ids. */
347
+ function resolveFixtureBlockOutcome(blocks) {
348
+ const ordered = resolveFixtureBlocks(blocks);
349
+ let content = "";
350
+ const toolCalls = [];
351
+ for (const block of ordered) if (block.type === "text") content += block.text;
352
+ else toolCalls.push({
353
+ name: block.name,
354
+ arguments: block.arguments,
355
+ ...block.id !== void 0 ? { id: block.id } : {}
356
+ });
357
+ return {
358
+ ordered,
359
+ content,
360
+ toolCalls,
361
+ hasToolCalls: toolCalls.length > 0
362
+ };
363
+ }
258
364
  function isErrorResponse(r) {
259
365
  return "error" in r && r.error !== null && typeof r.error === "object" && "message" in r.error && typeof r.error.message === "string";
260
366
  }
@@ -604,7 +710,8 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
604
710
  const chunks = [];
605
711
  const fingerprint = overrides?.systemFingerprint;
606
712
  if (blocks && blocks.length > 0) {
607
- const ordered = resolveFixtureBlocks(blocks);
713
+ const outcome = resolveFixtureBlockOutcome(blocks);
714
+ const ordered = outcome.ordered;
608
715
  if (reasoning) for (let i = 0; i < reasoning.length; i += chunkSize) {
609
716
  const slice = reasoning.slice(i, i + chunkSize);
610
717
  chunks.push({
@@ -711,7 +818,7 @@ function buildContentWithToolCallsChunks(content, toolCalls, model, chunkSize, r
711
818
  index: 0,
712
819
  delta: {},
713
820
  logprobs: null,
714
- finish_reason: overrides?.finishReason ?? "tool_calls"
821
+ finish_reason: overrides?.finishReason ?? (outcome.hasToolCalls ? "tool_calls" : "stop")
715
822
  }],
716
823
  ...fingerprint !== void 0 && { system_fingerprint: fingerprint }
717
824
  });
@@ -860,7 +967,31 @@ function buildContentWithToolCallsCompletion(content, toolCalls, model, reasonin
860
967
  };
861
968
  }
862
969
  const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
863
- function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
970
+ /**
971
+ * A body read that stopped because the CLIENT sent more bytes than the route
972
+ * allows. The socket is already destroyed when this rejects, so no status line
973
+ * ever reaches the caller — but the fault is the caller's, and error arms that
974
+ * journal and log the failure need to say so. Carrying the classification on
975
+ * the error type (rather than re-matching the message text) is what lets them:
976
+ * the message is unchanged from the plain `Error` this replaced.
977
+ */
978
+ var RequestBodyTooLargeError = class extends Error {
979
+ constructor(maxBytes) {
980
+ super(`Request body exceeded size limit of ${maxBytes} bytes`);
981
+ this.maxBytes = maxBytes;
982
+ this.name = "RequestBodyTooLargeError";
983
+ }
984
+ };
985
+ /**
986
+ * Read a request body as raw bytes, preserving every octet.
987
+ *
988
+ * This is the byte-level primitive {@link readBody} is built on: routes that
989
+ * must not lose bytes (binary file uploads) take the Buffer, everything else
990
+ * keeps taking the decoded string. Splitting it this way leaves the text path
991
+ * byte-identical — `readBody` performs exactly the same `Buffer.concat(...)`
992
+ * + default (utf8) `toString()` it always did, just one call later.
993
+ */
994
+ function readBodyBuffer(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
864
995
  return new Promise((resolve, reject) => {
865
996
  const chunks = [];
866
997
  let totalBytes = 0;
@@ -871,7 +1002,7 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
871
1002
  if (totalBytes > maxBytes) {
872
1003
  settled = true;
873
1004
  req.destroy();
874
- reject(/* @__PURE__ */ new Error(`Request body exceeded size limit of ${maxBytes} bytes`));
1005
+ reject(new RequestBodyTooLargeError(maxBytes));
875
1006
  return;
876
1007
  }
877
1008
  chunks.push(chunk);
@@ -879,8 +1010,58 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
879
1010
  req.on("end", () => {
880
1011
  if (!settled) {
881
1012
  settled = true;
882
- resolve(Buffer.concat(chunks).toString());
1013
+ resolve(Buffer.concat(chunks));
1014
+ }
1015
+ });
1016
+ req.on("error", (err) => {
1017
+ if (!settled) {
1018
+ settled = true;
1019
+ reject(err);
1020
+ }
1021
+ });
1022
+ });
1023
+ }
1024
+ /**
1025
+ * Read a request body that may legitimately be over-size, without either
1026
+ * buffering it all or dropping the socket.
1027
+ *
1028
+ * {@link readBodyBuffer} answers an over-size body with `req.destroy()`: no
1029
+ * status line, no body, no CORS headers. That is the right default for routes
1030
+ * whose limit is a pure DoS bound, but it is the wrong answer for a route that
1031
+ * owes the caller a `400` describing what was wrong — the caller cannot read an
1032
+ * error it never receives. So this variant splits the two concerns:
1033
+ *
1034
+ * - `maxBytes` bounds MEMORY. Past it the buffered chunks are dropped and the
1035
+ * body is only counted, so peak retention never exceeds `maxBytes` no matter
1036
+ * how large the body is. The caller gets `buffer: null` and answers itself.
1037
+ * - `drainMaxBytes` bounds WORK, and is the only socket drop here: a body that
1038
+ * keeps coming past it is not worth draining and rejects as `readBodyBuffer`
1039
+ * would.
1040
+ */
1041
+ function readBodyBufferBounded(req, maxBytes, drainMaxBytes) {
1042
+ return new Promise((resolve, reject) => {
1043
+ let chunks = [];
1044
+ let totalBytes = 0;
1045
+ let settled = false;
1046
+ req.on("data", (chunk) => {
1047
+ if (settled) return;
1048
+ totalBytes += chunk.length;
1049
+ if (chunks !== null && totalBytes > maxBytes) chunks = null;
1050
+ if (totalBytes > drainMaxBytes) {
1051
+ settled = true;
1052
+ req.destroy();
1053
+ reject(new RequestBodyTooLargeError(drainMaxBytes));
1054
+ return;
883
1055
  }
1056
+ if (chunks !== null) chunks.push(chunk);
1057
+ });
1058
+ req.on("end", () => {
1059
+ if (settled) return;
1060
+ settled = true;
1061
+ resolve({
1062
+ buffer: chunks === null ? null : Buffer.concat(chunks),
1063
+ bytesRead: totalBytes
1064
+ });
884
1065
  });
885
1066
  req.on("error", (err) => {
886
1067
  if (!settled) {
@@ -890,6 +1071,9 @@ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
890
1071
  });
891
1072
  });
892
1073
  }
1074
+ function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
1075
+ return readBodyBuffer(req, maxBytes).then((buf) => buf.toString());
1076
+ }
893
1077
  /**
894
1078
  * Case-insensitive substring/regex match used for search, rerank, and
895
1079
  * moderation endpoints where exact casing rarely matters. String patterns
@@ -908,11 +1092,14 @@ function matchesPattern(text, pattern) {
908
1092
  return result;
909
1093
  }
910
1094
  /**
911
- * The ONE definition of "which test does this traffic belong to": the
912
- * `X-Test-Id` header wins, then `?testId=` in the query string, then
913
- * `DEFAULT_TEST_ID`. Every per-test axis (fixture match-counts, the journal
914
- * filter, chaos scoping) resolves through this, so a caller that tags one way
915
- * can never land in two different scopes.
1095
+ * Which test LLM and other HTTP-route traffic belongs to: the `X-Test-Id`
1096
+ * header (raw, not percent-decoded) wins, then `?testId=` in the query string
1097
+ * (read through `URLSearchParams`, so percent-decoded and with `+` as a
1098
+ * space), then `DEFAULT_TEST_ID`. Every per-test axis of those routes
1099
+ * (fixture match-counts, the journal filter, chaos scoping) resolves through
1100
+ * this. MCP mounts resolve the test id with {@link resolveMcpIdentity}
1101
+ * instead, which percent-decodes the header, so `X-Test-Id: a%20b` is `a%20b`
1102
+ * here and `a b` there. Both read a `+` in the query as a space.
916
1103
  */
917
1104
  function resolveTestId(headers, url) {
918
1105
  const headerValue = headers["x-test-id"];
@@ -936,6 +1123,237 @@ function getContext(req) {
936
1123
  } else if (typeof headerValue === "string" && headerValue) return headerValue;
937
1124
  }
938
1125
  /**
1126
+ * Decode one MCP identity value: an `X-Test-Id` / `X-AIMock-Context` header
1127
+ * value, and also each query name and (through {@link decodeMcpQueryValue})
1128
+ * each `?testId=` / `?context=` / `?undeclared=` query value. Clients send `encodeURIComponent(id)` because
1129
+ * `fetch` rejects characters such as `›` in a header. A value that is not
1130
+ * valid percent-encoding (a raw `applies 50% discount`) is used as-is, with
1131
+ * `fellBack: true` so the caller can log the fallback. Only that `URIError`
1132
+ * is caught; any other throw propagates. MCP requests only: LLM routes read
1133
+ * the header raw and the query through `URLSearchParams` (see
1134
+ * {@link resolveTestId}).
1135
+ */
1136
+ function decodeMcpHeaderValue(raw) {
1137
+ try {
1138
+ return {
1139
+ value: decodeURIComponent(raw),
1140
+ fellBack: false
1141
+ };
1142
+ } catch (err) {
1143
+ if (!(err instanceof URIError)) throw err;
1144
+ return {
1145
+ value: raw,
1146
+ fellBack: true
1147
+ };
1148
+ }
1149
+ }
1150
+ /**
1151
+ * Decode one MCP query value (`?testId=`, `?context=`, `?undeclared=`) the way
1152
+ * `URLSearchParams` reads it (spec I1): a `+` is a space, then the value is
1153
+ * percent-decoded by the {@link decodeMcpHeaderValue} rule. So a query built
1154
+ * with `URL.searchParams.set(...)` (a space sent as `+`) and one built with
1155
+ * `encodeURIComponent` both resolve to the id itself. A value that is not
1156
+ * valid percent-encoding is used as-is (its `+` still a space), with
1157
+ * `fellBack: true`.
1158
+ */
1159
+ function decodeMcpQueryValue(raw) {
1160
+ return decodeMcpHeaderValue(raw.replace(/\+/g, " "));
1161
+ }
1162
+ /**
1163
+ * Every value of the header `name`, one per header line: `[]` when absent.
1164
+ * Node joins a repeated header into one comma-joined `req.headers` string, so
1165
+ * the values come from `req.headersDistinct` (one element per line) when the
1166
+ * request has it. A caller without it (a hand-built request) is read from
1167
+ * `req.headers`: one element for a string, each element for an array.
1168
+ */
1169
+ function headerValues(req, name) {
1170
+ const distinct = req.headersDistinct?.[name];
1171
+ if (distinct !== void 0) return distinct;
1172
+ const value = req.headers[name];
1173
+ if (value === void 0) return [];
1174
+ return Array.isArray(value) ? value : [value];
1175
+ }
1176
+ /**
1177
+ * Every pair of a query string, in order, each name decoded by the
1178
+ * `decodeMcpHeaderValue` rule. A bare `name` with no `=` counts as an
1179
+ * occurrence with an empty value, so `?testId&testId=t1` has two. Each value
1180
+ * is left raw for the caller to decode with {@link decodeMcpQueryValue}.
1181
+ * A name that is not valid percent-encoding (`test%Id`) gets `name: null`: it
1182
+ * matches no field, and the caller counts it.
1183
+ */
1184
+ function queryPairs(query) {
1185
+ if (query === "") return [];
1186
+ return query.split("&").map((pair) => {
1187
+ const eq = pair.indexOf("=");
1188
+ const key = decodeMcpHeaderValue(eq === -1 ? pair : pair.slice(0, eq));
1189
+ return {
1190
+ name: key.fellBack ? null : key.value,
1191
+ value: eq === -1 ? "" : pair.slice(eq + 1)
1192
+ };
1193
+ });
1194
+ }
1195
+ /**
1196
+ * A request value as a message part, the way the message builder quotes every
1197
+ * user string: JSON-quoted (quotes and control characters escaped), then cut
1198
+ * once as JSON text, so the whole echo, quotes, escapes and the
1199
+ * `… (<n> more chars)` count included, fits in `MCP_FAKES_ECHO_LIMIT` and the
1200
+ * cut never splits a JSON escape or a surrogate pair.
1201
+ */
1202
+ function echoIdentityValue(value) {
1203
+ return require_message_text.quote(value, require_constants.MCP_FAKES_ECHO_LIMIT);
1204
+ }
1205
+ const MCP_IDENTITY_INPUTS = {
1206
+ testId: {
1207
+ header: "x-test-id",
1208
+ query: "testId",
1209
+ label: "X-Test-Id"
1210
+ },
1211
+ context: {
1212
+ header: "x-aimock-context",
1213
+ query: "context",
1214
+ label: "X-AIMock-Context"
1215
+ },
1216
+ undeclared: {
1217
+ header: "x-aimock-mcp-undeclared",
1218
+ query: "undeclared",
1219
+ label: "X-AIMock-MCP-Undeclared"
1220
+ }
1221
+ };
1222
+ /**
1223
+ * Resolve the identity (test id, context, undeclared override) of one MCP request.
1224
+ * Each field resolves on its own, first of: the header, the query parameter,
1225
+ * the session value bound at `initialize`. A field sent more than once on
1226
+ * either path (more than one header line, read from `headersDistinct` because
1227
+ * Node joins repeated lines into one `headers` string; a header array from a
1228
+ * hand-built request; a repeated query name) is an error
1229
+ * (`MCP_DUPLICATE_IDENTITY`), even when the other path also carries it. For
1230
+ * the test id and the context, a header value is decoded with
1231
+ * `decodeURIComponent` (raw value on failure, with `fellBack` set) and a query
1232
+ * value the way `URLSearchParams` reads it (spec I1): a `+` is a space, then
1233
+ * the same `decodeURIComponent` rule. So `encodeURIComponent` output (what
1234
+ * clients send) and a query built with `URL.searchParams` both decode to the
1235
+ * id itself, while a raw `+` is a `+` in the header and a space in the query.
1236
+ * When both paths carry a test id or a context, the header is used and the
1237
+ * query value is ignored, even if the two differ, but an ignored query value
1238
+ * that does not decode still sets `fellBack`. The undeclared header is not
1239
+ * percent-decoded; its query value is, by the same query rule. Both are
1240
+ * trimmed and compared case-insensitively. `supplied` says whether the
1241
+ * request itself carried a non-empty header or query value for the field,
1242
+ * never `resolveTestId`'s result (which returns `"__default__"` when nothing
1243
+ * is sent). Blank values: an empty value is not supplied and falls through;
1244
+ * it is never rejected. A whitespace-only value is not supplied for the
1245
+ * undeclared override (it is trimmed), but is a real value for the test id
1246
+ * and the context, which match exactly and are never trimmed (Node trims a
1247
+ * header value, so only the query or a hand-built request can carry one). A
1248
+ * lone query name with no `=` carries no value. An empty session value counts
1249
+ * as none, and a missing `req.url` as `/`. A field with no value anywhere is
1250
+ * `null`. An unrecognized undeclared override on the header or the query is
1251
+ * an error (`ok: false`), not a fall-through: both are checked before the
1252
+ * header one is used, so a valid header does not hide a mistyped query value.
1253
+ * Bad percent-encoding is never silent: a test id or context value that does
1254
+ * not decode sets `fellBack`, on either path, used or ignored; an undeclared
1255
+ * query value that does not decode is that error, with the message saying
1256
+ * so; and a query name that does not decode matches no field and is counted
1257
+ * in `undecodedQueryNames`. `resolveTestId` / `getContext` stay unchanged for
1258
+ * LLM routes.
1259
+ */
1260
+ function resolveMcpIdentity(req, session) {
1261
+ const url = req.url ?? "/";
1262
+ const qIdx = url.indexOf("?");
1263
+ const pairs = queryPairs(qIdx === -1 ? "" : url.slice(qIdx + 1));
1264
+ const raw = {};
1265
+ for (const field of [
1266
+ "testId",
1267
+ "context",
1268
+ "undeclared"
1269
+ ]) {
1270
+ const input = MCP_IDENTITY_INPUTS[field];
1271
+ const sent = [["header", headerValues(req, input.header)], ["query", pairs.filter((p) => p.name === input.query).map((p) => p.value)]];
1272
+ for (const [source, values] of sent) if (values.length > 1) {
1273
+ const label = source === "header" ? require_message_text.msg`${require_message_text.fixed(input.label)} header` : require_message_text.msg`?${require_message_text.fixed(input.query)}= query parameter`;
1274
+ return {
1275
+ ok: false,
1276
+ error: {
1277
+ code: "MCP_DUPLICATE_IDENTITY",
1278
+ status: 400,
1279
+ field,
1280
+ source,
1281
+ count: values.length,
1282
+ message: require_message_text.build(require_message_text.msg`Duplicate ${label}: ${values.length} values sent, expected one`)
1283
+ }
1284
+ };
1285
+ }
1286
+ raw[field] = {
1287
+ header: sent[0][1][0],
1288
+ query: sent[1][1][0]
1289
+ };
1290
+ }
1291
+ const fromRequest = (field) => {
1292
+ const { header, query: q } = raw[field];
1293
+ const fromQuery = q ? decodeMcpQueryValue(q) : null;
1294
+ if (header) {
1295
+ const used = decodeMcpHeaderValue(header);
1296
+ return {
1297
+ value: used.value,
1298
+ fellBack: used.fellBack || (fromQuery?.fellBack ?? false)
1299
+ };
1300
+ }
1301
+ return fromQuery ?? {
1302
+ value: null,
1303
+ fellBack: false
1304
+ };
1305
+ };
1306
+ const testId = fromRequest("testId");
1307
+ const context = fromRequest("context");
1308
+ let undeclared = null;
1309
+ for (const source of ["header", "query"]) {
1310
+ const sent = raw.undeclared[source];
1311
+ if (sent === void 0) continue;
1312
+ const decoded = source === "header" ? {
1313
+ value: sent,
1314
+ fellBack: false
1315
+ } : decodeMcpQueryValue(sent);
1316
+ if (decoded.value.trim() === "") continue;
1317
+ const parsed = parseMcpUndeclared(decoded.value);
1318
+ if (parsed === null) {
1319
+ const echoed = echoIdentityValue(sent);
1320
+ const label = source === "header" ? require_message_text.msg`X-AIMock-MCP-Undeclared header` : require_message_text.msg`?undeclared= query parameter`;
1321
+ const note = decoded.fellBack ? require_message_text.msg` (not valid percent-encoding)` : require_message_text.msg``;
1322
+ return {
1323
+ ok: false,
1324
+ error: {
1325
+ code: "MCP_INVALID_UNDECLARED",
1326
+ status: 400,
1327
+ field: "undeclared",
1328
+ source,
1329
+ raw: require_echo_text.cutText(sent),
1330
+ message: require_message_text.build(require_message_text.msg`Invalid ${label} value ${echoed}${note}: expected allow or deny`)
1331
+ }
1332
+ };
1333
+ }
1334
+ undeclared ??= parsed;
1335
+ }
1336
+ const undecodedQueryNames = pairs.filter((p) => p.name === null).length;
1337
+ return {
1338
+ ok: true,
1339
+ identity: {
1340
+ testId: testId.value ?? (session?.testId || null),
1341
+ context: context.value ?? (session?.context || null),
1342
+ undeclared: undeclared ?? session?.undeclared ?? null
1343
+ },
1344
+ supplied: {
1345
+ testId: testId.value !== null,
1346
+ context: context.value !== null,
1347
+ undeclared: undeclared !== null
1348
+ },
1349
+ fellBack: {
1350
+ testId: testId.fellBack,
1351
+ context: context.fellBack
1352
+ },
1353
+ ...undecodedQueryNames > 0 ? { undecodedQueryNames } : {}
1354
+ };
1355
+ }
1356
+ /**
939
1357
  * Convert a test ID (e.g. Playwright titlePath) into a filesystem-safe slug
940
1358
  * suitable for use as a directory name in snapshot-style recording.
941
1359
  */
@@ -1122,10 +1540,68 @@ function buildEmbeddingResponse(embeddings, model, usage) {
1122
1540
  }
1123
1541
  };
1124
1542
  }
1543
+ /**
1544
+ * Build a stable, human-readable identifier for a fixture's match shape, for
1545
+ * any log line that has to name WHICH fixture it means. The `Fixture` type
1546
+ * carries no `id`/`name`, so the matchers are the only handle a reader has.
1547
+ *
1548
+ * Used by the relaxed-turnIndex warning (`router.ts`) and by the chaos
1549
+ * rejected-value warning (`chaos.ts`); one implementation so the two name the
1550
+ * same fixture the same way. The obvious `JSON.stringify(match)` is unfit: it
1551
+ * DROPS `predicate` functions (non-serialisable) and serialises any RegExp
1552
+ * matcher to `{}`, so a predicate- or regex-gated fixture's warning collapsed to
1553
+ * an uninformative "served fixture {}" / `{"userMessage":{}}` blob.
1554
+ *
1555
+ * Instead we list the PRESENT matcher keys in declaration order, annotating each
1556
+ * by VALUE KIND so predicates and regexes survive: `predicate(fn)`,
1557
+ * `userMessage(regex)`, `userMessage("hello")`, `turnIndex=0`, etc. The
1558
+ * fixture's array `index` is prefixed as a stable positional identifier when
1559
+ * the caller knows it (i.e. `>= 0`); callers holding only the fixture object
1560
+ * pass `-1` and get the matcher summary alone. String/number values are shown
1561
+ * inline (truncated) so a content match remains recognisable; the whole string
1562
+ * is capped to keep the log line bounded.
1563
+ */
1564
+ const DESCRIBE_MATCH_MAX = 160;
1565
+ function describeMatch(match, index) {
1566
+ const parts = [];
1567
+ for (const [key, value] of Object.entries(match)) {
1568
+ if (value === void 0) continue;
1569
+ if (typeof value === "function") parts.push(key === "predicate" ? "[predicate]" : `${key}[fn]`);
1570
+ else if (value instanceof RegExp) parts.push(`${key}(${value})`);
1571
+ else if (typeof value === "string") {
1572
+ const v = value.length > 40 ? `${value.slice(0, 40)}…` : value;
1573
+ parts.push(`${key}(${JSON.stringify(v)})`);
1574
+ } else if (Array.isArray(value)) parts.push(`${key}(${value.length} item${value.length === 1 ? "" : "s"})`);
1575
+ else if (typeof value === "object" && value !== null) {
1576
+ const json = JSON.stringify(value);
1577
+ parts.push(`${key}(${json.length > 40 ? `${json.slice(0, 40)}…` : json})`);
1578
+ } else parts.push(`${key}=${String(value)}`);
1579
+ }
1580
+ const keys = parts.length > 0 ? parts.join(", ") : "no matchers";
1581
+ const full = `${index >= 0 ? `#${index} ` : ""}{ ${keys} }`;
1582
+ if (full.length <= DESCRIBE_MATCH_MAX) return full;
1583
+ const head = full.slice(0, DESCRIBE_MATCH_MAX - 4);
1584
+ const cut = head.lastIndexOf(", ");
1585
+ return `${cut > 0 ? head.slice(0, cut) : head}, … }`;
1586
+ }
1587
+ /**
1588
+ * Parse an `X-AIMock-MCP-Undeclared` header or `?undeclared=` value.
1589
+ * Modeled on {@link resolveStrictMode}: case-insensitive, surrounding
1590
+ * whitespace trimmed. Returns `null` when unrecognised; unlike the strict
1591
+ * header, {@link resolveMcpIdentity} turns that into an error rather than a
1592
+ * fall-through, because falling through would turn a mistyped `deny` into
1593
+ * the permissive default.
1594
+ */
1595
+ function parseMcpUndeclared(raw) {
1596
+ const val = raw.trim().toLowerCase();
1597
+ if (val === "allow" || val === "deny") return val;
1598
+ return null;
1599
+ }
1125
1600
 
1126
1601
  //#endregion
1127
1602
  exports.FORMAT_TO_CONTENT_TYPE = FORMAT_TO_CONTENT_TYPE;
1128
1603
  exports.MAX_EMBEDDING_DIMENSIONS = MAX_EMBEDDING_DIMENSIONS;
1604
+ exports.RequestBodyTooLargeError = RequestBodyTooLargeError;
1129
1605
  exports.buildContentWithToolCallsChunks = buildContentWithToolCallsChunks;
1130
1606
  exports.buildContentWithToolCallsCompletion = buildContentWithToolCallsCompletion;
1131
1607
  exports.buildEmbeddingResponse = buildEmbeddingResponse;
@@ -1134,6 +1610,8 @@ exports.buildTextCompletion = buildTextCompletion;
1134
1610
  exports.buildToolCallChunks = buildToolCallChunks;
1135
1611
  exports.buildToolCallCompletion = buildToolCallCompletion;
1136
1612
  exports.buildUsageChunk = buildUsageChunk;
1613
+ exports.decodeMcpHeaderValue = decodeMcpHeaderValue;
1614
+ exports.describeMatch = describeMatch;
1137
1615
  exports.extractOverrides = extractOverrides;
1138
1616
  exports.flattenHeaders = flattenHeaders;
1139
1617
  exports.formatToMime = formatToMime;
@@ -1144,6 +1622,7 @@ exports.generateToolCallId = generateToolCallId;
1144
1622
  exports.generateToolUseId = generateToolUseId;
1145
1623
  exports.getContext = getContext;
1146
1624
  exports.getTestId = getTestId;
1625
+ exports.hasMintedRequestId = hasMintedRequestId;
1147
1626
  exports.isAudioResponse = isAudioResponse;
1148
1627
  exports.isContentWithToolCallsResponse = isContentWithToolCallsResponse;
1149
1628
  exports.isEmbeddingResponse = isEmbeddingResponse;
@@ -1151,18 +1630,25 @@ exports.isErrorResponse = isErrorResponse;
1151
1630
  exports.isImageResponse = isImageResponse;
1152
1631
  exports.isJSONResponse = isJSONResponse;
1153
1632
  exports.isJsonObject = isJsonObject;
1633
+ exports.isLiveResponse = isLiveResponse;
1154
1634
  exports.isResponseFactory = isResponseFactory;
1155
1635
  exports.isTextResponse = isTextResponse;
1156
1636
  exports.isToolCallResponse = isToolCallResponse;
1157
1637
  exports.isTranscriptionResponse = isTranscriptionResponse;
1158
1638
  exports.isVideoResponse = isVideoResponse;
1639
+ exports.markMintedRequestId = markMintedRequestId;
1159
1640
  exports.matchesPattern = matchesPattern;
1160
1641
  exports.normalizeEmbeddingInput = normalizeEmbeddingInput;
1161
1642
  exports.normalizeTextInput = normalizeTextInput;
1643
+ exports.parseStrictIntegerText = parseStrictIntegerText;
1162
1644
  exports.readBody = readBody;
1645
+ exports.readBodyBufferBounded = readBodyBufferBounded;
1646
+ exports.resolveFixtureBlockOutcome = resolveFixtureBlockOutcome;
1163
1647
  exports.resolveFixtureBlocks = resolveFixtureBlocks;
1648
+ exports.resolveMcpIdentity = resolveMcpIdentity;
1164
1649
  exports.resolveReasoningArtifactsForModel = resolveReasoningArtifactsForModel;
1165
1650
  exports.resolveReasoningForModel = resolveReasoningForModel;
1651
+ exports.resolveRequestId = resolveRequestId;
1166
1652
  exports.resolveResponse = resolveResponse;
1167
1653
  exports.resolveStrictMode = resolveStrictMode;
1168
1654
  exports.resolveTestId = resolveTestId;
@@ -1176,4 +1662,5 @@ exports.strictOverrideField = strictOverrideField;
1176
1662
  exports.validateChatMessages = validateChatMessages;
1177
1663
  exports.validateEmbeddingDimensions = validateEmbeddingDimensions;
1178
1664
  exports.validateToolsField = validateToolsField;
1665
+ exports.wouldProxyMiss = wouldProxyMiss;
1179
1666
  //# sourceMappingURL=helpers.cjs.map