@copilotkit/aimock 1.45.1 → 1.47.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 (492) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +25 -1
  4. package/README.md +11 -2
  5. package/dist/agui-mock.cjs +25 -25
  6. package/dist/agui-mock.cjs.map +1 -1
  7. package/dist/agui-mock.d.cts.map +1 -1
  8. package/dist/agui-mock.d.ts.map +1 -1
  9. package/dist/agui-mock.js +25 -25
  10. package/dist/agui-mock.js.map +1 -1
  11. package/dist/agui-types.d.cts.map +1 -1
  12. package/dist/aimock-cli.cjs +15 -1
  13. package/dist/aimock-cli.cjs.map +1 -1
  14. package/dist/aimock-cli.d.cts.map +1 -1
  15. package/dist/aimock-cli.d.ts.map +1 -1
  16. package/dist/aimock-cli.js +16 -2
  17. package/dist/aimock-cli.js.map +1 -1
  18. package/dist/api-key-auth.cjs +10 -9
  19. package/dist/api-key-auth.cjs.map +1 -1
  20. package/dist/api-key-auth.d.cts.map +1 -1
  21. package/dist/api-key-auth.d.ts.map +1 -1
  22. package/dist/api-key-auth.js +11 -10
  23. package/dist/api-key-auth.js.map +1 -1
  24. package/dist/aws-event-stream.cjs +20 -23
  25. package/dist/aws-event-stream.cjs.map +1 -1
  26. package/dist/aws-event-stream.d.cts +0 -1
  27. package/dist/aws-event-stream.d.ts +0 -1
  28. package/dist/aws-event-stream.js +20 -24
  29. package/dist/aws-event-stream.js.map +1 -1
  30. package/dist/batches.cjs +2 -4
  31. package/dist/batches.cjs.map +1 -1
  32. package/dist/batches.d.cts.map +1 -1
  33. package/dist/batches.d.ts.map +1 -1
  34. package/dist/batches.js +2 -4
  35. package/dist/batches.js.map +1 -1
  36. package/dist/bedrock-converse.cjs +139 -161
  37. package/dist/bedrock-converse.cjs.map +1 -1
  38. package/dist/bedrock-converse.d.cts.map +1 -1
  39. package/dist/bedrock-converse.d.ts.map +1 -1
  40. package/dist/bedrock-converse.js +137 -159
  41. package/dist/bedrock-converse.js.map +1 -1
  42. package/dist/bedrock.cjs +175 -216
  43. package/dist/bedrock.cjs.map +1 -1
  44. package/dist/bedrock.d.cts.map +1 -1
  45. package/dist/bedrock.d.ts.map +1 -1
  46. package/dist/bedrock.js +172 -213
  47. package/dist/bedrock.js.map +1 -1
  48. package/dist/byteplus-video.cjs +11 -10
  49. package/dist/byteplus-video.cjs.map +1 -1
  50. package/dist/byteplus-video.d.cts.map +1 -1
  51. package/dist/byteplus-video.d.ts.map +1 -1
  52. package/dist/byteplus-video.js +5 -4
  53. package/dist/byteplus-video.js.map +1 -1
  54. package/dist/chaos.cjs +5 -4
  55. package/dist/chaos.cjs.map +1 -1
  56. package/dist/chaos.d.cts.map +1 -1
  57. package/dist/chaos.d.ts.map +1 -1
  58. package/dist/chaos.js +5 -4
  59. package/dist/chaos.js.map +1 -1
  60. package/dist/cli.cjs +15 -0
  61. package/dist/cli.cjs.map +1 -1
  62. package/dist/cli.js +15 -0
  63. package/dist/cli.js.map +1 -1
  64. package/dist/cohere.cjs +107 -180
  65. package/dist/cohere.cjs.map +1 -1
  66. package/dist/cohere.d.cts.map +1 -1
  67. package/dist/cohere.d.ts.map +1 -1
  68. package/dist/cohere.js +106 -179
  69. package/dist/cohere.js.map +1 -1
  70. package/dist/config-loader.cjs +29 -1
  71. package/dist/config-loader.cjs.map +1 -1
  72. package/dist/config-loader.d.cts +7 -1
  73. package/dist/config-loader.d.cts.map +1 -1
  74. package/dist/config-loader.d.ts +7 -1
  75. package/dist/config-loader.d.ts.map +1 -1
  76. package/dist/config-loader.js +29 -2
  77. package/dist/config-loader.js.map +1 -1
  78. package/dist/count-tokens.cjs +146 -0
  79. package/dist/count-tokens.cjs.map +1 -0
  80. package/dist/count-tokens.js +146 -0
  81. package/dist/count-tokens.js.map +1 -0
  82. package/dist/elevenlabs-audio.cjs +36 -34
  83. package/dist/elevenlabs-audio.cjs.map +1 -1
  84. package/dist/elevenlabs-audio.d.cts.map +1 -1
  85. package/dist/elevenlabs-audio.d.ts.map +1 -1
  86. package/dist/elevenlabs-audio.js +33 -31
  87. package/dist/elevenlabs-audio.js.map +1 -1
  88. package/dist/elevenlabs-voice.cjs +38 -37
  89. package/dist/elevenlabs-voice.cjs.map +1 -1
  90. package/dist/elevenlabs-voice.d.cts.map +1 -1
  91. package/dist/elevenlabs-voice.d.ts.map +1 -1
  92. package/dist/elevenlabs-voice.js +33 -32
  93. package/dist/elevenlabs-voice.js.map +1 -1
  94. package/dist/embedding-request.cjs +16 -0
  95. package/dist/embedding-request.cjs.map +1 -0
  96. package/dist/embedding-request.js +14 -0
  97. package/dist/embedding-request.js.map +1 -0
  98. package/dist/embeddings.cjs +30 -20
  99. package/dist/embeddings.cjs.map +1 -1
  100. package/dist/embeddings.d.cts.map +1 -1
  101. package/dist/embeddings.d.ts.map +1 -1
  102. package/dist/embeddings.js +30 -20
  103. package/dist/embeddings.js.map +1 -1
  104. package/dist/fal-audio.cjs +45 -43
  105. package/dist/fal-audio.cjs.map +1 -1
  106. package/dist/fal-audio.d.cts.map +1 -1
  107. package/dist/fal-audio.d.ts.map +1 -1
  108. package/dist/fal-audio.js +42 -40
  109. package/dist/fal-audio.js.map +1 -1
  110. package/dist/fal.cjs +17 -15
  111. package/dist/fal.cjs.map +1 -1
  112. package/dist/fal.js +16 -14
  113. package/dist/fal.js.map +1 -1
  114. package/dist/files.cjs +2 -4
  115. package/dist/files.cjs.map +1 -1
  116. package/dist/files.d.cts.map +1 -1
  117. package/dist/files.d.ts.map +1 -1
  118. package/dist/files.js +2 -4
  119. package/dist/files.js.map +1 -1
  120. package/dist/fine-tuning.cjs +2 -4
  121. package/dist/fine-tuning.cjs.map +1 -1
  122. package/dist/fine-tuning.d.cts.map +1 -1
  123. package/dist/fine-tuning.d.ts.map +1 -1
  124. package/dist/fine-tuning.js +2 -4
  125. package/dist/fine-tuning.js.map +1 -1
  126. package/dist/fixture-loader.cjs +140 -44
  127. package/dist/fixture-loader.cjs.map +1 -1
  128. package/dist/fixture-loader.d.cts.map +1 -1
  129. package/dist/fixture-loader.d.ts.map +1 -1
  130. package/dist/fixture-loader.js +141 -46
  131. package/dist/fixture-loader.js.map +1 -1
  132. package/dist/gemini-embeddings.cjs +26 -24
  133. package/dist/gemini-embeddings.cjs.map +1 -1
  134. package/dist/gemini-embeddings.js +26 -24
  135. package/dist/gemini-embeddings.js.map +1 -1
  136. package/dist/gemini-interactions.cjs +113 -156
  137. package/dist/gemini-interactions.cjs.map +1 -1
  138. package/dist/gemini-interactions.d.cts +0 -1
  139. package/dist/gemini-interactions.d.cts.map +1 -1
  140. package/dist/gemini-interactions.d.ts +0 -1
  141. package/dist/gemini-interactions.d.ts.map +1 -1
  142. package/dist/gemini-interactions.js +113 -156
  143. package/dist/gemini-interactions.js.map +1 -1
  144. package/dist/gemini.cjs +295 -218
  145. package/dist/gemini.cjs.map +1 -1
  146. package/dist/gemini.d.cts.map +1 -1
  147. package/dist/gemini.d.ts.map +1 -1
  148. package/dist/gemini.js +295 -219
  149. package/dist/gemini.js.map +1 -1
  150. package/dist/grok-video.cjs +14 -12
  151. package/dist/grok-video.cjs.map +1 -1
  152. package/dist/grok-video.d.cts.map +1 -1
  153. package/dist/grok-video.d.ts.map +1 -1
  154. package/dist/grok-video.js +8 -6
  155. package/dist/grok-video.js.map +1 -1
  156. package/dist/helpers.cjs +411 -75
  157. package/dist/helpers.cjs.map +1 -1
  158. package/dist/helpers.d.cts +51 -1
  159. package/dist/helpers.d.cts.map +1 -1
  160. package/dist/helpers.d.ts +51 -1
  161. package/dist/helpers.d.ts.map +1 -1
  162. package/dist/helpers.js +402 -74
  163. package/dist/helpers.js.map +1 -1
  164. package/dist/images.cjs +30 -28
  165. package/dist/images.cjs.map +1 -1
  166. package/dist/images.d.cts.map +1 -1
  167. package/dist/images.d.ts.map +1 -1
  168. package/dist/images.js +27 -25
  169. package/dist/images.js.map +1 -1
  170. package/dist/index.cjs +4 -2
  171. package/dist/index.d.cts +4 -4
  172. package/dist/index.d.ts +4 -4
  173. package/dist/index.js +4 -4
  174. package/dist/journal.cjs +3 -1
  175. package/dist/journal.cjs.map +1 -1
  176. package/dist/journal.d.cts.map +1 -1
  177. package/dist/journal.d.ts.map +1 -1
  178. package/dist/journal.js +2 -1
  179. package/dist/journal.js.map +1 -1
  180. package/dist/llmock.cjs +3 -0
  181. package/dist/llmock.cjs.map +1 -1
  182. package/dist/llmock.d.cts.map +1 -1
  183. package/dist/llmock.d.ts.map +1 -1
  184. package/dist/llmock.js +3 -0
  185. package/dist/llmock.js.map +1 -1
  186. package/dist/mcp-fakes.d.cts.map +1 -1
  187. package/dist/mcp-handler.cjs +7 -3
  188. package/dist/mcp-handler.cjs.map +1 -1
  189. package/dist/mcp-handler.js +7 -3
  190. package/dist/mcp-handler.js.map +1 -1
  191. package/dist/mcp-recorder.cjs +2 -1
  192. package/dist/mcp-recorder.cjs.map +1 -1
  193. package/dist/mcp-recorder.js +3 -2
  194. package/dist/mcp-recorder.js.map +1 -1
  195. package/dist/messages.cjs +235 -202
  196. package/dist/messages.cjs.map +1 -1
  197. package/dist/messages.d.cts.map +1 -1
  198. package/dist/messages.d.ts.map +1 -1
  199. package/dist/messages.js +234 -202
  200. package/dist/messages.js.map +1 -1
  201. package/dist/metrics.cjs +5 -2
  202. package/dist/metrics.cjs.map +1 -1
  203. package/dist/metrics.d.cts.map +1 -1
  204. package/dist/metrics.d.ts.map +1 -1
  205. package/dist/metrics.js +6 -3
  206. package/dist/metrics.js.map +1 -1
  207. package/dist/misbehavior.cjs +62 -3
  208. package/dist/misbehavior.cjs.map +1 -1
  209. package/dist/misbehavior.d.cts.map +1 -1
  210. package/dist/misbehavior.d.ts.map +1 -1
  211. package/dist/misbehavior.js +63 -4
  212. package/dist/misbehavior.js.map +1 -1
  213. package/dist/model-utils.cjs +1 -0
  214. package/dist/model-utils.cjs.map +1 -1
  215. package/dist/model-utils.js +1 -1
  216. package/dist/model-utils.js.map +1 -1
  217. package/dist/moderation.cjs +15 -12
  218. package/dist/moderation.cjs.map +1 -1
  219. package/dist/moderation.js +14 -11
  220. package/dist/moderation.js.map +1 -1
  221. package/dist/ndjson-writer.cjs +21 -23
  222. package/dist/ndjson-writer.cjs.map +1 -1
  223. package/dist/ndjson-writer.d.cts +0 -1
  224. package/dist/ndjson-writer.d.cts.map +1 -1
  225. package/dist/ndjson-writer.d.ts +0 -1
  226. package/dist/ndjson-writer.d.ts.map +1 -1
  227. package/dist/ndjson-writer.js +21 -24
  228. package/dist/ndjson-writer.js.map +1 -1
  229. package/dist/ollama.cjs +276 -210
  230. package/dist/ollama.cjs.map +1 -1
  231. package/dist/ollama.d.cts.map +1 -1
  232. package/dist/ollama.d.ts.map +1 -1
  233. package/dist/ollama.js +273 -207
  234. package/dist/ollama.js.map +1 -1
  235. package/dist/openapi.cjs +323 -3
  236. package/dist/openapi.cjs.map +1 -1
  237. package/dist/openapi.d.cts.map +1 -1
  238. package/dist/openapi.d.ts.map +1 -1
  239. package/dist/openapi.js +324 -4
  240. package/dist/openapi.js.map +1 -1
  241. package/dist/openrouter-chat.cjs +11 -155
  242. package/dist/openrouter-chat.cjs.map +1 -1
  243. package/dist/openrouter-chat.js +11 -155
  244. package/dist/openrouter-chat.js.map +1 -1
  245. package/dist/openrouter-video.cjs +51 -74
  246. package/dist/openrouter-video.cjs.map +1 -1
  247. package/dist/openrouter-video.d.cts.map +1 -1
  248. package/dist/openrouter-video.d.ts.map +1 -1
  249. package/dist/openrouter-video.js +37 -60
  250. package/dist/openrouter-video.js.map +1 -1
  251. package/dist/raw-validation.cjs +177 -0
  252. package/dist/raw-validation.cjs.map +1 -0
  253. package/dist/raw-validation.js +176 -0
  254. package/dist/raw-validation.js.map +1 -0
  255. package/dist/recorder.cjs +176 -95
  256. package/dist/recorder.cjs.map +1 -1
  257. package/dist/recorder.d.cts.map +1 -1
  258. package/dist/recorder.d.ts.map +1 -1
  259. package/dist/recorder.js +176 -95
  260. package/dist/recorder.js.map +1 -1
  261. package/dist/rerank.cjs +13 -11
  262. package/dist/rerank.cjs.map +1 -1
  263. package/dist/rerank.js +12 -10
  264. package/dist/rerank.js.map +1 -1
  265. package/dist/response/catalog/anthropic-page.cjs +39 -0
  266. package/dist/response/catalog/anthropic-page.cjs.map +1 -0
  267. package/dist/response/catalog/anthropic-page.js +38 -0
  268. package/dist/response/catalog/anthropic-page.js.map +1 -0
  269. package/dist/response/catalog/collect.cjs +61 -0
  270. package/dist/response/catalog/collect.cjs.map +1 -0
  271. package/dist/response/catalog/collect.js +59 -0
  272. package/dist/response/catalog/collect.js.map +1 -0
  273. package/dist/response/catalog/gemini-page.cjs +25 -0
  274. package/dist/response/catalog/gemini-page.cjs.map +1 -0
  275. package/dist/response/catalog/gemini-page.js +24 -0
  276. package/dist/response/catalog/gemini-page.js.map +1 -0
  277. package/dist/response/catalog/render.cjs +182 -0
  278. package/dist/response/catalog/render.cjs.map +1 -0
  279. package/dist/response/catalog/render.js +171 -0
  280. package/dist/response/catalog/render.js.map +1 -0
  281. package/dist/response/deliver.cjs +144 -0
  282. package/dist/response/deliver.cjs.map +1 -0
  283. package/dist/response/deliver.js +143 -0
  284. package/dist/response/deliver.js.map +1 -0
  285. package/dist/response/errors.cjs +225 -0
  286. package/dist/response/errors.cjs.map +1 -0
  287. package/dist/response/errors.js +224 -0
  288. package/dist/response/errors.js.map +1 -0
  289. package/dist/response/finish.cjs +39 -0
  290. package/dist/response/finish.cjs.map +1 -0
  291. package/dist/response/finish.js +35 -0
  292. package/dist/response/finish.js.map +1 -0
  293. package/dist/response/frame-loop.cjs +102 -0
  294. package/dist/response/frame-loop.cjs.map +1 -0
  295. package/dist/response/frame-loop.js +100 -0
  296. package/dist/response/frame-loop.js.map +1 -0
  297. package/dist/response/lifecycle.cjs +223 -0
  298. package/dist/response/lifecycle.cjs.map +1 -0
  299. package/dist/response/lifecycle.js +211 -0
  300. package/dist/response/lifecycle.js.map +1 -0
  301. package/dist/response/policy.cjs +126 -0
  302. package/dist/response/policy.cjs.map +1 -0
  303. package/dist/response/policy.js +120 -0
  304. package/dist/response/policy.js.map +1 -0
  305. package/dist/response/profiles.cjs +69 -0
  306. package/dist/response/profiles.cjs.map +1 -0
  307. package/dist/response/profiles.js +65 -0
  308. package/dist/response/profiles.js.map +1 -0
  309. package/dist/response/proxy.cjs +71 -0
  310. package/dist/response/proxy.cjs.map +1 -0
  311. package/dist/response/proxy.js +70 -0
  312. package/dist/response/proxy.js.map +1 -0
  313. package/dist/response/raw.cjs +228 -0
  314. package/dist/response/raw.cjs.map +1 -0
  315. package/dist/response/raw.js +227 -0
  316. package/dist/response/raw.js.map +1 -0
  317. package/dist/response/timing.cjs +157 -0
  318. package/dist/response/timing.cjs.map +1 -0
  319. package/dist/response/timing.js +150 -0
  320. package/dist/response/timing.js.map +1 -0
  321. package/dist/response/usage/codecs/anthropic.cjs +52 -0
  322. package/dist/response/usage/codecs/anthropic.cjs.map +1 -0
  323. package/dist/response/usage/codecs/anthropic.js +50 -0
  324. package/dist/response/usage/codecs/anthropic.js.map +1 -0
  325. package/dist/response/usage/codecs/cohere.cjs +36 -0
  326. package/dist/response/usage/codecs/cohere.cjs.map +1 -0
  327. package/dist/response/usage/codecs/cohere.js +35 -0
  328. package/dist/response/usage/codecs/cohere.js.map +1 -0
  329. package/dist/response/usage/codecs/converse.cjs +16 -0
  330. package/dist/response/usage/codecs/converse.cjs.map +1 -0
  331. package/dist/response/usage/codecs/converse.js +15 -0
  332. package/dist/response/usage/codecs/converse.js.map +1 -0
  333. package/dist/response/usage/codecs/gemini.cjs +31 -0
  334. package/dist/response/usage/codecs/gemini.cjs.map +1 -0
  335. package/dist/response/usage/codecs/gemini.js +31 -0
  336. package/dist/response/usage/codecs/gemini.js.map +1 -0
  337. package/dist/response/usage/codecs/interactions.cjs +22 -0
  338. package/dist/response/usage/codecs/interactions.cjs.map +1 -0
  339. package/dist/response/usage/codecs/interactions.js +21 -0
  340. package/dist/response/usage/codecs/interactions.js.map +1 -0
  341. package/dist/response/usage/codecs/ollama.cjs +17 -0
  342. package/dist/response/usage/codecs/ollama.cjs.map +1 -0
  343. package/dist/response/usage/codecs/ollama.js +17 -0
  344. package/dist/response/usage/codecs/ollama.js.map +1 -0
  345. package/dist/response/usage/codecs/openai.cjs +52 -0
  346. package/dist/response/usage/codecs/openai.cjs.map +1 -0
  347. package/dist/response/usage/codecs/openai.js +50 -0
  348. package/dist/response/usage/codecs/openai.js.map +1 -0
  349. package/dist/response/usage/codecs/openrouter.cjs +68 -0
  350. package/dist/response/usage/codecs/openrouter.cjs.map +1 -0
  351. package/dist/response/usage/codecs/openrouter.js +67 -0
  352. package/dist/response/usage/codecs/openrouter.js.map +1 -0
  353. package/dist/response/usage/codecs/realtime.cjs +19 -0
  354. package/dist/response/usage/codecs/realtime.cjs.map +1 -0
  355. package/dist/response/usage/codecs/realtime.js +18 -0
  356. package/dist/response/usage/codecs/realtime.js.map +1 -0
  357. package/dist/response/usage/codecs/responses.cjs +21 -0
  358. package/dist/response/usage/codecs/responses.cjs.map +1 -0
  359. package/dist/response/usage/codecs/responses.js +20 -0
  360. package/dist/response/usage/codecs/responses.js.map +1 -0
  361. package/dist/response/usage/estimate.cjs +23 -0
  362. package/dist/response/usage/estimate.cjs.map +1 -0
  363. package/dist/response/usage/estimate.js +21 -0
  364. package/dist/response/usage/estimate.js.map +1 -0
  365. package/dist/response/usage/fields.cjs +72 -0
  366. package/dist/response/usage/fields.cjs.map +1 -0
  367. package/dist/response/usage/fields.js +70 -0
  368. package/dist/response/usage/fields.js.map +1 -0
  369. package/dist/response/usage/recording.cjs +52 -0
  370. package/dist/response/usage/recording.cjs.map +1 -0
  371. package/dist/response/usage/recording.js +52 -0
  372. package/dist/response/usage/recording.js.map +1 -0
  373. package/dist/responses.cjs +304 -196
  374. package/dist/responses.cjs.map +1 -1
  375. package/dist/responses.d.cts.map +1 -1
  376. package/dist/responses.d.ts.map +1 -1
  377. package/dist/responses.js +303 -195
  378. package/dist/responses.js.map +1 -1
  379. package/dist/route-registry.cjs +45 -0
  380. package/dist/route-registry.cjs.map +1 -1
  381. package/dist/route-registry.d.cts.map +1 -1
  382. package/dist/route-registry.d.ts.map +1 -1
  383. package/dist/route-registry.js +41 -1
  384. package/dist/route-registry.js.map +1 -1
  385. package/dist/router.cjs +24 -4
  386. package/dist/router.cjs.map +1 -1
  387. package/dist/router.d.cts +7 -1
  388. package/dist/router.d.cts.map +1 -1
  389. package/dist/router.d.ts +7 -1
  390. package/dist/router.d.ts.map +1 -1
  391. package/dist/router.js +24 -5
  392. package/dist/router.js.map +1 -1
  393. package/dist/search.cjs +13 -11
  394. package/dist/search.cjs.map +1 -1
  395. package/dist/search.js +12 -10
  396. package/dist/search.js.map +1 -1
  397. package/dist/server.cjs +293 -248
  398. package/dist/server.cjs.map +1 -1
  399. package/dist/server.d.cts.map +1 -1
  400. package/dist/server.d.ts.map +1 -1
  401. package/dist/server.js +294 -249
  402. package/dist/server.js.map +1 -1
  403. package/dist/speech.cjs +20 -18
  404. package/dist/speech.cjs.map +1 -1
  405. package/dist/speech.d.cts.map +1 -1
  406. package/dist/speech.d.ts.map +1 -1
  407. package/dist/speech.js +19 -17
  408. package/dist/speech.js.map +1 -1
  409. package/dist/sse-writer.cjs +56 -30
  410. package/dist/sse-writer.cjs.map +1 -1
  411. package/dist/sse-writer.d.cts +0 -1
  412. package/dist/sse-writer.d.cts.map +1 -1
  413. package/dist/sse-writer.d.ts +0 -1
  414. package/dist/sse-writer.d.ts.map +1 -1
  415. package/dist/sse-writer.js +55 -31
  416. package/dist/sse-writer.js.map +1 -1
  417. package/dist/stream-collapse.cjs +118 -11
  418. package/dist/stream-collapse.cjs.map +1 -1
  419. package/dist/stream-collapse.d.cts +10 -9
  420. package/dist/stream-collapse.d.cts.map +1 -1
  421. package/dist/stream-collapse.d.ts +10 -9
  422. package/dist/stream-collapse.d.ts.map +1 -1
  423. package/dist/stream-collapse.js +118 -11
  424. package/dist/stream-collapse.js.map +1 -1
  425. package/dist/transcription.cjs +31 -43
  426. package/dist/transcription.cjs.map +1 -1
  427. package/dist/transcription.d.cts.map +1 -1
  428. package/dist/transcription.d.ts.map +1 -1
  429. package/dist/transcription.js +31 -43
  430. package/dist/transcription.js.map +1 -1
  431. package/dist/types.cjs.map +1 -1
  432. package/dist/types.d.cts +231 -9
  433. package/dist/types.d.cts.map +1 -1
  434. package/dist/types.d.ts +231 -9
  435. package/dist/types.d.ts.map +1 -1
  436. package/dist/types.js.map +1 -1
  437. package/dist/vector-mock.cjs +3 -8
  438. package/dist/vector-mock.cjs.map +1 -1
  439. package/dist/vector-mock.d.cts.map +1 -1
  440. package/dist/vector-mock.d.ts.map +1 -1
  441. package/dist/vector-mock.js +3 -8
  442. package/dist/vector-mock.js.map +1 -1
  443. package/dist/vector-stores.cjs +2 -4
  444. package/dist/vector-stores.cjs.map +1 -1
  445. package/dist/vector-stores.d.cts.map +1 -1
  446. package/dist/vector-stores.d.ts.map +1 -1
  447. package/dist/vector-stores.js +2 -4
  448. package/dist/vector-stores.js.map +1 -1
  449. package/dist/veo-video.cjs +16 -14
  450. package/dist/veo-video.cjs.map +1 -1
  451. package/dist/veo-video.js +10 -8
  452. package/dist/veo-video.js.map +1 -1
  453. package/dist/video.cjs +21 -19
  454. package/dist/video.cjs.map +1 -1
  455. package/dist/video.d.cts.map +1 -1
  456. package/dist/video.d.ts.map +1 -1
  457. package/dist/video.js +20 -18
  458. package/dist/video.js.map +1 -1
  459. package/dist/ws-framing.cjs +12 -6
  460. package/dist/ws-framing.cjs.map +1 -1
  461. package/dist/ws-framing.d.cts +2 -0
  462. package/dist/ws-framing.d.cts.map +1 -1
  463. package/dist/ws-framing.d.ts +2 -0
  464. package/dist/ws-framing.d.ts.map +1 -1
  465. package/dist/ws-framing.js +12 -6
  466. package/dist/ws-framing.js.map +1 -1
  467. package/dist/ws-gemini-live.cjs +131 -96
  468. package/dist/ws-gemini-live.cjs.map +1 -1
  469. package/dist/ws-gemini-live.d.cts +0 -1
  470. package/dist/ws-gemini-live.d.cts.map +1 -1
  471. package/dist/ws-gemini-live.d.ts +0 -1
  472. package/dist/ws-gemini-live.d.ts.map +1 -1
  473. package/dist/ws-gemini-live.js +130 -95
  474. package/dist/ws-gemini-live.js.map +1 -1
  475. package/dist/ws-live.cjs +6 -5
  476. package/dist/ws-live.cjs.map +1 -1
  477. package/dist/ws-live.js +5 -4
  478. package/dist/ws-live.js.map +1 -1
  479. package/dist/ws-realtime.cjs +108 -124
  480. package/dist/ws-realtime.cjs.map +1 -1
  481. package/dist/ws-realtime.d.cts.map +1 -1
  482. package/dist/ws-realtime.d.ts.map +1 -1
  483. package/dist/ws-realtime.js +105 -121
  484. package/dist/ws-realtime.js.map +1 -1
  485. package/dist/ws-responses.cjs +80 -59
  486. package/dist/ws-responses.cjs.map +1 -1
  487. package/dist/ws-responses.d.cts.map +1 -1
  488. package/dist/ws-responses.d.ts.map +1 -1
  489. package/dist/ws-responses.js +79 -58
  490. package/dist/ws-responses.js.map +1 -1
  491. package/package.json +4 -1
  492. package/skills/write-fixtures/SKILL.md +57 -16
@@ -1 +1 @@
1
- {"version":3,"file":"llmock.js","names":[],"sources":["../src/llmock.ts"],"sourcesContent":["import type { LiveTranscript } from \"./live-types.js\";\nimport { normalizeLiveFixture, normalizeLiveOptions } from \"./live-fixture.js\";\nimport { isLiveResponse, markServerOwnedFixtures } from \"./helpers.js\";\nimport type {\n AudioResponse,\n ChaosConfig,\n EmbeddingFixtureOpts,\n FalQueueOpts,\n Fixture,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureMatch,\n FixtureOpts,\n FixtureResponse,\n ImageResponse,\n McpFakeSource,\n MockServerOptions,\n MisbehaviorConfig,\n MisbehaviorFaultId,\n Mountable,\n RecordConfig,\n ResponseFactory,\n TranscriptionResponse,\n VideoResponse,\n VoiceDesignResponse,\n} from \"./types.js\";\nimport {\n createServer,\n createServerWithResolvedAuth,\n performFullReset,\n type ServerInstance,\n} from \"./server.js\";\nimport type { ResolvedInboundAuth } from \"./api-key-auth.js\";\nimport {\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n queueOneShotError,\n clearFixtureQueue,\n entryToFixture,\n normalizeResponse,\n normalizeResponsesToolsKeys,\n validateFixtures,\n enableHeldFixtureMisbehavior,\n markFixtureResponsesToolsExtended,\n markFixtureMisbehaviorEnabled,\n MisbehaviorConfigError,\n} from \"./fixture-loader.js\";\nimport {\n loadFixtureFileWithServices,\n loadFixturesFromDirWithServices,\n type FixturesWithServices,\n} from \"./fixture-loader-services.js\";\nimport { ensureFakeMount, isAutoMount, planFileFakes } from \"./mcp-fakes-mount.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { build, msg, quote } from \"./message-text.js\";\nimport { DEFAULT_TEST_ID } from \"./constants.js\";\nimport { Journal } from \"./journal.js\";\nimport type { SearchFixture, SearchResult } from \"./search.js\";\nimport type { RerankFixture, RerankResult } from \"./rerank.js\";\nimport type { ModerationFixture, ModerationResult } from \"./moderation.js\";\nimport { imageResponseToFalJson, videoResponseToFalJson } from \"./fal.js\";\nimport { voiceDesignToJson } from \"./elevenlabs-voice.js\";\n\nimport {\n getFixtureMisbehaviorPosition,\n parseMisbehavior,\n resolveMisbehaviorSeed,\n setFixtureMisbehaviorPosition,\n validateFixtureMisbehavior,\n} from \"./misbehavior.js\";\n\nexport class LLMock {\n private fixtures: Fixture[] = [];\n private fixtureAddition = 0;\n private readonly fixtureCountOrigins = new WeakMap<Fixture, Fixture>();\n /**\n * Fixtures this LLMock built itself (on() and the other helpers), so the\n * caller never held them: the stored object is their identity.\n */\n private readonly ownFixtures = new WeakSet<Fixture>();\n private searchFixtures: SearchFixture[] = [];\n private rerankFixtures: RerankFixture[] = [];\n private moderationFixtures: ModerationFixture[] = [];\n private mounts: Array<{ path: string; handler: Mountable }> = [];\n /** `mcpFakes` blocks loaded before `start()`, handed to the server at start (W2). */\n private mcpFakeBuffer: McpFakeSource[] = [];\n /** MCPMocks the server or a load auto-mounted (W3, W6), for the L6 check. */\n private serverInstance: ServerInstance | null = null;\n private options: MockServerOptions;\n private readonly resolvedInboundAuth?: ResolvedInboundAuth;\n\n constructor(options?: MockServerOptions, resolvedInboundAuth?: ResolvedInboundAuth) {\n // Only this LLMock's server reads its array, so fixtures it makes may be marked in place.\n markServerOwnedFixtures(this.fixtures);\n this.options = options ?? {};\n if (this.options.live !== undefined) normalizeLiveOptions(this.options.live);\n // The `misbehavior` option is read only with `enableMisbehavior: true`;\n // otherwise it is unused data, as in 1.44.0.\n if (this.misbehaviorEnabled && this.options.misbehavior !== undefined) {\n this.setMisbehavior(this.options.misbehavior);\n }\n this.resolvedInboundAuth = resolvedInboundAuth;\n }\n\n /** Misbehavior (fixture keys, header, `misbehavior` option) needs `enableMisbehavior: true`. */\n private get misbehaviorEnabled(): boolean {\n return this.options.enableMisbehavior === true;\n }\n\n // ---- Fixture management ----\n\n private normalizeFixture(fixture: Fixture): Fixture {\n const misbehaviorEnabled = this.misbehaviorEnabled;\n // A fixture loaded from a file holds its `misbehavior` key until enabled.\n if (misbehaviorEnabled) enableHeldFixtureMisbehavior(fixture);\n // A fixture this LLMock built (on() and the helpers) is new to it, so it\n // needs no per-addition copy, and the object stored is its identity.\n const own = this.ownFixtures.delete(fixture);\n const countIdentity = own ? undefined : (this.fixtureCountOrigins.get(fixture) ?? fixture);\n const previousPosition = getFixtureMisbehaviorPosition(fixture);\n const isNewAddition = previousPosition === undefined || /^code#\\d+$/.test(previousPosition);\n const position = isNewAddition ? `code#${this.fixtureAddition++}` : previousPosition;\n // With misbehavior enabled, re-adding a code fixture creates a new fault\n // source without changing the old entry, so each addition is its own copy.\n // The journal counts and records every copy under the caller's object\n // (fixtureCountOrigins), so the identity APIs read as they do without\n // misbehavior: an object added twice is one caller fixture, as in 1.44.0.\n // Without misbehavior the position is never read, and the caller's object\n // is stored as in 1.44.0.\n if (isNewAddition && misbehaviorEnabled && !own) fixture = { ...fixture };\n if (misbehaviorEnabled && fixture.misbehavior !== undefined) {\n const parsed = parseMisbehavior(fixture.misbehavior);\n if (parsed.ok) fixture = { ...fixture, misbehavior: parsed.config };\n const issue = parsed.ok ? validateFixtureMisbehavior(fixture) : parsed.issue;\n if (issue) {\n throw new MisbehaviorConfigError({\n rule: issue.rule,\n file: position,\n detail: issue.message,\n });\n }\n }\n\n if (\n isLiveResponse(fixture.response) ||\n (fixture.match.endpoint === \"openai-live\" && typeof fixture.response !== \"function\")\n ) {\n fixture = {\n ...fixture,\n match: { ...fixture.match },\n response: normalizeLiveFixture(fixture.response, this.options.live),\n };\n } else if (countIdentity !== undefined && fixture !== countIdentity) {\n this.fixtureCountOrigins.set(fixture, countIdentity);\n }\n setFixtureMisbehaviorPosition(fixture, position);\n if (misbehaviorEnabled && fixture.misbehavior !== undefined) {\n markFixtureMisbehaviorEnabled(fixture);\n }\n // A fixture passed in is not marked for responsesTools \"extended\": the\n // server reads it through its extended view, so the caller's object (which\n // another server may share) is left as it was loaded.\n return fixture;\n }\n\n addFixture(fixture: Fixture): this {\n this.fixtures.push(this.normalizeFixture(fixture));\n return this;\n }\n\n addFixtures(fixtures: Fixture[]): this {\n this.fixtures.push(...fixtures.map((fixture) => this.normalizeFixture(fixture)));\n return this;\n }\n\n prependFixture(fixture: Fixture): this {\n this.fixtures.unshift(this.normalizeFixture(fixture));\n return this;\n }\n\n /** Mark a fixture this LLMock built, for {@link normalizeFixture}. */\n private own(fixture: Fixture): Fixture {\n this.ownFixtures.add(fixture);\n return fixture;\n }\n\n getFixtures(): readonly Fixture[] {\n return this.fixtures;\n }\n\n /**\n * Load a fixture file: its LLM fixtures and its `mcpFakes` blocks (F4).\n * Before `start()` the blocks are buffered and handed to the server at\n * start (W2); after it they go to the MCPMock serving each block's `mount`\n * path, auto-mounted when none does (W6). A block that cannot be honored\n * throws a `FixtureLoadError` and nothing from the file is added.\n */\n loadFixtureFile(filePath: string): this {\n return this.acceptLoaded(loadFixtureFileWithServices(filePath, undefined, this.options.live));\n }\n\n /** As {@link loadFixtureFile}, for every fixture file under `dirPath`. */\n loadFixtureDir(dirPath: string): this {\n return this.acceptLoaded(\n loadFixturesFromDirWithServices(dirPath, undefined, this.options.live),\n );\n }\n\n /**\n * Add a load's fakes (all or nothing), then its LLM fixtures. Before start\n * the fakes are checked as the start-time hand-off will check them, with\n * the blocks already buffered and the mounts added so far, so a file whose\n * fakes would be rejected adds nothing. A mount added after the load can\n * still make `start()` reject.\n */\n private acceptLoaded(loaded: FixturesWithServices): this {\n // With misbehavior enabled, a bad `misbehavior` key throws before anything is added.\n if (this.misbehaviorEnabled) loaded.fixtures.forEach(enableHeldFixtureMisbehavior);\n if (this.options.responsesTools === \"extended\") {\n loaded.fixtures.forEach(markFixtureResponsesToolsExtended);\n }\n if (loaded.mcpFakes.length > 0) {\n if (this.serverInstance) {\n this.addFakesAfterStart(this.serverInstance, loaded.mcpFakes);\n } else {\n planFileFakes(\n this.mounts,\n [...this.mcpFakeBuffer, ...loaded.mcpFakes],\n new Set(loaded.mcpFakes),\n );\n this.mcpFakeBuffer.push(...loaded.mcpFakes);\n }\n }\n this.fixtures.push(...loaded.fixtures);\n return this;\n }\n\n /**\n * W6 for a load after start. Every group of blocks (by `mount` path) is\n * checked before any mount is touched: a path held by a mount that is not\n * an MCPMock is a mount conflict, and each group is first added to a\n * throwaway store. Groups for an existing MCPMock are then added to it (its\n * own add is all or nothing and finds collisions with its loaded ids);\n * groups for a free path are added last, to a new auto-mounted MCPMock,\n * wired as W4. The add warnings (L8) are logged at `warn`.\n */\n private addFakesAfterStart(server: ServerInstance, sources: McpFakeSource[]): void {\n const { onExisting, onNew } = planFileFakes(this.mounts, sources);\n\n const logger = server.defaults.logger;\n for (const { handler, group } of onExisting) {\n const result = handler.addMcpFakes?.(group, { kind: \"file\" });\n for (const warning of result?.warnings ?? []) logger.warn(warning.message);\n }\n const registry = server.defaults.registry;\n for (const { path, group } of onNew) {\n const target = ensureFakeMount(\n this.mounts,\n path,\n {\n journal: server.journal,\n ...(registry ? { registry } : {}),\n logger,\n replaySpeed: server.defaults.replaySpeed,\n },\n logger,\n );\n // The check above found no mount at this path, and nothing ran since.\n if (\"conflict\" in target) continue;\n const result = target.handler.addMcpFakes?.(group, { kind: \"file\" });\n for (const warning of result?.warnings ?? []) logger.warn(warning.message);\n }\n }\n\n /** R4, R5: unload the fakes of every mount and the pre-start buffer. */\n private unloadMcpFakes(): void {\n this.mcpFakeBuffer.length = 0;\n for (const { handler } of this.mounts) handler.clearMcpFakes?.();\n }\n\n /**\n * Add fixtures from a JSON string or pre-parsed array of fixture entries.\n * Validates all fixtures and throws if any have severity \"error\".\n */\n addFixturesFromJSON(input: string | FixtureFileEntry[]): this {\n let entries: FixtureFileEntry[];\n if (typeof input === \"string\") {\n try {\n entries = JSON.parse(input);\n } catch (err) {\n throw new Error(\n `addFixturesFromJSON: invalid JSON — ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else {\n entries = input;\n }\n if (!Array.isArray(entries)) {\n throw new TypeError(\n \"addFixturesFromJSON: expected an array of fixture entries; use loadFixtureFile for a {fixtures:[...]} file\",\n );\n }\n const converted = entries.map((entry) => {\n const position = `code#${this.fixtureAddition++}`;\n const fixture = entryToFixture(entry, undefined, this.options.live, {\n file: position,\n index: 0,\n });\n setFixtureMisbehaviorPosition(fixture, position);\n if (this.misbehaviorEnabled) enableHeldFixtureMisbehavior(fixture);\n if (this.options.responsesTools === \"extended\") markFixtureResponsesToolsExtended(fixture);\n return fixture;\n });\n\n const issues = validateFixtures(converted, this.options.live);\n const errors = issues.filter((i) => i.severity === \"error\");\n if (errors.length > 0) {\n throw new Error(`Fixture validation failed: ${JSON.stringify(errors)}`);\n }\n this.fixtures.push(...converted);\n return this;\n }\n\n // Clears in place to preserve array reference identity — the running\n // server reads this same array on every request — and invalidates any\n // one-shot claim parked in flight so it cannot re-arm into the cleared queue.\n clearFixtures(): this {\n clearFixtureQueue(this.fixtures);\n this.serverInstance?.journal.clearMisbehaviorCounters();\n this.unloadMcpFakes();\n return this;\n }\n\n // ---- Convenience ----\n\n on(\n match: FixtureMatch,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n let normalized: FixtureResponse | ResponseFactory = response as ResponseFactory;\n if (typeof response !== \"function\") {\n normalized = normalizeResponse(response, this.options.live);\n // `customToolCalls` / `responsesBlocks` are normalized only where they are\n // read; otherwise they stay as written, as in 1.44.0.\n if (this.options.responsesTools === \"extended\" && !isLiveResponse(normalized)) {\n normalizeResponsesToolsKeys(normalized as unknown as Record<string, unknown>);\n }\n }\n return this.addFixture(this.own({ match, response: normalized, ...opts }));\n }\n\n onLive(\n match: Omit<FixtureMatch, \"endpoint\">,\n transcript: LiveTranscript,\n opts?: FixtureOpts,\n ): this {\n return this.on({ ...match, endpoint: \"openai-live\" }, { live: transcript }, opts);\n }\n\n onMessage(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern }, response, opts);\n }\n\n onEmbedding(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: EmbeddingFixtureOpts,\n ): this {\n return this.on({ inputText: pattern }, response, opts);\n }\n\n onJsonOutput(pattern: string | RegExp, jsonContent: object | string, opts?: FixtureOpts): this {\n const content = typeof jsonContent === \"string\" ? jsonContent : JSON.stringify(jsonContent);\n return this.on({ userMessage: pattern, responseFormat: \"json_object\" }, { content }, opts);\n }\n\n onToolCall(\n name: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolName: name }, response, opts);\n }\n\n onToolResult(\n id: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolCallId: id }, response, opts);\n }\n\n onTurn(\n turn: number,\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern, turnIndex: turn }, response, opts);\n }\n\n onImage(prompt: string | RegExp, response: ImageResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"image\" },\n response,\n }),\n );\n }\n\n onSpeech(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: input, endpoint: \"speech\" },\n response,\n }),\n );\n }\n\n onTranscription(response: TranscriptionResponse): this {\n return this.addFixture(\n this.own({\n match: { endpoint: \"transcription\" },\n response,\n }),\n );\n }\n\n onTranslation(response: TranscriptionResponse): this {\n return this.addFixture(\n this.own({\n match: { endpoint: \"translation\" },\n response,\n }),\n );\n }\n\n onVideo(prompt: string | RegExp, response: VideoResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"video\" },\n response,\n }),\n );\n }\n\n onAudio(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture(this.own({ match: { userMessage: input }, response }));\n }\n\n onSoundEffect(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: text, endpoint: \"audio-gen\" },\n response,\n }),\n );\n }\n\n onMusic(prompt: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"audio-gen\" },\n response,\n }),\n );\n }\n\n onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: text, endpoint: \"elevenlabs-tts\" },\n response,\n }),\n );\n }\n\n onElevenLabsVoiceDesign(description: string | RegExp, response: VoiceDesignResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: description, endpoint: \"elevenlabs-voice-design\" },\n response: voiceDesignToJson(response),\n }),\n );\n }\n\n onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"fal-audio\", ...(model ? { model } : {}) },\n response,\n }),\n );\n }\n\n // fal.queue.* is the dominant client API; onFalRun is a sync alias.\n //\n // `opts.billableUnits` rides through to the completed `queue-result`\n // response's `x-fal-billable-units` header (emitted alongside\n // `x-fal-request-id`), letting consumers like `@tanstack/ai-fal` surface a\n // billed-units value on replay. Omit it to preserve the header-less default.\n onFalQueue(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n const { billableUnits, ...fixtureOpts } = opts ?? {};\n return this.addFixture(\n this.own({\n match: { model: modelOrPrompt, endpoint: \"fal\" },\n response: { json: response, ...(billableUnits != null ? { billableUnits } : {}) },\n ...fixtureOpts,\n }),\n );\n }\n\n onFalRun(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, response, opts);\n }\n\n /**\n * Register a fal.ai image fixture. Wraps an `ImageResponse` (the shape used\n * by `onImage` and OpenAI/Azure image fixtures) into fal's image envelope\n * before storing it as a `RawJSONResponse`. Defaults `width`/`height` to\n * 1024 when the fixture's `ImageItem` doesn't carry them.\n */\n onFalImage(modelOrPrompt: string | RegExp, response: ImageResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, imageResponseToFalJson(response), opts);\n }\n\n /**\n * Register a fal.ai video fixture. Wraps a `VideoResponse` into fal's video\n * envelope (`{ video: { url, content_type, file_name, file_size }, seed }`)\n * before storing it as a `RawJSONResponse`.\n */\n onFalVideo(modelOrPrompt: string | RegExp, response: VideoResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, videoResponseToFalJson(response), opts);\n }\n\n // ---- Service mock convenience methods ----\n\n onSearch(pattern: string | RegExp, results: SearchResult[]): this {\n this.searchFixtures.push({ match: pattern, results });\n return this;\n }\n\n onRerank(pattern: string | RegExp, results: RerankResult[]): this {\n this.rerankFixtures.push({ match: pattern, results });\n return this;\n }\n\n onModerate(pattern: string | RegExp, result: ModerationResult): this {\n this.moderationFixtures.push({ match: pattern, result });\n return this;\n }\n\n /**\n * Queue a one-shot error that will be returned for the next matching\n * request, then automatically removed. Implemented as an internal fixture\n * inserted at the front of the fixture list; see `queueOneShotError` for\n * the endpoint gate and the served-not-evaluated consumption rule.\n */\n nextRequestError(\n status: number,\n errorBody?: { message?: string; type?: string; code?: string },\n ): this {\n // Same gate as `POST /__aimock/error` and fixture validation — this is the\n // form the docs use, and an unchecked status reaches `res.writeHead` on\n // the next matched request: 99/1000 throw there (the injected error is\n // lost and the caller sees a generic 500), and 1xx hangs the request until\n // the client times out. Throwing HERE names the offending call instead.\n if (!isInjectableStatus(status)) {\n throw new RangeError(\n `nextRequestError: invalid status ${String(status)} — must be ${INJECTED_STATUS_RANGE}`,\n );\n }\n queueOneShotError(this.fixtures, status, errorBody);\n return this;\n }\n\n // ---- Mounts ----\n\n mount(path: string, handler: Mountable): this {\n // W4: an auto-mounted MCPMock at `path` takes its requests first (dispatch\n // takes the first match), so the new mount is shadowed; so is one at\n // `path` plus \"/\", whose root request the auto-mount answers as its own.\n // An auto-mount lets any other sub-path fall through: that is no shadow.\n const shadowedBy = this.serverInstance\n ? this.mounts.find(\n (m) => isAutoMount(m.handler) && (path === m.path || path === m.path + \"/\"),\n )\n : undefined;\n this.mounts.push({ path, handler });\n\n // If server is already running, wire up journal, registry, logger and baseUrl\n // immediately so late mounts behave identically to pre-start mounts.\n if (this.serverInstance) {\n if (handler.setJournal) handler.setJournal(this.serverInstance.journal);\n if (handler.setBaseUrl) handler.setBaseUrl(this.serverInstance.url + path);\n const registry = this.serverInstance.defaults.registry;\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n const logger = this.serverInstance.defaults.logger;\n if (handler.setLogger) handler.setLogger(logger);\n // B11/R12: only aimock's own MCPMock takes the replay speed; a custom\n // Mountable is never called (1.44.0 had no such hook).\n if (handler instanceof MCPMock) {\n handler.setReplaySpeed(this.serverInstance.defaults.replaySpeed);\n }\n if (shadowedBy) {\n logger.warn(\n build(\n msg`MCP fakes: the mount at ${quote(path)} is shadowed by the MCP mock auto-mounted at ${quote(shadowedBy.path)}; its requests reach the auto-mount`,\n ),\n );\n }\n }\n\n return this;\n }\n\n // ---- Journal proxies ----\n\n getRequests(): import(\"./types.js\").JournalEntry[] {\n return this.journal.getAll();\n }\n\n getLastRequest(): import(\"./types.js\").JournalEntry | null {\n return this.journal.getLast();\n }\n\n /**\n * Clear the request journal. Fixture match-counts (sequencing state) are\n * left intact — use `resetMatchCounts()` for those.\n */\n clearRequests(): void {\n this.journal.clearEntries();\n }\n\n /**\n * Reset fixture match counts, and the MCP fakes consumption state of every\n * mount (R6), for `testId` or for all test ids. Fakes stay loaded.\n */\n resetMatchCounts(testId?: string): this {\n if (this.serverInstance) {\n this.serverInstance.journal.clearMatchCounts(testId);\n }\n for (const { handler } of this.mounts) handler.resetScenarioState?.(testId);\n return this;\n }\n\n // ---- Chaos ----\n\n /**\n * Set the server-wide chaos baseline. Writes through to a RUNNING server as\n * well as the construction options: an untagged `POST /__aimock/chaos`\n * installs a baseline override that shadows `options.chaos`, and without this\n * the call would silently do nothing until the next `reset()`. Per-testId\n * overrides still win over the baseline.\n */\n setChaos(config: ChaosConfig): this {\n this.options.chaos = config;\n if (this.serverInstance) this.serverInstance.defaults.chaos = config;\n return this;\n }\n\n /**\n * Turn chaos off everywhere: the construction config, the runtime baseline,\n * and every per-testId override (assigning `undefined` is the full-clear\n * signal the `defaults.chaos` setter defines).\n */\n clearChaos(): this {\n delete this.options.chaos;\n if (this.serverInstance) this.serverInstance.defaults.chaos = undefined;\n return this;\n }\n\n // ---- Semantic misbehavior ----\n\n /** Replace construction/runtime baselines without changing named test overrides. */\n setMisbehavior(config: MisbehaviorConfig | MisbehaviorFaultId): this {\n if (!this.misbehaviorEnabled) {\n throw new TypeError(\n \"setMisbehavior: misbehavior is not enabled; construct with enableMisbehavior: true\",\n );\n }\n const parsed = parseMisbehavior(config);\n if (!parsed.ok) throw new TypeError(`${parsed.issue.rule}: ${parsed.issue.message}`);\n this.options.misbehavior = parsed.config;\n const defaults = this.serverInstance?.defaults;\n if (defaults?.misbehavior) {\n defaults.misbehavior.baseline =\n parsed.config.seed === \"random\"\n ? { ...parsed.config, seed: resolveMisbehaviorSeed(parsed.config.seed, defaults.logger) }\n : parsed.config;\n if (defaults.misbehavior.byTestId.has(DEFAULT_TEST_ID)) {\n defaults.misbehavior.byTestId.set(DEFAULT_TEST_ID, defaults.misbehavior.baseline);\n }\n }\n return this;\n }\n\n /** Clear the baseline and all runtime overrides, before or after start. */\n clearMisbehavior(): this {\n delete this.options.misbehavior;\n const scope = this.serverInstance?.defaults.misbehavior;\n if (scope) {\n scope.baseline = undefined;\n scope.byTestId.clear();\n }\n return this;\n }\n\n // ---- Recording ----\n\n enableRecording(config: RecordConfig): this {\n this.options.record = config;\n return this;\n }\n\n disableRecording(): this {\n delete this.options.record;\n return this;\n }\n\n // ---- Reset ----\n\n /**\n * Full reset — the in-process equivalent of `POST /__aimock/reset`. Shares\n * one implementation with the control-API route so the two cannot drift.\n *\n * The one deliberate difference: search / rerank / moderation fixtures are\n * also cleared here. Those are registered through this class only — the\n * control API has no route that creates them, so the HTTP reset can neither\n * reach nor observe them.\n *\n * NOT ALL OF THIS IS PER-INSTANCE. `performFullReset` clears module-global\n * state as well: the Gemini interaction and event-id counters\n * (`resetInteractionCounter` / `resetEventIdCounter` in\n * `./gemini-interactions.js`), the fal.ai job/queue maps (`falJobs`,\n * `falQueueStates`), the fine-tuning job store (`clearFineTuningStore`),\n * and the ElevenLabs Voice Design store (`clearElevenLabsVoices`). With two\n * `LLMock` instances live in one process,\n * `a.reset()` rewinds the Gemini id sequence that `b` is mid-way through —\n * `b` then re-emits `aimock-int-0` / `evt_1`, ids it has already handed\n * out — and drops `b`'s in-flight fal jobs. Give each instance its own\n * process (or its own vitest worker) if that matters.\n *\n * The global stores are cleared even before `start()`, when there is no\n * server instance to reset.\n */\n reset(): this {\n this.searchFixtures.length = 0;\n this.rerankFixtures.length = 0;\n this.moderationFixtures.length = 0;\n // `ServerInstance` carries no mounts, so the fakes are unloaded here (R4).\n this.unloadMcpFakes();\n performFullReset(this.fixtures, this.serverInstance);\n return this;\n }\n\n // ---- Server lifecycle ----\n\n async start(): Promise<string> {\n if (this.serverInstance) {\n throw new Error(\"Server already started\");\n }\n const serviceFixtures = {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n mcpFakes: [...this.mcpFakeBuffer],\n };\n this.serverInstance = await (this.resolvedInboundAuth\n ? createServerWithResolvedAuth(\n this.fixtures,\n this.options,\n this.resolvedInboundAuth,\n this.mounts,\n serviceFixtures,\n )\n : createServer(this.fixtures, this.options, this.mounts, serviceFixtures));\n const countIdentity = (fixture: Fixture) => this.fixtureCountOrigins.get(fixture) ?? fixture;\n this.serverInstance.journal.configureFixtureCountIdentity(countIdentity);\n // The server holds the buffered fakes now (W2). A start that rejects took\n // its hand-off back, so the buffer is kept for a retry.\n this.mcpFakeBuffer.length = 0;\n return this.serverInstance.url;\n }\n\n closeLiveSessions(testId?: string): this {\n this.serverInstance?.closeLiveSessions(testId);\n return this;\n }\n\n async stop(): Promise<void> {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n const { server } = this.serverInstance;\n await new Promise<void>((resolve, reject) => {\n server.close((err: Error | undefined) => (err ? reject(err) : resolve()));\n });\n this.serverInstance = null;\n }\n\n // ---- Accessors ----\n\n get journal(): Journal {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.journal;\n }\n\n get url(): string {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.url;\n }\n\n get baseUrl(): string {\n return this.url;\n }\n\n get port(): number {\n const parsed = new URL(this.url); // this.url throws if not started\n if (!parsed.port) {\n throw new Error(`Server URL has no explicit port: ${this.url}`);\n }\n return parseInt(parsed.port, 10);\n }\n\n // ---- Static factory ----\n\n static async create(options?: MockServerOptions): Promise<LLMock> {\n const instance = new LLMock(options);\n await instance.start();\n return instance;\n }\n}\n\n/** @internal Configuration startup preserves a policy resolved from the selected source. */\nexport function createLLMockWithResolvedAuth(\n options: MockServerOptions,\n resolvedAuth: ResolvedInboundAuth,\n): LLMock {\n return new LLMock(options, resolvedAuth);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llmock.js","names":[],"sources":["../src/llmock.ts"],"sourcesContent":["import type { LiveTranscript } from \"./live-types.js\";\nimport { normalizeLiveFixture, normalizeLiveOptions } from \"./live-fixture.js\";\nimport { isLiveResponse, markServerOwnedFixtures } from \"./helpers.js\";\nimport type {\n AudioResponse,\n ChaosConfig,\n EmbeddingFixtureOpts,\n FalQueueOpts,\n Fixture,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureMatch,\n FixtureOpts,\n FixtureResponse,\n ImageResponse,\n McpFakeSource,\n MockServerOptions,\n MisbehaviorConfig,\n MisbehaviorFaultId,\n Mountable,\n RecordConfig,\n ResponseFactory,\n TranscriptionResponse,\n VideoResponse,\n VoiceDesignResponse,\n} from \"./types.js\";\nimport {\n createServer,\n createServerWithResolvedAuth,\n performFullReset,\n type ServerInstance,\n} from \"./server.js\";\nimport type { ResolvedInboundAuth } from \"./api-key-auth.js\";\nimport {\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n queueOneShotError,\n clearFixtureQueue,\n entryToFixture,\n normalizeResponse,\n normalizeResponsesToolsKeys,\n validateFixtures,\n enableHeldFixtureMisbehavior,\n markFixtureResponsesToolsExtended,\n markFixtureMisbehaviorEnabled,\n MisbehaviorConfigError,\n} from \"./fixture-loader.js\";\nimport {\n loadFixtureFileWithServices,\n loadFixturesFromDirWithServices,\n type FixturesWithServices,\n} from \"./fixture-loader-services.js\";\nimport { ensureFakeMount, isAutoMount, planFileFakes } from \"./mcp-fakes-mount.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { build, msg, quote } from \"./message-text.js\";\nimport { DEFAULT_TEST_ID } from \"./constants.js\";\nimport { Journal } from \"./journal.js\";\nimport type { SearchFixture, SearchResult } from \"./search.js\";\nimport type { RerankFixture, RerankResult } from \"./rerank.js\";\nimport type { ModerationFixture, ModerationResult } from \"./moderation.js\";\nimport { imageResponseToFalJson, videoResponseToFalJson } from \"./fal.js\";\nimport { voiceDesignToJson } from \"./elevenlabs-voice.js\";\nimport { Logger } from \"./logger.js\";\nimport { parsePolicy } from \"./response/policy.js\";\n\nimport {\n getFixtureMisbehaviorPosition,\n parseMisbehavior,\n resolveMisbehaviorSeed,\n setFixtureMisbehaviorPosition,\n validateFixtureMisbehavior,\n} from \"./misbehavior.js\";\n\nexport class LLMock {\n private fixtures: Fixture[] = [];\n private fixtureAddition = 0;\n private readonly fixtureCountOrigins = new WeakMap<Fixture, Fixture>();\n /**\n * Fixtures this LLMock built itself (on() and the other helpers), so the\n * caller never held them: the stored object is their identity.\n */\n private readonly ownFixtures = new WeakSet<Fixture>();\n private searchFixtures: SearchFixture[] = [];\n private rerankFixtures: RerankFixture[] = [];\n private moderationFixtures: ModerationFixture[] = [];\n private mounts: Array<{ path: string; handler: Mountable }> = [];\n /** `mcpFakes` blocks loaded before `start()`, handed to the server at start (W2). */\n private mcpFakeBuffer: McpFakeSource[] = [];\n /** MCPMocks the server or a load auto-mounted (W3, W6), for the L6 check. */\n private serverInstance: ServerInstance | null = null;\n private options: MockServerOptions;\n private readonly resolvedInboundAuth?: ResolvedInboundAuth;\n\n constructor(options?: MockServerOptions, resolvedInboundAuth?: ResolvedInboundAuth) {\n // Only this LLMock's server reads its array, so fixtures it makes may be marked in place.\n markServerOwnedFixtures(this.fixtures);\n this.options = options ?? {};\n // Validate this public entry point without copying or changing caller options.\n parsePolicy(this.options.policy, (message) => new Logger(\"warn\").warn(message));\n if (this.options.live !== undefined) normalizeLiveOptions(this.options.live);\n // The `misbehavior` option is read only with `enableMisbehavior: true`;\n // otherwise it is unused data, as in 1.44.0.\n if (this.misbehaviorEnabled && this.options.misbehavior !== undefined) {\n this.setMisbehavior(this.options.misbehavior);\n }\n this.resolvedInboundAuth = resolvedInboundAuth;\n }\n\n /** Misbehavior (fixture keys, header, `misbehavior` option) needs `enableMisbehavior: true`. */\n private get misbehaviorEnabled(): boolean {\n return this.options.enableMisbehavior === true;\n }\n\n // ---- Fixture management ----\n\n private normalizeFixture(fixture: Fixture): Fixture {\n const misbehaviorEnabled = this.misbehaviorEnabled;\n // A fixture loaded from a file holds its `misbehavior` key until enabled.\n if (misbehaviorEnabled) enableHeldFixtureMisbehavior(fixture);\n // A fixture this LLMock built (on() and the helpers) is new to it, so it\n // needs no per-addition copy, and the object stored is its identity.\n const own = this.ownFixtures.delete(fixture);\n const countIdentity = own ? undefined : (this.fixtureCountOrigins.get(fixture) ?? fixture);\n const previousPosition = getFixtureMisbehaviorPosition(fixture);\n const isNewAddition = previousPosition === undefined || /^code#\\d+$/.test(previousPosition);\n const position = isNewAddition ? `code#${this.fixtureAddition++}` : previousPosition;\n // With misbehavior enabled, re-adding a code fixture creates a new fault\n // source without changing the old entry, so each addition is its own copy.\n // The journal counts and records every copy under the caller's object\n // (fixtureCountOrigins), so the identity APIs read as they do without\n // misbehavior: an object added twice is one caller fixture, as in 1.44.0.\n // Without misbehavior the position is never read, and the caller's object\n // is stored as in 1.44.0.\n if (isNewAddition && misbehaviorEnabled && !own) fixture = { ...fixture };\n if (misbehaviorEnabled && fixture.misbehavior !== undefined) {\n const parsed = parseMisbehavior(fixture.misbehavior);\n if (parsed.ok) fixture = { ...fixture, misbehavior: parsed.config };\n const issue = parsed.ok ? validateFixtureMisbehavior(fixture) : parsed.issue;\n if (issue) {\n throw new MisbehaviorConfigError({\n rule: issue.rule,\n file: position,\n detail: issue.message,\n });\n }\n }\n\n if (\n isLiveResponse(fixture.response) ||\n (fixture.match.endpoint === \"openai-live\" && typeof fixture.response !== \"function\")\n ) {\n fixture = {\n ...fixture,\n match: { ...fixture.match },\n response: normalizeLiveFixture(fixture.response, this.options.live),\n };\n } else if (countIdentity !== undefined && fixture !== countIdentity) {\n this.fixtureCountOrigins.set(fixture, countIdentity);\n }\n setFixtureMisbehaviorPosition(fixture, position);\n if (misbehaviorEnabled && fixture.misbehavior !== undefined) {\n markFixtureMisbehaviorEnabled(fixture);\n }\n // A fixture passed in is not marked for responsesTools \"extended\": the\n // server reads it through its extended view, so the caller's object (which\n // another server may share) is left as it was loaded.\n return fixture;\n }\n\n addFixture(fixture: Fixture): this {\n this.fixtures.push(this.normalizeFixture(fixture));\n return this;\n }\n\n addFixtures(fixtures: Fixture[]): this {\n this.fixtures.push(...fixtures.map((fixture) => this.normalizeFixture(fixture)));\n return this;\n }\n\n prependFixture(fixture: Fixture): this {\n this.fixtures.unshift(this.normalizeFixture(fixture));\n return this;\n }\n\n /** Mark a fixture this LLMock built, for {@link normalizeFixture}. */\n private own(fixture: Fixture): Fixture {\n this.ownFixtures.add(fixture);\n return fixture;\n }\n\n getFixtures(): readonly Fixture[] {\n return this.fixtures;\n }\n\n /**\n * Load a fixture file: its LLM fixtures and its `mcpFakes` blocks (F4).\n * Before `start()` the blocks are buffered and handed to the server at\n * start (W2); after it they go to the MCPMock serving each block's `mount`\n * path, auto-mounted when none does (W6). A block that cannot be honored\n * throws a `FixtureLoadError` and nothing from the file is added.\n */\n loadFixtureFile(filePath: string): this {\n return this.acceptLoaded(loadFixtureFileWithServices(filePath, undefined, this.options.live));\n }\n\n /** As {@link loadFixtureFile}, for every fixture file under `dirPath`. */\n loadFixtureDir(dirPath: string): this {\n return this.acceptLoaded(\n loadFixturesFromDirWithServices(dirPath, undefined, this.options.live),\n );\n }\n\n /**\n * Add a load's fakes (all or nothing), then its LLM fixtures. Before start\n * the fakes are checked as the start-time hand-off will check them, with\n * the blocks already buffered and the mounts added so far, so a file whose\n * fakes would be rejected adds nothing. A mount added after the load can\n * still make `start()` reject.\n */\n private acceptLoaded(loaded: FixturesWithServices): this {\n // With misbehavior enabled, a bad `misbehavior` key throws before anything is added.\n if (this.misbehaviorEnabled) loaded.fixtures.forEach(enableHeldFixtureMisbehavior);\n if (this.options.responsesTools === \"extended\") {\n loaded.fixtures.forEach(markFixtureResponsesToolsExtended);\n }\n if (loaded.mcpFakes.length > 0) {\n if (this.serverInstance) {\n this.addFakesAfterStart(this.serverInstance, loaded.mcpFakes);\n } else {\n planFileFakes(\n this.mounts,\n [...this.mcpFakeBuffer, ...loaded.mcpFakes],\n new Set(loaded.mcpFakes),\n );\n this.mcpFakeBuffer.push(...loaded.mcpFakes);\n }\n }\n this.fixtures.push(...loaded.fixtures);\n return this;\n }\n\n /**\n * W6 for a load after start. Every group of blocks (by `mount` path) is\n * checked before any mount is touched: a path held by a mount that is not\n * an MCPMock is a mount conflict, and each group is first added to a\n * throwaway store. Groups for an existing MCPMock are then added to it (its\n * own add is all or nothing and finds collisions with its loaded ids);\n * groups for a free path are added last, to a new auto-mounted MCPMock,\n * wired as W4. The add warnings (L8) are logged at `warn`.\n */\n private addFakesAfterStart(server: ServerInstance, sources: McpFakeSource[]): void {\n const { onExisting, onNew } = planFileFakes(this.mounts, sources);\n\n const logger = server.defaults.logger;\n for (const { handler, group } of onExisting) {\n const result = handler.addMcpFakes?.(group, { kind: \"file\" });\n for (const warning of result?.warnings ?? []) logger.warn(warning.message);\n }\n const registry = server.defaults.registry;\n for (const { path, group } of onNew) {\n const target = ensureFakeMount(\n this.mounts,\n path,\n {\n journal: server.journal,\n ...(registry ? { registry } : {}),\n logger,\n replaySpeed: server.defaults.replaySpeed,\n },\n logger,\n );\n // The check above found no mount at this path, and nothing ran since.\n if (\"conflict\" in target) continue;\n const result = target.handler.addMcpFakes?.(group, { kind: \"file\" });\n for (const warning of result?.warnings ?? []) logger.warn(warning.message);\n }\n }\n\n /** R4, R5: unload the fakes of every mount and the pre-start buffer. */\n private unloadMcpFakes(): void {\n this.mcpFakeBuffer.length = 0;\n for (const { handler } of this.mounts) handler.clearMcpFakes?.();\n }\n\n /**\n * Add fixtures from a JSON string or pre-parsed array of fixture entries.\n * Validates all fixtures and throws if any have severity \"error\".\n */\n addFixturesFromJSON(input: string | FixtureFileEntry[]): this {\n let entries: FixtureFileEntry[];\n if (typeof input === \"string\") {\n try {\n entries = JSON.parse(input);\n } catch (err) {\n throw new Error(\n `addFixturesFromJSON: invalid JSON — ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else {\n entries = input;\n }\n if (!Array.isArray(entries)) {\n throw new TypeError(\n \"addFixturesFromJSON: expected an array of fixture entries; use loadFixtureFile for a {fixtures:[...]} file\",\n );\n }\n const converted = entries.map((entry) => {\n const position = `code#${this.fixtureAddition++}`;\n const fixture = entryToFixture(entry, undefined, this.options.live, {\n file: position,\n index: 0,\n });\n setFixtureMisbehaviorPosition(fixture, position);\n if (this.misbehaviorEnabled) enableHeldFixtureMisbehavior(fixture);\n if (this.options.responsesTools === \"extended\") markFixtureResponsesToolsExtended(fixture);\n return fixture;\n });\n\n const issues = validateFixtures(converted, this.options.live);\n const errors = issues.filter((i) => i.severity === \"error\");\n if (errors.length > 0) {\n throw new Error(`Fixture validation failed: ${JSON.stringify(errors)}`);\n }\n this.fixtures.push(...converted);\n return this;\n }\n\n // Clears in place to preserve array reference identity — the running\n // server reads this same array on every request — and invalidates any\n // one-shot claim parked in flight so it cannot re-arm into the cleared queue.\n clearFixtures(): this {\n clearFixtureQueue(this.fixtures);\n this.serverInstance?.journal.clearMisbehaviorCounters();\n this.unloadMcpFakes();\n return this;\n }\n\n // ---- Convenience ----\n\n on(\n match: FixtureMatch,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n let normalized: FixtureResponse | ResponseFactory = response as ResponseFactory;\n if (typeof response !== \"function\") {\n normalized = normalizeResponse(response, this.options.live);\n // `customToolCalls` / `responsesBlocks` are normalized only where they are\n // read; otherwise they stay as written, as in 1.44.0.\n if (this.options.responsesTools === \"extended\" && !isLiveResponse(normalized)) {\n normalizeResponsesToolsKeys(normalized as unknown as Record<string, unknown>);\n }\n }\n return this.addFixture(this.own({ match, response: normalized, ...opts }));\n }\n\n onLive(\n match: Omit<FixtureMatch, \"endpoint\">,\n transcript: LiveTranscript,\n opts?: FixtureOpts,\n ): this {\n return this.on({ ...match, endpoint: \"openai-live\" }, { live: transcript }, opts);\n }\n\n onMessage(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern }, response, opts);\n }\n\n onEmbedding(\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: EmbeddingFixtureOpts,\n ): this {\n return this.on({ inputText: pattern }, response, opts);\n }\n\n onJsonOutput(pattern: string | RegExp, jsonContent: object | string, opts?: FixtureOpts): this {\n const content = typeof jsonContent === \"string\" ? jsonContent : JSON.stringify(jsonContent);\n return this.on({ userMessage: pattern, responseFormat: \"json_object\" }, { content }, opts);\n }\n\n onToolCall(\n name: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolName: name }, response, opts);\n }\n\n onToolResult(\n id: string,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ toolCallId: id }, response, opts);\n }\n\n onTurn(\n turn: number,\n pattern: string | RegExp,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.on({ userMessage: pattern, turnIndex: turn }, response, opts);\n }\n\n onImage(prompt: string | RegExp, response: ImageResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"image\" },\n response,\n }),\n );\n }\n\n onSpeech(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: input, endpoint: \"speech\" },\n response,\n }),\n );\n }\n\n onTranscription(response: TranscriptionResponse): this {\n return this.addFixture(\n this.own({\n match: { endpoint: \"transcription\" },\n response,\n }),\n );\n }\n\n onTranslation(response: TranscriptionResponse): this {\n return this.addFixture(\n this.own({\n match: { endpoint: \"translation\" },\n response,\n }),\n );\n }\n\n onVideo(prompt: string | RegExp, response: VideoResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"video\" },\n response,\n }),\n );\n }\n\n onAudio(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture(this.own({ match: { userMessage: input }, response }));\n }\n\n onSoundEffect(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: text, endpoint: \"audio-gen\" },\n response,\n }),\n );\n }\n\n onMusic(prompt: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"audio-gen\" },\n response,\n }),\n );\n }\n\n onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: text, endpoint: \"elevenlabs-tts\" },\n response,\n }),\n );\n }\n\n onElevenLabsVoiceDesign(description: string | RegExp, response: VoiceDesignResponse): this {\n return this.addFixture(\n this.own({\n match: { userMessage: description, endpoint: \"elevenlabs-voice-design\" },\n response: voiceDesignToJson(response),\n }),\n );\n }\n\n onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this {\n return this.addFixture(\n this.own({\n match: { userMessage: prompt, endpoint: \"fal-audio\", ...(model ? { model } : {}) },\n response,\n }),\n );\n }\n\n // fal.queue.* is the dominant client API; onFalRun is a sync alias.\n //\n // `opts.billableUnits` rides through to the completed `queue-result`\n // response's `x-fal-billable-units` header (emitted alongside\n // `x-fal-request-id`), letting consumers like `@tanstack/ai-fal` surface a\n // billed-units value on replay. Omit it to preserve the header-less default.\n onFalQueue(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n const { billableUnits, ...fixtureOpts } = opts ?? {};\n return this.addFixture(\n this.own({\n match: { model: modelOrPrompt, endpoint: \"fal\" },\n response: { json: response, ...(billableUnits != null ? { billableUnits } : {}) },\n ...fixtureOpts,\n }),\n );\n }\n\n onFalRun(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, response, opts);\n }\n\n /**\n * Register a fal.ai image fixture. Wraps an `ImageResponse` (the shape used\n * by `onImage` and OpenAI/Azure image fixtures) into fal's image envelope\n * before storing it as a `RawJSONResponse`. Defaults `width`/`height` to\n * 1024 when the fixture's `ImageItem` doesn't carry them.\n */\n onFalImage(modelOrPrompt: string | RegExp, response: ImageResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, imageResponseToFalJson(response), opts);\n }\n\n /**\n * Register a fal.ai video fixture. Wraps a `VideoResponse` into fal's video\n * envelope (`{ video: { url, content_type, file_name, file_size }, seed }`)\n * before storing it as a `RawJSONResponse`.\n */\n onFalVideo(modelOrPrompt: string | RegExp, response: VideoResponse, opts?: FalQueueOpts): this {\n return this.onFalQueue(modelOrPrompt, videoResponseToFalJson(response), opts);\n }\n\n // ---- Service mock convenience methods ----\n\n onSearch(pattern: string | RegExp, results: SearchResult[]): this {\n this.searchFixtures.push({ match: pattern, results });\n return this;\n }\n\n onRerank(pattern: string | RegExp, results: RerankResult[]): this {\n this.rerankFixtures.push({ match: pattern, results });\n return this;\n }\n\n onModerate(pattern: string | RegExp, result: ModerationResult): this {\n this.moderationFixtures.push({ match: pattern, result });\n return this;\n }\n\n /**\n * Queue a one-shot error that will be returned for the next matching\n * request, then automatically removed. Implemented as an internal fixture\n * inserted at the front of the fixture list; see `queueOneShotError` for\n * the endpoint gate and the served-not-evaluated consumption rule.\n */\n nextRequestError(\n status: number,\n errorBody?: { message?: string; type?: string; code?: string },\n ): this {\n // Same gate as `POST /__aimock/error` and fixture validation — this is the\n // form the docs use, and an unchecked status reaches `res.writeHead` on\n // the next matched request: 99/1000 throw there (the injected error is\n // lost and the caller sees a generic 500), and 1xx hangs the request until\n // the client times out. Throwing HERE names the offending call instead.\n if (!isInjectableStatus(status)) {\n throw new RangeError(\n `nextRequestError: invalid status ${String(status)} — must be ${INJECTED_STATUS_RANGE}`,\n );\n }\n queueOneShotError(this.fixtures, status, errorBody);\n return this;\n }\n\n // ---- Mounts ----\n\n mount(path: string, handler: Mountable): this {\n // W4: an auto-mounted MCPMock at `path` takes its requests first (dispatch\n // takes the first match), so the new mount is shadowed; so is one at\n // `path` plus \"/\", whose root request the auto-mount answers as its own.\n // An auto-mount lets any other sub-path fall through: that is no shadow.\n const shadowedBy = this.serverInstance\n ? this.mounts.find(\n (m) => isAutoMount(m.handler) && (path === m.path || path === m.path + \"/\"),\n )\n : undefined;\n this.mounts.push({ path, handler });\n\n // If server is already running, wire up journal, registry, logger and baseUrl\n // immediately so late mounts behave identically to pre-start mounts.\n if (this.serverInstance) {\n if (handler.setJournal) handler.setJournal(this.serverInstance.journal);\n if (handler.setBaseUrl) handler.setBaseUrl(this.serverInstance.url + path);\n const registry = this.serverInstance.defaults.registry;\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n const logger = this.serverInstance.defaults.logger;\n if (handler.setLogger) handler.setLogger(logger);\n // B11/R12: only aimock's own MCPMock takes the replay speed; a custom\n // Mountable is never called (1.44.0 had no such hook).\n if (handler instanceof MCPMock) {\n handler.setReplaySpeed(this.serverInstance.defaults.replaySpeed);\n }\n if (shadowedBy) {\n logger.warn(\n build(\n msg`MCP fakes: the mount at ${quote(path)} is shadowed by the MCP mock auto-mounted at ${quote(shadowedBy.path)}; its requests reach the auto-mount`,\n ),\n );\n }\n }\n\n return this;\n }\n\n // ---- Journal proxies ----\n\n getRequests(): import(\"./types.js\").JournalEntry[] {\n return this.journal.getAll();\n }\n\n getLastRequest(): import(\"./types.js\").JournalEntry | null {\n return this.journal.getLast();\n }\n\n /**\n * Clear the request journal. Fixture match-counts (sequencing state) are\n * left intact — use `resetMatchCounts()` for those.\n */\n clearRequests(): void {\n this.journal.clearEntries();\n }\n\n /**\n * Reset fixture match counts, and the MCP fakes consumption state of every\n * mount (R6), for `testId` or for all test ids. Fakes stay loaded.\n */\n resetMatchCounts(testId?: string): this {\n if (this.serverInstance) {\n this.serverInstance.journal.clearMatchCounts(testId);\n }\n for (const { handler } of this.mounts) handler.resetScenarioState?.(testId);\n return this;\n }\n\n // ---- Chaos ----\n\n /**\n * Set the server-wide chaos baseline. Writes through to a RUNNING server as\n * well as the construction options: an untagged `POST /__aimock/chaos`\n * installs a baseline override that shadows `options.chaos`, and without this\n * the call would silently do nothing until the next `reset()`. Per-testId\n * overrides still win over the baseline.\n */\n setChaos(config: ChaosConfig): this {\n this.options.chaos = config;\n if (this.serverInstance) this.serverInstance.defaults.chaos = config;\n return this;\n }\n\n /**\n * Turn chaos off everywhere: the construction config, the runtime baseline,\n * and every per-testId override (assigning `undefined` is the full-clear\n * signal the `defaults.chaos` setter defines).\n */\n clearChaos(): this {\n delete this.options.chaos;\n if (this.serverInstance) this.serverInstance.defaults.chaos = undefined;\n return this;\n }\n\n // ---- Semantic misbehavior ----\n\n /** Replace construction/runtime baselines without changing named test overrides. */\n setMisbehavior(config: MisbehaviorConfig | MisbehaviorFaultId): this {\n if (!this.misbehaviorEnabled) {\n throw new TypeError(\n \"setMisbehavior: misbehavior is not enabled; construct with enableMisbehavior: true\",\n );\n }\n const parsed = parseMisbehavior(config);\n if (!parsed.ok) throw new TypeError(`${parsed.issue.rule}: ${parsed.issue.message}`);\n this.options.misbehavior = parsed.config;\n const defaults = this.serverInstance?.defaults;\n if (defaults?.misbehavior) {\n defaults.misbehavior.baseline =\n parsed.config.seed === \"random\"\n ? { ...parsed.config, seed: resolveMisbehaviorSeed(parsed.config.seed, defaults.logger) }\n : parsed.config;\n if (defaults.misbehavior.byTestId.has(DEFAULT_TEST_ID)) {\n defaults.misbehavior.byTestId.set(DEFAULT_TEST_ID, defaults.misbehavior.baseline);\n }\n }\n return this;\n }\n\n /** Clear the baseline and all runtime overrides, before or after start. */\n clearMisbehavior(): this {\n delete this.options.misbehavior;\n const scope = this.serverInstance?.defaults.misbehavior;\n if (scope) {\n scope.baseline = undefined;\n scope.byTestId.clear();\n }\n return this;\n }\n\n // ---- Recording ----\n\n enableRecording(config: RecordConfig): this {\n this.options.record = config;\n return this;\n }\n\n disableRecording(): this {\n delete this.options.record;\n return this;\n }\n\n // ---- Reset ----\n\n /**\n * Full reset — the in-process equivalent of `POST /__aimock/reset`. Shares\n * one implementation with the control-API route so the two cannot drift.\n *\n * The one deliberate difference: search / rerank / moderation fixtures are\n * also cleared here. Those are registered through this class only — the\n * control API has no route that creates them, so the HTTP reset can neither\n * reach nor observe them.\n *\n * NOT ALL OF THIS IS PER-INSTANCE. `performFullReset` clears module-global\n * state as well: the Gemini interaction and event-id counters\n * (`resetInteractionCounter` / `resetEventIdCounter` in\n * `./gemini-interactions.js`), the fal.ai job/queue maps (`falJobs`,\n * `falQueueStates`), the fine-tuning job store (`clearFineTuningStore`),\n * and the ElevenLabs Voice Design store (`clearElevenLabsVoices`). With two\n * `LLMock` instances live in one process,\n * `a.reset()` rewinds the Gemini id sequence that `b` is mid-way through —\n * `b` then re-emits `aimock-int-0` / `evt_1`, ids it has already handed\n * out — and drops `b`'s in-flight fal jobs. Give each instance its own\n * process (or its own vitest worker) if that matters.\n *\n * The global stores are cleared even before `start()`, when there is no\n * server instance to reset.\n */\n reset(): this {\n this.searchFixtures.length = 0;\n this.rerankFixtures.length = 0;\n this.moderationFixtures.length = 0;\n // `ServerInstance` carries no mounts, so the fakes are unloaded here (R4).\n this.unloadMcpFakes();\n performFullReset(this.fixtures, this.serverInstance);\n return this;\n }\n\n // ---- Server lifecycle ----\n\n async start(): Promise<string> {\n if (this.serverInstance) {\n throw new Error(\"Server already started\");\n }\n const serviceFixtures = {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n mcpFakes: [...this.mcpFakeBuffer],\n };\n this.serverInstance = await (this.resolvedInboundAuth\n ? createServerWithResolvedAuth(\n this.fixtures,\n this.options,\n this.resolvedInboundAuth,\n this.mounts,\n serviceFixtures,\n )\n : createServer(this.fixtures, this.options, this.mounts, serviceFixtures));\n const countIdentity = (fixture: Fixture) => this.fixtureCountOrigins.get(fixture) ?? fixture;\n this.serverInstance.journal.configureFixtureCountIdentity(countIdentity);\n // The server holds the buffered fakes now (W2). A start that rejects took\n // its hand-off back, so the buffer is kept for a retry.\n this.mcpFakeBuffer.length = 0;\n return this.serverInstance.url;\n }\n\n closeLiveSessions(testId?: string): this {\n this.serverInstance?.closeLiveSessions(testId);\n return this;\n }\n\n async stop(): Promise<void> {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n const { server } = this.serverInstance;\n await new Promise<void>((resolve, reject) => {\n server.close((err: Error | undefined) => (err ? reject(err) : resolve()));\n });\n this.serverInstance = null;\n }\n\n // ---- Accessors ----\n\n get journal(): Journal {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.journal;\n }\n\n get url(): string {\n if (!this.serverInstance) {\n throw new Error(\"Server not started\");\n }\n return this.serverInstance.url;\n }\n\n get baseUrl(): string {\n return this.url;\n }\n\n get port(): number {\n const parsed = new URL(this.url); // this.url throws if not started\n if (!parsed.port) {\n throw new Error(`Server URL has no explicit port: ${this.url}`);\n }\n return parseInt(parsed.port, 10);\n }\n\n // ---- Static factory ----\n\n static async create(options?: MockServerOptions): Promise<LLMock> {\n const instance = new LLMock(options);\n await instance.start();\n return instance;\n }\n}\n\n/** @internal Configuration startup preserves a policy resolved from the selected source. */\nexport function createLLMockWithResolvedAuth(\n options: MockServerOptions,\n resolvedAuth: ResolvedInboundAuth,\n): LLMock {\n return new LLMock(options, resolvedAuth);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-fakes.d.cts","names":[],"sources":["../src/mcp-fakes.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-fakes.d.cts","names":[],"sources":["../src/mcp-fakes.ts"],"sourcesContent":[],"mappings":"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"}
@@ -352,11 +352,15 @@ function createMCPRequestHandler(state) {
352
352
  if (!uri) return jsonRpcError(id, -32602, "Missing resource URI");
353
353
  const entry = state.resources.get(uri);
354
354
  if (!entry) return jsonRpcError(id, -32602, `Unknown resource: ${uri}`);
355
+ const text = entry.content?.text;
356
+ const blob = entry.content?.blob;
357
+ const mimeType = entry.content?.mimeType ?? entry.def.mimeType;
355
358
  return jsonRpcResult(id, { contents: [{
356
359
  uri,
357
- ...entry.content?.text !== void 0 && { text: entry.content.text },
358
- ...entry.content?.blob !== void 0 && { blob: entry.content.blob },
359
- ...entry.content?.mimeType !== void 0 && { mimeType: entry.content.mimeType }
360
+ ...text !== void 0 && { text },
361
+ ...blob !== void 0 && { blob },
362
+ ...text === void 0 && blob === void 0 && { text: "" },
363
+ ...mimeType !== void 0 && { mimeType }
360
364
  }] });
361
365
  },
362
366
  "prompts/list": async (_params, id) => {
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-handler.cjs","names":["quote","jsonText","plainText","build","MCP_FAKE_ERROR_CODES","createJsonRpcDispatcher","fixed","resolveMcpIdentity","decodeMcpHeaderValue"],"sources":["../src/mcp-handler.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { createJsonRpcDispatcher } from \"./jsonrpc.js\";\nimport type {\n MCPToolDefinition,\n MCPResourceDefinition,\n MCPResourceContent,\n MCPPromptDefinition,\n MCPPromptResult,\n MCPContent,\n MCPSession,\n} from \"./mcp-types.js\";\nimport type { McpFakeClaim, McpFakeStore } from \"./mcp-fakes.js\";\nimport {\n MCP_FAKE_ERROR_CODES,\n type McpFakeErrorCode,\n type McpFakeIdentity,\n type McpFakeNotification,\n type McpFakeOutcome,\n} from \"./types.js\";\nimport { decodeMcpHeaderValue, resolveMcpIdentity, type McpIdentityResolution } from \"./helpers.js\";\nimport { Message, build, fixed, jsonText, msg, plainText, quote } from \"./message-text.js\";\n\n/**\n * `data.aimock.code` of a `tools/call` whose fake claim threw: an aimock\n * defect (a validated entry whose result could not be built or sent), not a\n * scenario failure. Answered with the JSON-RPC internal-error code `-32603`;\n * the entry stays unconsumed.\n */\nexport const MCP_FAKE_INTERNAL_ERROR = \"MCP_FAKE_INTERNAL_ERROR\";\nconst MCP_FAKE_INTERNAL_ERROR_RPC_CODE = -32603;\n\n/** What every fake event carries: who called which tool on which mount (I9). */\ninterface McpFakeEventBase {\n identity: McpFakeIdentity;\n tool: string;\n /** The mount path the request came in on (I9). */\n mount: string;\n /** The call's `arguments` as received (RP2). */\n args: unknown;\n}\n\n/**\n * One MCP fake outcome of a `tools/call`, for the mount's side channels\n * (metric and log line; spec 9.3). `answered` names the entry; every other\n * kind is a failure with its `data.aimock.code` and the JSON-RPC error\n * message sent to the client. `evicted` also carries the evicted test id and\n * the cap; `internal_error` is a claim that threw (`MCP_FAKE_INTERNAL_ERROR`).\n */\nexport type McpFakeEvent = McpFakeEventBase &\n (\n | { kind: \"answered\"; entryId: string }\n | {\n kind: Exclude<McpFakeOutcome, \"answered\" | \"evicted\">;\n code: McpFakeErrorCode;\n message: string;\n }\n | { kind: \"evicted\"; code: \"MCP_FAKE_EVICTED\"; message: string; testId: string; cap: number }\n | { kind: \"internal_error\"; code: typeof MCP_FAKE_INTERNAL_ERROR; message: string }\n );\n\n/** An identity field whose value can fall back to the raw value (H1). */\nexport type McpDecodeField = \"testId\" | \"context\";\n\n/**\n * A decode fallback of one request, for L2: a test id or context value that\n * is not valid percent-encoding (on the header or the query; `used` is false\n * for a query value the header overrode), or query names that are not valid\n * percent-encoding and so match no identity field.\n */\nexport type McpDecodeFallback =\n | { kind: \"value\"; field: McpDecodeField; source: \"header\" | \"query\"; raw: string; used: boolean }\n | { kind: \"names\"; count: number };\n\n/** One JSON-RPC message of a request, for one journal entry (B2). */\nexport interface MCPMessageRecord {\n /** The JSON-RPC request object of a `tools/call`, else `null`. */\n body: Record<string, unknown> | null;\n /** Set when a fake answered or failed this `tools/call`. */\n mcpFake: { id: string | null; outcome: McpFakeOutcome } | null;\n /** What the mount's own code threw while serving this message, else `null`. */\n error: string | null;\n}\n\n/**\n * What one request handled by `createMCPRequestHandler` resolved, for the\n * mount's journal (B2, B3). `identity` is `null` when the request had none to\n * resolve (a rejected identity; a DELETE with a missing or unknown session).\n * `messages` has one record per JSON-RPC message: one for a single message,\n * one per element of a batch, so each `tools/call` of a batch is journaled\n * with its own body and fake outcome. The mount writes one journal entry per\n * record, and one with no body when there is none (a request answered before\n * any message was read, or an empty batch).\n */\nexport interface MCPRequestRecord {\n identity: McpFakeIdentity | null;\n messages: MCPMessageRecord[];\n}\n\n/** An empty record, for the caller to pass in and read even if the handler throws. */\nexport function newMCPRequestRecord(): MCPRequestRecord {\n return { identity: null, messages: [] };\n}\n\nexport interface MCPState {\n serverInfo: { name: string; version: string };\n tools: Map<string, { def: MCPToolDefinition; handler?: (...args: unknown[]) => unknown }>;\n resources: Map<string, { def: MCPResourceDefinition; content?: MCPResourceContent }>;\n prompts: Map<\n string,\n {\n def: MCPPromptDefinition;\n handler?: (...args: unknown[]) => MCPPromptResult | Promise<MCPPromptResult>;\n }\n >;\n sessions: Map<string, MCPSession>;\n /** The mount's fakes (one store per mount). */\n fakes: McpFakeStore;\n /** Whether any fake block is loaded on the mount (gates L2). */\n hasFakes(): boolean;\n /** A fake answered or failed a `tools/call` (metric, L1/L10 log). */\n onFakeEvent(evt: McpFakeEvent): void;\n /**\n * A request of `sessionId` sent an identity value (or query name) that is\n * not valid percent-encoding (H1). Called only when `hasFakes()`; the mount\n * logs L2 once per session per field and source.\n */\n onDecodeFallback(sessionId: string, fallback: McpDecodeFallback): void;\n /** `sessionId` was deleted (DELETE): the mount drops its per-session state. */\n onSessionClosed(sessionId: string): void;\n /** RP2: a tools/call no fake applied to (fakes:10 step 3), with who answered. */\n onUnfaked(evt: {\n identity: McpFakeIdentity;\n tool: string;\n mount: string;\n args: unknown;\n answeredBy: \"handler\" | \"config\" | \"empty\" | \"unknown-tool\";\n }): void;\n /** T1: the replay speed recorded timing plays at (`value / speed`). */\n replaySpeed(): number;\n}\n\n/**\n * C8: the `onToolCall` handlers that answer a config `mcp.tools[].result`.\n * `tools/call` reports such an answer as `answeredBy: \"config\"`. Internal:\n * not exported from the package.\n */\nexport const configToolHandlers = new WeakSet<(...args: unknown[]) => unknown>();\n\n/** C7: the syslog levels of `logging/setLevel`, lowest first. */\nconst LOG_LEVELS = [\n \"debug\",\n \"info\",\n \"notice\",\n \"warning\",\n \"error\",\n \"critical\",\n \"alert\",\n \"emergency\",\n] as const;\n\n/** C7: the rank of a syslog level name, or -1 when it is not one. */\nfunction logLevelRank(level: unknown): number {\n return typeof level === \"string\" ? (LOG_LEVELS as readonly string[]).indexOf(level) : -1;\n}\n\nfunction jsonRpcResult(id: string | number, result: unknown) {\n return { jsonrpc: \"2.0\" as const, id, result };\n}\n\nfunction jsonRpcError(id: string | number | null, code: number, message: string, data?: unknown) {\n return {\n jsonrpc: \"2.0\" as const,\n id,\n error: data === undefined ? { code, message } : { code, message, data },\n };\n}\n\n/**\n * The identity part of a fake message or log line (I9): `testId \"<id>\"`,\n * `context \"<ctx>\"`, both, or `no testId or context`.\n */\nexport function describeMcpIdentity(identity: McpFakeIdentity): Message {\n const { testId, context } = identity;\n if (testId !== null && context !== null) {\n return msg`testId ${quote(testId)}, context ${quote(context)}`;\n }\n if (testId !== null) return msg`testId ${quote(testId)}`;\n if (context !== null) return msg`context ${quote(context)}`;\n return msg`no testId or context`;\n}\n\n/** A value as JSON text for a message part. */\nfunction jsonPart(value: unknown): ReturnType<typeof jsonText> {\n return jsonText(JSON.stringify(value) ?? \"null\");\n}\n\n/** The outcome of one `tools/call` invocation, for its message record. */\ntype CallOutcome = Omit<MCPMessageRecord, \"body\">;\n\n/**\n * What `tools/call` reads of one request (its resolved identity and mount,\n * and which invocations are notifications) and writes back: one outcome per\n * `tools/call` invocation, in order, so a batch's calls each keep their own.\n */\ninterface FakeRequestContext {\n identity: McpFakeIdentity;\n mount: string;\n /**\n * Per `tools/call` invocation, in order: true when its message has no `id`\n * member. The dispatcher passes a null id both for a notification and for\n * a request whose id is null or not a string or number, so the handler\n * cannot tell them apart from its id.\n */\n notifications: boolean[];\n calls: CallOutcome[];\n /**\n * Set by the outer handler for a single `tools/call` it already claimed\n * (MR15 interception), so the method does not claim twice: `reply` is the\n * answer or failure `callFake` built, `none` means no fake applied. The\n * outcome of that call is already in `calls`.\n */\n precomputed?:\n | {\n kind: \"reply\";\n value: ReturnType<typeof jsonRpcResult> | ReturnType<typeof jsonRpcError>;\n }\n | { kind: \"none\" };\n}\n\n/**\n * A fake failure: the JSON-RPC error to send and the event to report; an\n * `evicted` one also carries the evicted test id and the cap.\n */\ntype FakeFailure = { message: string; aimock: Record<string, unknown> } & (\n | { outcome: Exclude<McpFakeOutcome, \"answered\" | \"evicted\">; code: McpFakeErrorCode }\n | { outcome: \"evicted\"; code: \"MCP_FAKE_EVICTED\"; evicted: { testId: string; cap: number } }\n);\n\n/**\n * The 9.2 error for a failed claim (`mismatch`, `exhausted`, `evicted`), or\n * for an undeclared tool under `deny` (`not_declared`).\n */\nexport function fakeFailure(\n claim: Exclude<McpFakeClaim, { kind: \"answer\" } | { kind: \"none\" }> | { kind: \"not_declared\" },\n tool: string,\n ctx: FakeRequestContext,\n declaredTools: () => string[],\n): FakeFailure {\n const who = describeMcpIdentity(ctx.identity);\n const base = {\n tool,\n testId: ctx.identity.testId,\n context: ctx.identity.context,\n mount: ctx.mount,\n };\n switch (claim.kind) {\n case \"mismatch\": {\n const declared = claim.declared.map((d) =>\n d.args !== undefined\n ? msg`${plainText(d.id)} ${jsonPart(d.args)}`\n : msg`${plainText(d.id)} anyArgs`,\n );\n const list = declared.reduce<Message>(\n (acc, part, i) => (i === 0 ? part : msg`${acc}; ${part}`),\n msg`none`,\n );\n return {\n code: \"MCP_FAKE_MISMATCH\",\n outcome: \"mismatch\",\n message: build(\n msg`aimock MCP fake mismatch: tool ${quote(tool)} was called with arguments that match no declared fake (${who}). Received ${jsonPart(claim.received)}. Declared: ${list}.`,\n ),\n aimock: {\n code: \"MCP_FAKE_MISMATCH\",\n ...base,\n received: claim.received,\n declared: claim.declared,\n firstDifference: claim.firstDifference,\n },\n };\n }\n case \"exhausted\": {\n const used =\n claim.matchingDeclared === 1\n ? msg`the 1 matching fake is`\n : msg`all ${claim.matchingDeclared} matching fakes are`;\n return {\n code: \"MCP_FAKE_EXHAUSTED\",\n outcome: \"exhausted\",\n message: build(\n msg`aimock MCP fake exhausted: tool ${quote(tool)} with ${jsonPart(claim.received)} was called again, but ${used} already used (${who}).`,\n ),\n aimock: {\n code: \"MCP_FAKE_EXHAUSTED\",\n ...base,\n received: claim.received,\n matchingDeclared: claim.matchingDeclared,\n matchingConsumed: claim.matchingConsumed,\n matchingIds: claim.matchingIds,\n },\n };\n }\n case \"evicted\":\n // Only a test id is ever evicted (never the untagged state), so the\n // claim's test id is the request's.\n return {\n code: \"MCP_FAKE_EVICTED\",\n outcome: \"evicted\",\n evicted: { testId: claim.testId, cap: claim.maxTestIds },\n message: build(\n msg`aimock MCP fake evicted: consumption state for testId ${quote(claim.testId)} was evicted by the per-mount test-id cap (${claim.maxTestIds}); reset before reusing this test id (${who}).`,\n ),\n aimock: { code: \"MCP_FAKE_EVICTED\", ...base, testId: claim.testId, cap: claim.maxTestIds },\n };\n case \"not_declared\":\n return {\n code: \"MCP_FAKE_NOT_DECLARED\",\n outcome: \"not_declared\",\n message: build(\n msg`Unknown tool: ${plainText(tool)} (aimock MCP fake not declared: this scenario denies undeclared tools; ${who}).`,\n ),\n aimock: { code: \"MCP_FAKE_NOT_DECLARED\", ...base, declaredTools: declaredTools() },\n };\n }\n}\n\nexport function createMCPRequestHandler(state: MCPState) {\n /** Per-request fake context, set by the outer handler for the dispatcher's methods. */\n const contexts = new WeakMap<http.IncomingMessage, FakeRequestContext>();\n /** C7: each session's `logging/setLevel` level; dropped on DELETE. */\n const logLevels = new Map<string, string>();\n\n /** The initialize capabilities: `logging` only on a mount with recorded logs (C7). */\n const capabilities = (): Record<string, unknown> =>\n state.fakes.hasRecordedLogs()\n ? { tools: {}, resources: {}, prompts: {}, logging: {} }\n : { tools: {}, resources: {}, prompts: {} };\n\n /**\n * Spec 10 steps 1-2 for `tools/call`: a fake answer or fake failure, or\n * `null` to fall through to today's behavior (step 3).\n */\n const callFake = (\n ctx: FakeRequestContext,\n outcome: CallOutcome,\n tool: string,\n args: unknown,\n id: string | number,\n ): ReturnType<typeof jsonRpcResult> | ReturnType<typeof jsonRpcError> | null => {\n const event = { identity: ctx.identity, tool, mount: ctx.mount, args };\n let claim: McpFakeClaim;\n try {\n claim = state.fakes.claim(tool, args, ctx.identity);\n } catch (err) {\n // A validated entry whose result cannot be built or sent: an aimock\n // defect. Fail loud on every side channel, never a generic -32603.\n const thrown = err instanceof Error ? err.message : String(err);\n const message = build(\n msg`aimock MCP fake internal error: tool ${quote(tool)} could not be answered (${describeMcpIdentity(ctx.identity)}): ${plainText(thrown)}`,\n );\n outcome.error = message;\n state.onFakeEvent({\n ...event,\n kind: \"internal_error\",\n code: MCP_FAKE_INTERNAL_ERROR,\n message,\n });\n return jsonRpcError(id, MCP_FAKE_INTERNAL_ERROR_RPC_CODE, message, {\n aimock: {\n code: MCP_FAKE_INTERNAL_ERROR,\n tool,\n testId: ctx.identity.testId,\n context: ctx.identity.context,\n mount: ctx.mount,\n error: thrown,\n },\n });\n }\n if (claim.kind === \"answer\") {\n outcome.mcpFake = { id: claim.entry.id, outcome: \"answered\" };\n state.onFakeEvent({ ...event, kind: \"answered\", entryId: claim.entry.id });\n return jsonRpcResult(id, claim.result);\n }\n let failure: FakeFailure;\n if (claim.kind === \"none\") {\n if (state.fakes.policy(ctx.identity) !== \"deny\") return null;\n failure = fakeFailure({ kind: \"not_declared\" }, tool, ctx, () =>\n state.fakes.declaredTools(ctx.identity),\n );\n } else {\n failure = fakeFailure(claim, tool, ctx, () => []);\n }\n outcome.mcpFake = { id: null, outcome: failure.outcome };\n state.onFakeEvent(\n failure.outcome === \"evicted\"\n ? {\n ...event,\n kind: \"evicted\",\n code: failure.code,\n message: failure.message,\n ...failure.evicted,\n }\n : { ...event, kind: failure.outcome, code: failure.code, message: failure.message },\n );\n return jsonRpcError(id, MCP_FAKE_ERROR_CODES[failure.code], failure.message, {\n aimock: failure.aimock,\n });\n };\n\n const dispatcher = createJsonRpcDispatcher({\n methods: {\n // initialize is handled directly in the outer function — this entry is\n // only here so the dispatcher doesn't return \"Method not found\" if the\n // request somehow reaches it.\n initialize: async (_params, id) => {\n return jsonRpcResult(id, {\n protocolVersion: \"2025-03-26\",\n capabilities: capabilities(),\n serverInfo: state.serverInfo,\n });\n },\n\n \"notifications/initialized\": async (_params, _id, req) => {\n const sessionId = req.headers[\"mcp-session-id\"] as string;\n const session = state.sessions.get(sessionId);\n if (session) {\n session.initialized = true;\n }\n return null;\n },\n\n ping: async (_params, id) => {\n return jsonRpcResult(id, {});\n },\n\n // C7: only a mount with recorded log lines serves logging/setLevel;\n // every other mount answers exactly as the dispatcher does for an\n // unknown method (src/jsonrpc.ts).\n \"logging/setLevel\": async (params, id, req) => {\n if (!state.fakes.hasRecordedLogs()) return jsonRpcError(id, -32601, \"Method not found\");\n const level = (params ?? {}) as { level?: unknown };\n if (logLevelRank(level.level) === -1) {\n return jsonRpcError(id, -32602, \"Invalid log level\");\n }\n const sessionId = req.headers[\"mcp-session-id\"];\n if (typeof sessionId === \"string\") logLevels.set(sessionId, String(level.level));\n return jsonRpcResult(id, {});\n },\n\n \"tools/list\": async (_params, id, req) => {\n const tools: MCPToolDefinition[] = [];\n // inputSchema is required on every listed Tool, with a root `type`; a\n // tool registered without one lists `{ type: \"object\" }`, as fake\n // tools already do, and a schema without a `type` gets\n // `type: \"object\"` added. An explicit `type` is left as is.\n for (const { def } of state.tools.values()) {\n tools.push(\n def.inputSchema?.type !== undefined\n ? def\n : { ...def, inputSchema: { type: \"object\", ...def.inputSchema } },\n );\n }\n const ctx = contexts.get(req);\n // AM7: a recorded list comes first, in recorded order (its definition\n // wins), then registered tools missing from it, then the other fake\n // tools.\n const recorded = ctx ? state.fakes.recordedList(ctx.identity) : null;\n if (ctx && recorded) {\n const listed: unknown[] = [...recorded];\n const names = new Set(recorded.map((t) => t.name));\n for (const def of tools) {\n if (!names.has(def.name)) {\n names.add(def.name);\n listed.push(def);\n }\n }\n for (const fake of state.fakes.listTools(ctx.identity)) {\n if (!names.has(fake.name)) {\n names.add(fake.name);\n listed.push(fake);\n }\n }\n return jsonRpcResult(id, { tools: listed });\n }\n // Spec 10: the union with the applicable fake tools; a registered\n // definition wins for metadata.\n if (ctx) {\n const registered = new Set(tools.map((t) => t.name));\n for (const fake of state.fakes.listTools(ctx.identity)) {\n if (!registered.has(fake.name)) tools.push(fake);\n }\n }\n return jsonRpcResult(id, { tools });\n },\n\n \"tools/call\": async (params, id, req) => {\n // One outcome per invocation, in order, even when nothing is claimed,\n // so each message of a batch is matched with its own.\n const ctx = contexts.get(req);\n // A single call the outer handler already claimed: its outcome is\n // already in `calls`, and its claim is not run again.\n const precomputed = ctx?.precomputed;\n if (ctx) ctx.precomputed = undefined;\n const isNotification = !precomputed && ctx?.notifications[ctx.calls.length] === true;\n if (!precomputed) ctx?.calls.push({ mcpFake: null, error: null });\n const outcome: CallOutcome = ctx?.calls[ctx.calls.length - 1] ?? {\n mcpFake: null,\n error: null,\n };\n // A notification (no `id` member) gets no answer (JSON-RPC 2.0) and\n // claims no fake entry, but a registered handler still runs for its\n // side effects, as on origin/main. A request whose id is null or of\n // another type is still served, with id null.\n const { name: rawName, arguments: args } = (params ?? {}) as {\n name?: unknown;\n arguments?: unknown;\n };\n if (!rawName) {\n return jsonRpcError(id, -32602, \"Missing tool name\");\n }\n if (typeof rawName !== \"string\") {\n const got = Array.isArray(rawName) ? \"array\" : typeof rawName;\n return jsonRpcError(\n id,\n -32602,\n build(msg`Invalid tool name: expected a string, got ${fixed(got)}`),\n );\n }\n const name = rawName;\n // Spec 10 steps 1-2: fakes, then the deny policy; never a handler\n // after a fake failure.\n if (precomputed?.kind === \"reply\") return precomputed.value;\n if (ctx && !isNotification && !precomputed) {\n const fake = callFake(ctx, outcome, name, args, id);\n if (fake) return fake;\n }\n const entry = state.tools.get(name);\n // RP2: every tools/call no fake applied to is logged with who answers it.\n if (ctx && !isNotification) {\n state.onUnfaked({\n identity: ctx.identity,\n tool: name,\n mount: ctx.mount,\n args,\n answeredBy: !entry\n ? \"unknown-tool\"\n : entry.handler && configToolHandlers.has(entry.handler)\n ? \"config\"\n : entry.handler\n ? \"handler\"\n : \"empty\",\n });\n }\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown tool: ${name}`);\n }\n if (entry.handler) {\n try {\n const result = await entry.handler(args);\n const content: MCPContent[] = Array.isArray(result)\n ? result\n : [{ type: \"text\", text: String(result) }];\n return jsonRpcResult(id, { content, isError: false });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return jsonRpcResult(id, {\n content: [{ type: \"text\", text: message }],\n isError: true,\n });\n }\n }\n // No handler — return empty content\n return jsonRpcResult(id, { content: [], isError: false });\n },\n\n \"resources/list\": async (_params, id) => {\n const resources: MCPResourceDefinition[] = [];\n for (const { def } of state.resources.values()) {\n resources.push(def);\n }\n return jsonRpcResult(id, { resources });\n },\n\n \"resources/read\": async (params, id) => {\n const { uri } = (params ?? {}) as { uri?: string };\n if (!uri) {\n return jsonRpcError(id, -32602, \"Missing resource URI\");\n }\n const entry = state.resources.get(uri);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown resource: ${uri}`);\n }\n return jsonRpcResult(id, {\n contents: [\n {\n uri,\n ...(entry.content?.text !== undefined && { text: entry.content.text }),\n ...(entry.content?.blob !== undefined && { blob: entry.content.blob }),\n ...(entry.content?.mimeType !== undefined && { mimeType: entry.content.mimeType }),\n },\n ],\n });\n },\n\n \"prompts/list\": async (_params, id) => {\n const prompts: MCPPromptDefinition[] = [];\n for (const { def } of state.prompts.values()) {\n prompts.push(def);\n }\n return jsonRpcResult(id, { prompts });\n },\n\n \"prompts/get\": async (params, id) => {\n const { name, arguments: args } = (params ?? {}) as { name?: string; arguments?: unknown };\n if (!name) {\n return jsonRpcError(id, -32602, \"Missing prompt name\");\n }\n const entry = state.prompts.get(name);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown prompt: ${name}`);\n }\n if (entry.handler) {\n try {\n const result = await entry.handler(args);\n return jsonRpcResult(id, result);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return jsonRpcError(id, -32603, `Prompt handler error: ${message}`);\n }\n }\n // No handler — return empty messages\n return jsonRpcResult(id, { messages: [] });\n },\n },\n });\n\n /** Answer a rejected identity (H4, H5) with HTTP 400, in the session-error shape. */\n const rejectIdentity = (\n res: http.ServerResponse,\n resolution: Extract<McpIdentityResolution, { ok: false }>,\n ): void => {\n res.writeHead(resolution.error.status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: resolution.error.message, code: resolution.error.code }));\n };\n\n /**\n * L2: report each identity value that fell back to the raw value (H1),\n * naming its source (header or query) and the value itself, and any query\n * name that did not decode. `fellBack` says only that some value of the\n * field fell back; the header is checked on its own, and the query by the\n * same resolver given the query alone, so the rules are the resolver's.\n */\n const reportFallback = (\n sessionId: string,\n req: http.IncomingMessage,\n resolution: Extract<McpIdentityResolution, { ok: true }>,\n ): void => {\n if (!state.hasFakes()) return;\n const { fellBack } = resolution;\n if (fellBack.testId || fellBack.context) {\n const queryOnly = resolveMcpIdentity({ headers: {}, url: req.url });\n for (const field of [\"testId\", \"context\"] as const) {\n if (!fellBack[field]) continue;\n const header = req.headers[IDENTITY_HEADERS[field]];\n const headerSent = typeof header === \"string\" && header !== \"\";\n if (headerSent && decodeMcpHeaderValue(header).fellBack) {\n state.onDecodeFallback(sessionId, {\n kind: \"value\",\n field,\n source: \"header\",\n raw: header,\n used: true,\n });\n }\n const fromQuery =\n queryOnly.ok && queryOnly.fellBack[field] ? queryOnly.identity[field] : null;\n if (fromQuery !== null) {\n state.onDecodeFallback(sessionId, {\n kind: \"value\",\n field,\n source: \"query\",\n raw: fromQuery,\n used: !headerSent,\n });\n }\n }\n }\n if (resolution.undecodedQueryNames) {\n state.onDecodeFallback(sessionId, { kind: \"names\", count: resolution.undecodedQueryNames });\n }\n };\n\n /**\n * Handle one MCP request. `mount` is the path the mount is served at (I9;\n * `/` for a standalone server). Resolves with what the request resolved,\n * for the mount's journal entry.\n */\n return async (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n mount = \"/\",\n record: MCPRequestRecord = newMCPRequestRecord(),\n ): Promise<MCPRequestRecord> => {\n /** T1: recorded `atMs` / `durationMs` are measured from here. */\n const arrivedAt = performance.now();\n // DELETE handler: session teardown\n if (req.method === \"DELETE\") {\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing mcp-session-id header\" }));\n return record;\n }\n if (!state.sessions.has(sessionId)) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Session not found\" }));\n return record;\n }\n // Journal only: identity inputs are not checked on a session teardown.\n const resolution = resolveMcpIdentity(req, state.sessions.get(sessionId));\n if (resolution.ok) record.identity = resolution.identity;\n state.sessions.delete(sessionId);\n logLevels.delete(sessionId);\n state.onSessionClosed(sessionId);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return record;\n }\n\n // Identity inputs (I1-I3, H4, H5): on every POST, a bad undeclared\n // override or a repeated field is rejected before the request is served.\n const headerSessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n const knownSession = headerSessionId ? state.sessions.get(headerSessionId) : undefined;\n\n // Parse the body to determine method for session validation\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n const resolution = resolveMcpIdentity(req, knownSession);\n if (!resolution.ok) {\n rejectIdentity(res, resolution);\n return record;\n }\n record.identity = resolution.identity;\n if (headerSessionId && knownSession) reportFallback(headerSessionId, req, resolution);\n // Let the dispatcher handle parse errors\n await dispatcher(req, res, body);\n return record;\n }\n\n const method =\n typeof parsed === \"object\" && parsed !== null && \"method\" in parsed\n ? (parsed as { method: unknown }).method\n : undefined;\n\n // Handle initialize directly to control response headers\n if (method === \"initialize\") {\n const id =\n typeof parsed === \"object\" && parsed !== null && \"id\" in parsed\n ? (parsed as { id: unknown }).id\n : null;\n\n // I3: only the values the initialize request itself supplies are bound.\n const resolution = resolveMcpIdentity(req);\n if (!resolution.ok) {\n rejectIdentity(res, resolution);\n return record;\n }\n record.identity = resolution.identity;\n const { identity, supplied } = resolution;\n\n const sessionId = randomUUID();\n state.sessions.set(sessionId, {\n id: sessionId,\n initialized: false,\n createdAt: Date.now(),\n ...(supplied.testId && identity.testId !== null ? { testId: identity.testId } : {}),\n ...(supplied.context && identity.context !== null ? { context: identity.context } : {}),\n ...(supplied.undeclared && identity.undeclared !== null\n ? { undeclared: identity.undeclared }\n : {}),\n });\n reportFallback(sessionId, req, resolution);\n\n const response = {\n jsonrpc: \"2.0\",\n id,\n result: {\n protocolVersion: \"2025-03-26\",\n capabilities: capabilities(),\n serverInfo: state.serverInfo,\n },\n };\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Mcp-Session-Id\": sessionId,\n });\n res.end(JSON.stringify(response));\n return record;\n }\n\n const resolution = resolveMcpIdentity(req, knownSession);\n if (!resolution.ok) {\n rejectIdentity(res, resolution);\n return record;\n }\n record.identity = resolution.identity;\n\n // Session validation for all other methods\n const sessionId = headerSessionId;\n if (!sessionId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing mcp-session-id header\" }));\n return record;\n }\n if (!state.sessions.has(sessionId)) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Session not found\" }));\n return record;\n }\n reportFallback(sessionId, req, resolution);\n\n // Enforce initialization: only allow notifications/initialized through\n // before the session is fully initialized\n const session = state.sessions.get(sessionId)!;\n if (!session.initialized && method !== \"notifications/initialized\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n jsonRpcError(\n typeof parsed === \"object\" && parsed !== null && \"id\" in parsed\n ? ((parsed as { id: unknown }).id as string | number)\n : null,\n -32002,\n \"Session not initialized\",\n ),\n ),\n );\n return record;\n }\n\n // Delegate to the JSON-RPC dispatcher for all other methods\n // The dispatcher invokes `tools/call` once per message that is an object\n // with `jsonrpc: \"2.0\"` and that method, in order (see B2 below).\n const notifications = (Array.isArray(parsed) ? parsed : [parsed])\n .filter((m): m is Record<string, unknown> => isToolsCall(m) && m.jsonrpc === \"2.0\")\n .map((m) => !(\"id\" in m));\n const ctx: FakeRequestContext = {\n identity: resolution.identity,\n mount,\n notifications,\n calls: [],\n };\n contexts.set(req, ctx);\n // MR15 / T1: a single tools/call is claimed here, before the dispatcher,\n // because an answer with recorded timing or notifications is written by\n // `writeFakeToolAnswer` (SSE or delayed JSON), which the dispatcher's\n // JSON-only writer cannot do. Any other outcome is handed to the method\n // through `ctx.precomputed`, so the claim runs once.\n const single = singleToolsCall(parsed);\n if (single) {\n const outcome: CallOutcome = { mcpFake: null, error: null };\n ctx.calls.push(outcome);\n const fake = callFake(ctx, outcome, single.name, single.args, single.id);\n const replay =\n fake && outcome.mcpFake?.outcome === \"answered\" && outcome.mcpFake.id !== null\n ? state.fakes.replayOf(outcome.mcpFake.id)\n : null;\n if (\n fake &&\n \"result\" in fake &&\n replay &&\n (replay.notifications.length > 0 ||\n (replay.timing === \"recorded\" && replay.durationMs !== undefined))\n ) {\n await writeFakeToolAnswer(\n req,\n res,\n single.id,\n fake.result,\n replay,\n single.params,\n state.replaySpeed(),\n logLevels.get(sessionId) ?? null,\n arrivedAt,\n );\n record.messages = [\n { body: single.message, mcpFake: outcome.mcpFake, error: outcome.error },\n ];\n return record;\n }\n ctx.precomputed = fake ? { kind: \"reply\", value: fake } : { kind: \"none\" };\n }\n await dispatcher(req, res, body);\n // B2: each tools/call message is journaled with its body and its own\n // outcome. The dispatcher invokes `tools/call` once per message that is\n // an object with `jsonrpc: \"2.0\"` and that method, in order, so the n-th\n // such message takes the n-th outcome.\n let next = 0;\n const messageOf = (message: unknown): MCPMessageRecord => {\n if (!isToolsCall(message)) return { body: null, mcpFake: null, error: null };\n const outcome = message.jsonrpc === \"2.0\" ? ctx.calls[next++] : undefined;\n return { body: message, mcpFake: outcome?.mcpFake ?? null, error: outcome?.error ?? null };\n };\n record.messages = Array.isArray(parsed) ? parsed.map(messageOf) : [messageOf(parsed)];\n return record;\n };\n}\n\n/**\n * A single JSON-RPC `tools/call` request (not a batch, not a notification)\n * with a string or number id and a string tool name, else `null`. Only such\n * a message is claimed by the outer handler (MR15).\n */\nfunction singleToolsCall(parsed: unknown): {\n message: Record<string, unknown>;\n id: string | number;\n name: string;\n args: unknown;\n params: unknown;\n} | null {\n if (!isToolsCall(parsed) || parsed.jsonrpc !== \"2.0\" || !(\"id\" in parsed)) return null;\n const id = parsed.id;\n if (typeof id !== \"string\" && typeof id !== \"number\") return null;\n const params = parsed.params;\n if (typeof params !== \"object\" || params === null) return null;\n const name: unknown = (params as { name?: unknown }).name;\n if (typeof name !== \"string\" || name === \"\") return null;\n return { message: parsed, id, name, args: (params as { arguments?: unknown }).arguments, params };\n}\n\n/** Resolve after `ms` (no wait when `ms <= 0`). */\nfunction sleep(ms: number): Promise<void> {\n return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();\n}\n\n/** The client's `_meta.progressToken` of a request's params, else `undefined`. */\nfunction progressTokenOf(params: unknown): string | number | undefined {\n if (typeof params !== \"object\" || params === null) return undefined;\n const meta: unknown = (params as { _meta?: unknown })._meta;\n if (typeof meta !== \"object\" || meta === null) return undefined;\n const token: unknown = (meta as { progressToken?: unknown }).progressToken;\n return typeof token === \"string\" || typeof token === \"number\" ? token : undefined;\n}\n\n/**\n * FA3 gate of one recorded notification for this request: the params to send,\n * or `null` when it does not replay. `notifications/progress` replays only\n * when the request carries a progress token, which replaces the recorded one;\n * `notifications/message` only when the session set a log level (C7) and the\n * line is at or above it. No other method replays.\n */\nfunction replayedParams(\n notification: McpFakeNotification,\n progressToken: string | number | undefined,\n logLevel: string | null,\n): Record<string, unknown> | null {\n if (notification.method === \"notifications/progress\") {\n return progressToken === undefined ? null : { ...notification.params, progressToken };\n }\n if (notification.method === \"notifications/message\") {\n const min = logLevelRank(logLevel);\n const rank = logLevelRank(notification.params.level);\n return min !== -1 && rank >= min ? { ...notification.params } : null;\n }\n return null;\n}\n\n/**\n * Write a fake's tools/call answer. SSE iff the entry has a notification whose\n * FA3 gate passes AND Accept lists text/event-stream; else JSON. Timing per T1\n * (value / speed) unless the block's timing is \"immediate\". `logLevel` is the\n * session's `logging/setLevel` level (C7), `arrivedAt` the `performance.now()`\n * of the request's arrival, which `atMs` and `durationMs` are measured from.\n */\nexport async function writeFakeToolAnswer(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n id: string | number | null,\n result: unknown,\n replay: ReturnType<McpFakeStore[\"replayOf\"]>,\n params: unknown,\n speed: number,\n logLevel: string | null = null,\n arrivedAt: number = performance.now(),\n): Promise<void> {\n const timed = replay !== null && replay.timing === \"recorded\";\n const waitUntil = (atMs: number): Promise<void> =>\n timed ? sleep(atMs / speed - (performance.now() - arrivedAt)) : Promise.resolve();\n const token = progressTokenOf(params);\n const notifications = [...(replay?.notifications ?? [])]\n .sort((a, b) => a.atMs - b.atMs)\n .flatMap((n) => {\n const sent = replayedParams(n, token, logLevel);\n return sent ? [{ atMs: n.atMs, method: n.method, params: sent }] : [];\n });\n const accept = req.headers.accept ?? \"\";\n const answer = { jsonrpc: \"2.0\" as const, id, result };\n if (notifications.length > 0 && accept.includes(\"text/event-stream\")) {\n res.writeHead(200, { \"Content-Type\": \"text/event-stream\", \"Cache-Control\": \"no-cache\" });\n res.flushHeaders();\n for (const n of notifications) {\n await waitUntil(n.atMs);\n if (res.destroyed) return;\n res.write(\n `event: message\\ndata: ${JSON.stringify({ jsonrpc: \"2.0\", method: n.method, params: n.params })}\\n\\n`,\n );\n }\n if (replay?.durationMs !== undefined) await waitUntil(replay.durationMs);\n if (res.destroyed) return;\n res.end(`event: message\\ndata: ${JSON.stringify(answer)}\\n\\n`);\n return;\n }\n if (replay?.durationMs !== undefined) await waitUntil(replay.durationMs);\n if (res.destroyed) return;\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(answer));\n}\n\n/** The identity header of each field whose value can fall back (H1). */\nconst IDENTITY_HEADERS: Record<McpDecodeField, string> = {\n testId: \"x-test-id\",\n context: \"x-aimock-context\",\n};\n\n/** A JSON-RPC message object whose method is `tools/call`. */\nfunction isToolsCall(message: unknown): message is Record<string, unknown> {\n return (\n typeof message === \"object\" &&\n message !== null &&\n !Array.isArray(message) &&\n \"method\" in message &&\n message.method === \"tools/call\"\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp-handler.cjs","names":["quote","jsonText","plainText","build","MCP_FAKE_ERROR_CODES","createJsonRpcDispatcher","fixed","resolveMcpIdentity","decodeMcpHeaderValue"],"sources":["../src/mcp-handler.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { createJsonRpcDispatcher } from \"./jsonrpc.js\";\nimport type {\n MCPToolDefinition,\n MCPResourceDefinition,\n MCPResourceContent,\n MCPPromptDefinition,\n MCPPromptResult,\n MCPContent,\n MCPSession,\n} from \"./mcp-types.js\";\nimport type { McpFakeClaim, McpFakeStore } from \"./mcp-fakes.js\";\nimport {\n MCP_FAKE_ERROR_CODES,\n type McpFakeErrorCode,\n type McpFakeIdentity,\n type McpFakeNotification,\n type McpFakeOutcome,\n} from \"./types.js\";\nimport { decodeMcpHeaderValue, resolveMcpIdentity, type McpIdentityResolution } from \"./helpers.js\";\nimport { Message, build, fixed, jsonText, msg, plainText, quote } from \"./message-text.js\";\n\n/**\n * `data.aimock.code` of a `tools/call` whose fake claim threw: an aimock\n * defect (a validated entry whose result could not be built or sent), not a\n * scenario failure. Answered with the JSON-RPC internal-error code `-32603`;\n * the entry stays unconsumed.\n */\nexport const MCP_FAKE_INTERNAL_ERROR = \"MCP_FAKE_INTERNAL_ERROR\";\nconst MCP_FAKE_INTERNAL_ERROR_RPC_CODE = -32603;\n\n/** What every fake event carries: who called which tool on which mount (I9). */\ninterface McpFakeEventBase {\n identity: McpFakeIdentity;\n tool: string;\n /** The mount path the request came in on (I9). */\n mount: string;\n /** The call's `arguments` as received (RP2). */\n args: unknown;\n}\n\n/**\n * One MCP fake outcome of a `tools/call`, for the mount's side channels\n * (metric and log line; spec 9.3). `answered` names the entry; every other\n * kind is a failure with its `data.aimock.code` and the JSON-RPC error\n * message sent to the client. `evicted` also carries the evicted test id and\n * the cap; `internal_error` is a claim that threw (`MCP_FAKE_INTERNAL_ERROR`).\n */\nexport type McpFakeEvent = McpFakeEventBase &\n (\n | { kind: \"answered\"; entryId: string }\n | {\n kind: Exclude<McpFakeOutcome, \"answered\" | \"evicted\">;\n code: McpFakeErrorCode;\n message: string;\n }\n | { kind: \"evicted\"; code: \"MCP_FAKE_EVICTED\"; message: string; testId: string; cap: number }\n | { kind: \"internal_error\"; code: typeof MCP_FAKE_INTERNAL_ERROR; message: string }\n );\n\n/** An identity field whose value can fall back to the raw value (H1). */\nexport type McpDecodeField = \"testId\" | \"context\";\n\n/**\n * A decode fallback of one request, for L2: a test id or context value that\n * is not valid percent-encoding (on the header or the query; `used` is false\n * for a query value the header overrode), or query names that are not valid\n * percent-encoding and so match no identity field.\n */\nexport type McpDecodeFallback =\n | { kind: \"value\"; field: McpDecodeField; source: \"header\" | \"query\"; raw: string; used: boolean }\n | { kind: \"names\"; count: number };\n\n/** One JSON-RPC message of a request, for one journal entry (B2). */\nexport interface MCPMessageRecord {\n /** The JSON-RPC request object of a `tools/call`, else `null`. */\n body: Record<string, unknown> | null;\n /** Set when a fake answered or failed this `tools/call`. */\n mcpFake: { id: string | null; outcome: McpFakeOutcome } | null;\n /** What the mount's own code threw while serving this message, else `null`. */\n error: string | null;\n}\n\n/**\n * What one request handled by `createMCPRequestHandler` resolved, for the\n * mount's journal (B2, B3). `identity` is `null` when the request had none to\n * resolve (a rejected identity; a DELETE with a missing or unknown session).\n * `messages` has one record per JSON-RPC message: one for a single message,\n * one per element of a batch, so each `tools/call` of a batch is journaled\n * with its own body and fake outcome. The mount writes one journal entry per\n * record, and one with no body when there is none (a request answered before\n * any message was read, or an empty batch).\n */\nexport interface MCPRequestRecord {\n identity: McpFakeIdentity | null;\n messages: MCPMessageRecord[];\n}\n\n/** An empty record, for the caller to pass in and read even if the handler throws. */\nexport function newMCPRequestRecord(): MCPRequestRecord {\n return { identity: null, messages: [] };\n}\n\nexport interface MCPState {\n serverInfo: { name: string; version: string };\n tools: Map<string, { def: MCPToolDefinition; handler?: (...args: unknown[]) => unknown }>;\n resources: Map<string, { def: MCPResourceDefinition; content?: MCPResourceContent }>;\n prompts: Map<\n string,\n {\n def: MCPPromptDefinition;\n handler?: (...args: unknown[]) => MCPPromptResult | Promise<MCPPromptResult>;\n }\n >;\n sessions: Map<string, MCPSession>;\n /** The mount's fakes (one store per mount). */\n fakes: McpFakeStore;\n /** Whether any fake block is loaded on the mount (gates L2). */\n hasFakes(): boolean;\n /** A fake answered or failed a `tools/call` (metric, L1/L10 log). */\n onFakeEvent(evt: McpFakeEvent): void;\n /**\n * A request of `sessionId` sent an identity value (or query name) that is\n * not valid percent-encoding (H1). Called only when `hasFakes()`; the mount\n * logs L2 once per session per field and source.\n */\n onDecodeFallback(sessionId: string, fallback: McpDecodeFallback): void;\n /** `sessionId` was deleted (DELETE): the mount drops its per-session state. */\n onSessionClosed(sessionId: string): void;\n /** RP2: a tools/call no fake applied to (fakes:10 step 3), with who answered. */\n onUnfaked(evt: {\n identity: McpFakeIdentity;\n tool: string;\n mount: string;\n args: unknown;\n answeredBy: \"handler\" | \"config\" | \"empty\" | \"unknown-tool\";\n }): void;\n /** T1: the replay speed recorded timing plays at (`value / speed`). */\n replaySpeed(): number;\n}\n\n/**\n * C8: the `onToolCall` handlers that answer a config `mcp.tools[].result`.\n * `tools/call` reports such an answer as `answeredBy: \"config\"`. Internal:\n * not exported from the package.\n */\nexport const configToolHandlers = new WeakSet<(...args: unknown[]) => unknown>();\n\n/** C7: the syslog levels of `logging/setLevel`, lowest first. */\nconst LOG_LEVELS = [\n \"debug\",\n \"info\",\n \"notice\",\n \"warning\",\n \"error\",\n \"critical\",\n \"alert\",\n \"emergency\",\n] as const;\n\n/** C7: the rank of a syslog level name, or -1 when it is not one. */\nfunction logLevelRank(level: unknown): number {\n return typeof level === \"string\" ? (LOG_LEVELS as readonly string[]).indexOf(level) : -1;\n}\n\nfunction jsonRpcResult(id: string | number, result: unknown) {\n return { jsonrpc: \"2.0\" as const, id, result };\n}\n\nfunction jsonRpcError(id: string | number | null, code: number, message: string, data?: unknown) {\n return {\n jsonrpc: \"2.0\" as const,\n id,\n error: data === undefined ? { code, message } : { code, message, data },\n };\n}\n\n/**\n * The identity part of a fake message or log line (I9): `testId \"<id>\"`,\n * `context \"<ctx>\"`, both, or `no testId or context`.\n */\nexport function describeMcpIdentity(identity: McpFakeIdentity): Message {\n const { testId, context } = identity;\n if (testId !== null && context !== null) {\n return msg`testId ${quote(testId)}, context ${quote(context)}`;\n }\n if (testId !== null) return msg`testId ${quote(testId)}`;\n if (context !== null) return msg`context ${quote(context)}`;\n return msg`no testId or context`;\n}\n\n/** A value as JSON text for a message part. */\nfunction jsonPart(value: unknown): ReturnType<typeof jsonText> {\n return jsonText(JSON.stringify(value) ?? \"null\");\n}\n\n/** The outcome of one `tools/call` invocation, for its message record. */\ntype CallOutcome = Omit<MCPMessageRecord, \"body\">;\n\n/**\n * What `tools/call` reads of one request (its resolved identity and mount,\n * and which invocations are notifications) and writes back: one outcome per\n * `tools/call` invocation, in order, so a batch's calls each keep their own.\n */\ninterface FakeRequestContext {\n identity: McpFakeIdentity;\n mount: string;\n /**\n * Per `tools/call` invocation, in order: true when its message has no `id`\n * member. The dispatcher passes a null id both for a notification and for\n * a request whose id is null or not a string or number, so the handler\n * cannot tell them apart from its id.\n */\n notifications: boolean[];\n calls: CallOutcome[];\n /**\n * Set by the outer handler for a single `tools/call` it already claimed\n * (MR15 interception), so the method does not claim twice: `reply` is the\n * answer or failure `callFake` built, `none` means no fake applied. The\n * outcome of that call is already in `calls`.\n */\n precomputed?:\n | {\n kind: \"reply\";\n value: ReturnType<typeof jsonRpcResult> | ReturnType<typeof jsonRpcError>;\n }\n | { kind: \"none\" };\n}\n\n/**\n * A fake failure: the JSON-RPC error to send and the event to report; an\n * `evicted` one also carries the evicted test id and the cap.\n */\ntype FakeFailure = { message: string; aimock: Record<string, unknown> } & (\n | { outcome: Exclude<McpFakeOutcome, \"answered\" | \"evicted\">; code: McpFakeErrorCode }\n | { outcome: \"evicted\"; code: \"MCP_FAKE_EVICTED\"; evicted: { testId: string; cap: number } }\n);\n\n/**\n * The 9.2 error for a failed claim (`mismatch`, `exhausted`, `evicted`), or\n * for an undeclared tool under `deny` (`not_declared`).\n */\nexport function fakeFailure(\n claim: Exclude<McpFakeClaim, { kind: \"answer\" } | { kind: \"none\" }> | { kind: \"not_declared\" },\n tool: string,\n ctx: FakeRequestContext,\n declaredTools: () => string[],\n): FakeFailure {\n const who = describeMcpIdentity(ctx.identity);\n const base = {\n tool,\n testId: ctx.identity.testId,\n context: ctx.identity.context,\n mount: ctx.mount,\n };\n switch (claim.kind) {\n case \"mismatch\": {\n const declared = claim.declared.map((d) =>\n d.args !== undefined\n ? msg`${plainText(d.id)} ${jsonPart(d.args)}`\n : msg`${plainText(d.id)} anyArgs`,\n );\n const list = declared.reduce<Message>(\n (acc, part, i) => (i === 0 ? part : msg`${acc}; ${part}`),\n msg`none`,\n );\n return {\n code: \"MCP_FAKE_MISMATCH\",\n outcome: \"mismatch\",\n message: build(\n msg`aimock MCP fake mismatch: tool ${quote(tool)} was called with arguments that match no declared fake (${who}). Received ${jsonPart(claim.received)}. Declared: ${list}.`,\n ),\n aimock: {\n code: \"MCP_FAKE_MISMATCH\",\n ...base,\n received: claim.received,\n declared: claim.declared,\n firstDifference: claim.firstDifference,\n },\n };\n }\n case \"exhausted\": {\n const used =\n claim.matchingDeclared === 1\n ? msg`the 1 matching fake is`\n : msg`all ${claim.matchingDeclared} matching fakes are`;\n return {\n code: \"MCP_FAKE_EXHAUSTED\",\n outcome: \"exhausted\",\n message: build(\n msg`aimock MCP fake exhausted: tool ${quote(tool)} with ${jsonPart(claim.received)} was called again, but ${used} already used (${who}).`,\n ),\n aimock: {\n code: \"MCP_FAKE_EXHAUSTED\",\n ...base,\n received: claim.received,\n matchingDeclared: claim.matchingDeclared,\n matchingConsumed: claim.matchingConsumed,\n matchingIds: claim.matchingIds,\n },\n };\n }\n case \"evicted\":\n // Only a test id is ever evicted (never the untagged state), so the\n // claim's test id is the request's.\n return {\n code: \"MCP_FAKE_EVICTED\",\n outcome: \"evicted\",\n evicted: { testId: claim.testId, cap: claim.maxTestIds },\n message: build(\n msg`aimock MCP fake evicted: consumption state for testId ${quote(claim.testId)} was evicted by the per-mount test-id cap (${claim.maxTestIds}); reset before reusing this test id (${who}).`,\n ),\n aimock: { code: \"MCP_FAKE_EVICTED\", ...base, testId: claim.testId, cap: claim.maxTestIds },\n };\n case \"not_declared\":\n return {\n code: \"MCP_FAKE_NOT_DECLARED\",\n outcome: \"not_declared\",\n message: build(\n msg`Unknown tool: ${plainText(tool)} (aimock MCP fake not declared: this scenario denies undeclared tools; ${who}).`,\n ),\n aimock: { code: \"MCP_FAKE_NOT_DECLARED\", ...base, declaredTools: declaredTools() },\n };\n }\n}\n\nexport function createMCPRequestHandler(state: MCPState) {\n /** Per-request fake context, set by the outer handler for the dispatcher's methods. */\n const contexts = new WeakMap<http.IncomingMessage, FakeRequestContext>();\n /** C7: each session's `logging/setLevel` level; dropped on DELETE. */\n const logLevels = new Map<string, string>();\n\n /** The initialize capabilities: `logging` only on a mount with recorded logs (C7). */\n const capabilities = (): Record<string, unknown> =>\n state.fakes.hasRecordedLogs()\n ? { tools: {}, resources: {}, prompts: {}, logging: {} }\n : { tools: {}, resources: {}, prompts: {} };\n\n /**\n * Spec 10 steps 1-2 for `tools/call`: a fake answer or fake failure, or\n * `null` to fall through to today's behavior (step 3).\n */\n const callFake = (\n ctx: FakeRequestContext,\n outcome: CallOutcome,\n tool: string,\n args: unknown,\n id: string | number,\n ): ReturnType<typeof jsonRpcResult> | ReturnType<typeof jsonRpcError> | null => {\n const event = { identity: ctx.identity, tool, mount: ctx.mount, args };\n let claim: McpFakeClaim;\n try {\n claim = state.fakes.claim(tool, args, ctx.identity);\n } catch (err) {\n // A validated entry whose result cannot be built or sent: an aimock\n // defect. Fail loud on every side channel, never a generic -32603.\n const thrown = err instanceof Error ? err.message : String(err);\n const message = build(\n msg`aimock MCP fake internal error: tool ${quote(tool)} could not be answered (${describeMcpIdentity(ctx.identity)}): ${plainText(thrown)}`,\n );\n outcome.error = message;\n state.onFakeEvent({\n ...event,\n kind: \"internal_error\",\n code: MCP_FAKE_INTERNAL_ERROR,\n message,\n });\n return jsonRpcError(id, MCP_FAKE_INTERNAL_ERROR_RPC_CODE, message, {\n aimock: {\n code: MCP_FAKE_INTERNAL_ERROR,\n tool,\n testId: ctx.identity.testId,\n context: ctx.identity.context,\n mount: ctx.mount,\n error: thrown,\n },\n });\n }\n if (claim.kind === \"answer\") {\n outcome.mcpFake = { id: claim.entry.id, outcome: \"answered\" };\n state.onFakeEvent({ ...event, kind: \"answered\", entryId: claim.entry.id });\n return jsonRpcResult(id, claim.result);\n }\n let failure: FakeFailure;\n if (claim.kind === \"none\") {\n if (state.fakes.policy(ctx.identity) !== \"deny\") return null;\n failure = fakeFailure({ kind: \"not_declared\" }, tool, ctx, () =>\n state.fakes.declaredTools(ctx.identity),\n );\n } else {\n failure = fakeFailure(claim, tool, ctx, () => []);\n }\n outcome.mcpFake = { id: null, outcome: failure.outcome };\n state.onFakeEvent(\n failure.outcome === \"evicted\"\n ? {\n ...event,\n kind: \"evicted\",\n code: failure.code,\n message: failure.message,\n ...failure.evicted,\n }\n : { ...event, kind: failure.outcome, code: failure.code, message: failure.message },\n );\n return jsonRpcError(id, MCP_FAKE_ERROR_CODES[failure.code], failure.message, {\n aimock: failure.aimock,\n });\n };\n\n const dispatcher = createJsonRpcDispatcher({\n methods: {\n // initialize is handled directly in the outer function — this entry is\n // only here so the dispatcher doesn't return \"Method not found\" if the\n // request somehow reaches it.\n initialize: async (_params, id) => {\n return jsonRpcResult(id, {\n protocolVersion: \"2025-03-26\",\n capabilities: capabilities(),\n serverInfo: state.serverInfo,\n });\n },\n\n \"notifications/initialized\": async (_params, _id, req) => {\n const sessionId = req.headers[\"mcp-session-id\"] as string;\n const session = state.sessions.get(sessionId);\n if (session) {\n session.initialized = true;\n }\n return null;\n },\n\n ping: async (_params, id) => {\n return jsonRpcResult(id, {});\n },\n\n // C7: only a mount with recorded log lines serves logging/setLevel;\n // every other mount answers exactly as the dispatcher does for an\n // unknown method (src/jsonrpc.ts).\n \"logging/setLevel\": async (params, id, req) => {\n if (!state.fakes.hasRecordedLogs()) return jsonRpcError(id, -32601, \"Method not found\");\n const level = (params ?? {}) as { level?: unknown };\n if (logLevelRank(level.level) === -1) {\n return jsonRpcError(id, -32602, \"Invalid log level\");\n }\n const sessionId = req.headers[\"mcp-session-id\"];\n if (typeof sessionId === \"string\") logLevels.set(sessionId, String(level.level));\n return jsonRpcResult(id, {});\n },\n\n \"tools/list\": async (_params, id, req) => {\n const tools: MCPToolDefinition[] = [];\n // inputSchema is required on every listed Tool, with a root `type`; a\n // tool registered without one lists `{ type: \"object\" }`, as fake\n // tools already do, and a schema without a `type` gets\n // `type: \"object\"` added. An explicit `type` is left as is.\n for (const { def } of state.tools.values()) {\n tools.push(\n def.inputSchema?.type !== undefined\n ? def\n : { ...def, inputSchema: { type: \"object\", ...def.inputSchema } },\n );\n }\n const ctx = contexts.get(req);\n // AM7: a recorded list comes first, in recorded order (its definition\n // wins), then registered tools missing from it, then the other fake\n // tools.\n const recorded = ctx ? state.fakes.recordedList(ctx.identity) : null;\n if (ctx && recorded) {\n const listed: unknown[] = [...recorded];\n const names = new Set(recorded.map((t) => t.name));\n for (const def of tools) {\n if (!names.has(def.name)) {\n names.add(def.name);\n listed.push(def);\n }\n }\n for (const fake of state.fakes.listTools(ctx.identity)) {\n if (!names.has(fake.name)) {\n names.add(fake.name);\n listed.push(fake);\n }\n }\n return jsonRpcResult(id, { tools: listed });\n }\n // Spec 10: the union with the applicable fake tools; a registered\n // definition wins for metadata.\n if (ctx) {\n const registered = new Set(tools.map((t) => t.name));\n for (const fake of state.fakes.listTools(ctx.identity)) {\n if (!registered.has(fake.name)) tools.push(fake);\n }\n }\n return jsonRpcResult(id, { tools });\n },\n\n \"tools/call\": async (params, id, req) => {\n // One outcome per invocation, in order, even when nothing is claimed,\n // so each message of a batch is matched with its own.\n const ctx = contexts.get(req);\n // A single call the outer handler already claimed: its outcome is\n // already in `calls`, and its claim is not run again.\n const precomputed = ctx?.precomputed;\n if (ctx) ctx.precomputed = undefined;\n const isNotification = !precomputed && ctx?.notifications[ctx.calls.length] === true;\n if (!precomputed) ctx?.calls.push({ mcpFake: null, error: null });\n const outcome: CallOutcome = ctx?.calls[ctx.calls.length - 1] ?? {\n mcpFake: null,\n error: null,\n };\n // A notification (no `id` member) gets no answer (JSON-RPC 2.0) and\n // claims no fake entry, but a registered handler still runs for its\n // side effects, as on origin/main. A request whose id is null or of\n // another type is still served, with id null.\n const { name: rawName, arguments: args } = (params ?? {}) as {\n name?: unknown;\n arguments?: unknown;\n };\n if (!rawName) {\n return jsonRpcError(id, -32602, \"Missing tool name\");\n }\n if (typeof rawName !== \"string\") {\n const got = Array.isArray(rawName) ? \"array\" : typeof rawName;\n return jsonRpcError(\n id,\n -32602,\n build(msg`Invalid tool name: expected a string, got ${fixed(got)}`),\n );\n }\n const name = rawName;\n // Spec 10 steps 1-2: fakes, then the deny policy; never a handler\n // after a fake failure.\n if (precomputed?.kind === \"reply\") return precomputed.value;\n if (ctx && !isNotification && !precomputed) {\n const fake = callFake(ctx, outcome, name, args, id);\n if (fake) return fake;\n }\n const entry = state.tools.get(name);\n // RP2: every tools/call no fake applied to is logged with who answers it.\n if (ctx && !isNotification) {\n state.onUnfaked({\n identity: ctx.identity,\n tool: name,\n mount: ctx.mount,\n args,\n answeredBy: !entry\n ? \"unknown-tool\"\n : entry.handler && configToolHandlers.has(entry.handler)\n ? \"config\"\n : entry.handler\n ? \"handler\"\n : \"empty\",\n });\n }\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown tool: ${name}`);\n }\n if (entry.handler) {\n try {\n const result = await entry.handler(args);\n const content: MCPContent[] = Array.isArray(result)\n ? result\n : [{ type: \"text\", text: String(result) }];\n return jsonRpcResult(id, { content, isError: false });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return jsonRpcResult(id, {\n content: [{ type: \"text\", text: message }],\n isError: true,\n });\n }\n }\n // No handler — return empty content\n return jsonRpcResult(id, { content: [], isError: false });\n },\n\n \"resources/list\": async (_params, id) => {\n const resources: MCPResourceDefinition[] = [];\n for (const { def } of state.resources.values()) {\n resources.push(def);\n }\n return jsonRpcResult(id, { resources });\n },\n\n \"resources/read\": async (params, id) => {\n const { uri } = (params ?? {}) as { uri?: string };\n if (!uri) {\n return jsonRpcError(id, -32602, \"Missing resource URI\");\n }\n const entry = state.resources.get(uri);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown resource: ${uri}`);\n }\n const text = entry.content?.text;\n const blob = entry.content?.blob;\n // A resource added without content still needs text or blob: MCP clients\n // reject resource contents that carry neither.\n const mimeType = entry.content?.mimeType ?? entry.def.mimeType;\n return jsonRpcResult(id, {\n contents: [\n {\n uri,\n ...(text !== undefined && { text }),\n ...(blob !== undefined && { blob }),\n ...(text === undefined && blob === undefined && { text: \"\" }),\n ...(mimeType !== undefined && { mimeType }),\n },\n ],\n });\n },\n\n \"prompts/list\": async (_params, id) => {\n const prompts: MCPPromptDefinition[] = [];\n for (const { def } of state.prompts.values()) {\n prompts.push(def);\n }\n return jsonRpcResult(id, { prompts });\n },\n\n \"prompts/get\": async (params, id) => {\n const { name, arguments: args } = (params ?? {}) as { name?: string; arguments?: unknown };\n if (!name) {\n return jsonRpcError(id, -32602, \"Missing prompt name\");\n }\n const entry = state.prompts.get(name);\n if (!entry) {\n return jsonRpcError(id, -32602, `Unknown prompt: ${name}`);\n }\n if (entry.handler) {\n try {\n const result = await entry.handler(args);\n return jsonRpcResult(id, result);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return jsonRpcError(id, -32603, `Prompt handler error: ${message}`);\n }\n }\n // No handler — return empty messages\n return jsonRpcResult(id, { messages: [] });\n },\n },\n });\n\n /** Answer a rejected identity (H4, H5) with HTTP 400, in the session-error shape. */\n const rejectIdentity = (\n res: http.ServerResponse,\n resolution: Extract<McpIdentityResolution, { ok: false }>,\n ): void => {\n res.writeHead(resolution.error.status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: resolution.error.message, code: resolution.error.code }));\n };\n\n /**\n * L2: report each identity value that fell back to the raw value (H1),\n * naming its source (header or query) and the value itself, and any query\n * name that did not decode. `fellBack` says only that some value of the\n * field fell back; the header is checked on its own, and the query by the\n * same resolver given the query alone, so the rules are the resolver's.\n */\n const reportFallback = (\n sessionId: string,\n req: http.IncomingMessage,\n resolution: Extract<McpIdentityResolution, { ok: true }>,\n ): void => {\n if (!state.hasFakes()) return;\n const { fellBack } = resolution;\n if (fellBack.testId || fellBack.context) {\n const queryOnly = resolveMcpIdentity({ headers: {}, url: req.url });\n for (const field of [\"testId\", \"context\"] as const) {\n if (!fellBack[field]) continue;\n const header = req.headers[IDENTITY_HEADERS[field]];\n const headerSent = typeof header === \"string\" && header !== \"\";\n if (headerSent && decodeMcpHeaderValue(header).fellBack) {\n state.onDecodeFallback(sessionId, {\n kind: \"value\",\n field,\n source: \"header\",\n raw: header,\n used: true,\n });\n }\n const fromQuery =\n queryOnly.ok && queryOnly.fellBack[field] ? queryOnly.identity[field] : null;\n if (fromQuery !== null) {\n state.onDecodeFallback(sessionId, {\n kind: \"value\",\n field,\n source: \"query\",\n raw: fromQuery,\n used: !headerSent,\n });\n }\n }\n }\n if (resolution.undecodedQueryNames) {\n state.onDecodeFallback(sessionId, { kind: \"names\", count: resolution.undecodedQueryNames });\n }\n };\n\n /**\n * Handle one MCP request. `mount` is the path the mount is served at (I9;\n * `/` for a standalone server). Resolves with what the request resolved,\n * for the mount's journal entry.\n */\n return async (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n mount = \"/\",\n record: MCPRequestRecord = newMCPRequestRecord(),\n ): Promise<MCPRequestRecord> => {\n /** T1: recorded `atMs` / `durationMs` are measured from here. */\n const arrivedAt = performance.now();\n // DELETE handler: session teardown\n if (req.method === \"DELETE\") {\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing mcp-session-id header\" }));\n return record;\n }\n if (!state.sessions.has(sessionId)) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Session not found\" }));\n return record;\n }\n // Journal only: identity inputs are not checked on a session teardown.\n const resolution = resolveMcpIdentity(req, state.sessions.get(sessionId));\n if (resolution.ok) record.identity = resolution.identity;\n state.sessions.delete(sessionId);\n logLevels.delete(sessionId);\n state.onSessionClosed(sessionId);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return record;\n }\n\n // Identity inputs (I1-I3, H4, H5): on every POST, a bad undeclared\n // override or a repeated field is rejected before the request is served.\n const headerSessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n const knownSession = headerSessionId ? state.sessions.get(headerSessionId) : undefined;\n\n // Parse the body to determine method for session validation\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n const resolution = resolveMcpIdentity(req, knownSession);\n if (!resolution.ok) {\n rejectIdentity(res, resolution);\n return record;\n }\n record.identity = resolution.identity;\n if (headerSessionId && knownSession) reportFallback(headerSessionId, req, resolution);\n // Let the dispatcher handle parse errors\n await dispatcher(req, res, body);\n return record;\n }\n\n const method =\n typeof parsed === \"object\" && parsed !== null && \"method\" in parsed\n ? (parsed as { method: unknown }).method\n : undefined;\n\n // Handle initialize directly to control response headers\n if (method === \"initialize\") {\n const id =\n typeof parsed === \"object\" && parsed !== null && \"id\" in parsed\n ? (parsed as { id: unknown }).id\n : null;\n\n // I3: only the values the initialize request itself supplies are bound.\n const resolution = resolveMcpIdentity(req);\n if (!resolution.ok) {\n rejectIdentity(res, resolution);\n return record;\n }\n record.identity = resolution.identity;\n const { identity, supplied } = resolution;\n\n const sessionId = randomUUID();\n state.sessions.set(sessionId, {\n id: sessionId,\n initialized: false,\n createdAt: Date.now(),\n ...(supplied.testId && identity.testId !== null ? { testId: identity.testId } : {}),\n ...(supplied.context && identity.context !== null ? { context: identity.context } : {}),\n ...(supplied.undeclared && identity.undeclared !== null\n ? { undeclared: identity.undeclared }\n : {}),\n });\n reportFallback(sessionId, req, resolution);\n\n const response = {\n jsonrpc: \"2.0\",\n id,\n result: {\n protocolVersion: \"2025-03-26\",\n capabilities: capabilities(),\n serverInfo: state.serverInfo,\n },\n };\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Mcp-Session-Id\": sessionId,\n });\n res.end(JSON.stringify(response));\n return record;\n }\n\n const resolution = resolveMcpIdentity(req, knownSession);\n if (!resolution.ok) {\n rejectIdentity(res, resolution);\n return record;\n }\n record.identity = resolution.identity;\n\n // Session validation for all other methods\n const sessionId = headerSessionId;\n if (!sessionId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing mcp-session-id header\" }));\n return record;\n }\n if (!state.sessions.has(sessionId)) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Session not found\" }));\n return record;\n }\n reportFallback(sessionId, req, resolution);\n\n // Enforce initialization: only allow notifications/initialized through\n // before the session is fully initialized\n const session = state.sessions.get(sessionId)!;\n if (!session.initialized && method !== \"notifications/initialized\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n jsonRpcError(\n typeof parsed === \"object\" && parsed !== null && \"id\" in parsed\n ? ((parsed as { id: unknown }).id as string | number)\n : null,\n -32002,\n \"Session not initialized\",\n ),\n ),\n );\n return record;\n }\n\n // Delegate to the JSON-RPC dispatcher for all other methods\n // The dispatcher invokes `tools/call` once per message that is an object\n // with `jsonrpc: \"2.0\"` and that method, in order (see B2 below).\n const notifications = (Array.isArray(parsed) ? parsed : [parsed])\n .filter((m): m is Record<string, unknown> => isToolsCall(m) && m.jsonrpc === \"2.0\")\n .map((m) => !(\"id\" in m));\n const ctx: FakeRequestContext = {\n identity: resolution.identity,\n mount,\n notifications,\n calls: [],\n };\n contexts.set(req, ctx);\n // MR15 / T1: a single tools/call is claimed here, before the dispatcher,\n // because an answer with recorded timing or notifications is written by\n // `writeFakeToolAnswer` (SSE or delayed JSON), which the dispatcher's\n // JSON-only writer cannot do. Any other outcome is handed to the method\n // through `ctx.precomputed`, so the claim runs once.\n const single = singleToolsCall(parsed);\n if (single) {\n const outcome: CallOutcome = { mcpFake: null, error: null };\n ctx.calls.push(outcome);\n const fake = callFake(ctx, outcome, single.name, single.args, single.id);\n const replay =\n fake && outcome.mcpFake?.outcome === \"answered\" && outcome.mcpFake.id !== null\n ? state.fakes.replayOf(outcome.mcpFake.id)\n : null;\n if (\n fake &&\n \"result\" in fake &&\n replay &&\n (replay.notifications.length > 0 ||\n (replay.timing === \"recorded\" && replay.durationMs !== undefined))\n ) {\n await writeFakeToolAnswer(\n req,\n res,\n single.id,\n fake.result,\n replay,\n single.params,\n state.replaySpeed(),\n logLevels.get(sessionId) ?? null,\n arrivedAt,\n );\n record.messages = [\n { body: single.message, mcpFake: outcome.mcpFake, error: outcome.error },\n ];\n return record;\n }\n ctx.precomputed = fake ? { kind: \"reply\", value: fake } : { kind: \"none\" };\n }\n await dispatcher(req, res, body);\n // B2: each tools/call message is journaled with its body and its own\n // outcome. The dispatcher invokes `tools/call` once per message that is\n // an object with `jsonrpc: \"2.0\"` and that method, in order, so the n-th\n // such message takes the n-th outcome.\n let next = 0;\n const messageOf = (message: unknown): MCPMessageRecord => {\n if (!isToolsCall(message)) return { body: null, mcpFake: null, error: null };\n const outcome = message.jsonrpc === \"2.0\" ? ctx.calls[next++] : undefined;\n return { body: message, mcpFake: outcome?.mcpFake ?? null, error: outcome?.error ?? null };\n };\n record.messages = Array.isArray(parsed) ? parsed.map(messageOf) : [messageOf(parsed)];\n return record;\n };\n}\n\n/**\n * A single JSON-RPC `tools/call` request (not a batch, not a notification)\n * with a string or number id and a string tool name, else `null`. Only such\n * a message is claimed by the outer handler (MR15).\n */\nfunction singleToolsCall(parsed: unknown): {\n message: Record<string, unknown>;\n id: string | number;\n name: string;\n args: unknown;\n params: unknown;\n} | null {\n if (!isToolsCall(parsed) || parsed.jsonrpc !== \"2.0\" || !(\"id\" in parsed)) return null;\n const id = parsed.id;\n if (typeof id !== \"string\" && typeof id !== \"number\") return null;\n const params = parsed.params;\n if (typeof params !== \"object\" || params === null) return null;\n const name: unknown = (params as { name?: unknown }).name;\n if (typeof name !== \"string\" || name === \"\") return null;\n return { message: parsed, id, name, args: (params as { arguments?: unknown }).arguments, params };\n}\n\n/** Resolve after `ms` (no wait when `ms <= 0`). */\nfunction sleep(ms: number): Promise<void> {\n return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();\n}\n\n/** The client's `_meta.progressToken` of a request's params, else `undefined`. */\nfunction progressTokenOf(params: unknown): string | number | undefined {\n if (typeof params !== \"object\" || params === null) return undefined;\n const meta: unknown = (params as { _meta?: unknown })._meta;\n if (typeof meta !== \"object\" || meta === null) return undefined;\n const token: unknown = (meta as { progressToken?: unknown }).progressToken;\n return typeof token === \"string\" || typeof token === \"number\" ? token : undefined;\n}\n\n/**\n * FA3 gate of one recorded notification for this request: the params to send,\n * or `null` when it does not replay. `notifications/progress` replays only\n * when the request carries a progress token, which replaces the recorded one;\n * `notifications/message` only when the session set a log level (C7) and the\n * line is at or above it. No other method replays.\n */\nfunction replayedParams(\n notification: McpFakeNotification,\n progressToken: string | number | undefined,\n logLevel: string | null,\n): Record<string, unknown> | null {\n if (notification.method === \"notifications/progress\") {\n return progressToken === undefined ? null : { ...notification.params, progressToken };\n }\n if (notification.method === \"notifications/message\") {\n const min = logLevelRank(logLevel);\n const rank = logLevelRank(notification.params.level);\n return min !== -1 && rank >= min ? { ...notification.params } : null;\n }\n return null;\n}\n\n/**\n * Write a fake's tools/call answer. SSE iff the entry has a notification whose\n * FA3 gate passes AND Accept lists text/event-stream; else JSON. Timing per T1\n * (value / speed) unless the block's timing is \"immediate\". `logLevel` is the\n * session's `logging/setLevel` level (C7), `arrivedAt` the `performance.now()`\n * of the request's arrival, which `atMs` and `durationMs` are measured from.\n */\nexport async function writeFakeToolAnswer(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n id: string | number | null,\n result: unknown,\n replay: ReturnType<McpFakeStore[\"replayOf\"]>,\n params: unknown,\n speed: number,\n logLevel: string | null = null,\n arrivedAt: number = performance.now(),\n): Promise<void> {\n const timed = replay !== null && replay.timing === \"recorded\";\n const waitUntil = (atMs: number): Promise<void> =>\n timed ? sleep(atMs / speed - (performance.now() - arrivedAt)) : Promise.resolve();\n const token = progressTokenOf(params);\n const notifications = [...(replay?.notifications ?? [])]\n .sort((a, b) => a.atMs - b.atMs)\n .flatMap((n) => {\n const sent = replayedParams(n, token, logLevel);\n return sent ? [{ atMs: n.atMs, method: n.method, params: sent }] : [];\n });\n const accept = req.headers.accept ?? \"\";\n const answer = { jsonrpc: \"2.0\" as const, id, result };\n if (notifications.length > 0 && accept.includes(\"text/event-stream\")) {\n res.writeHead(200, { \"Content-Type\": \"text/event-stream\", \"Cache-Control\": \"no-cache\" });\n res.flushHeaders();\n for (const n of notifications) {\n await waitUntil(n.atMs);\n if (res.destroyed) return;\n res.write(\n `event: message\\ndata: ${JSON.stringify({ jsonrpc: \"2.0\", method: n.method, params: n.params })}\\n\\n`,\n );\n }\n if (replay?.durationMs !== undefined) await waitUntil(replay.durationMs);\n if (res.destroyed) return;\n res.end(`event: message\\ndata: ${JSON.stringify(answer)}\\n\\n`);\n return;\n }\n if (replay?.durationMs !== undefined) await waitUntil(replay.durationMs);\n if (res.destroyed) return;\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(answer));\n}\n\n/** The identity header of each field whose value can fall back (H1). */\nconst IDENTITY_HEADERS: Record<McpDecodeField, string> = {\n testId: \"x-test-id\",\n context: \"x-aimock-context\",\n};\n\n/** A JSON-RPC message object whose method is `tools/call`. */\nfunction isToolsCall(message: unknown): message is Record<string, unknown> {\n return (\n typeof message === \"object\" &&\n message !== null &&\n !Array.isArray(message) &&\n \"method\" in message &&\n message.method === \"tools/call\"\n );\n}\n"],"mappings":"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"}
@@ -351,11 +351,15 @@ function createMCPRequestHandler(state) {
351
351
  if (!uri) return jsonRpcError(id, -32602, "Missing resource URI");
352
352
  const entry = state.resources.get(uri);
353
353
  if (!entry) return jsonRpcError(id, -32602, `Unknown resource: ${uri}`);
354
+ const text = entry.content?.text;
355
+ const blob = entry.content?.blob;
356
+ const mimeType = entry.content?.mimeType ?? entry.def.mimeType;
354
357
  return jsonRpcResult(id, { contents: [{
355
358
  uri,
356
- ...entry.content?.text !== void 0 && { text: entry.content.text },
357
- ...entry.content?.blob !== void 0 && { blob: entry.content.blob },
358
- ...entry.content?.mimeType !== void 0 && { mimeType: entry.content.mimeType }
359
+ ...text !== void 0 && { text },
360
+ ...blob !== void 0 && { blob },
361
+ ...text === void 0 && blob === void 0 && { text: "" },
362
+ ...mimeType !== void 0 && { mimeType }
359
363
  }] });
360
364
  },
361
365
  "prompts/list": async (_params, id) => {