@copilotkit/aimock 1.42.1 → 1.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (442) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +65 -0
  4. package/README.md +108 -16
  5. package/dist/agui-handler.d.ts.map +1 -1
  6. package/dist/agui-mock.cjs +1 -1
  7. package/dist/agui-mock.cjs.map +1 -1
  8. package/dist/agui-mock.d.cts.map +1 -1
  9. package/dist/agui-mock.d.ts.map +1 -1
  10. package/dist/agui-mock.js +1 -1
  11. package/dist/agui-mock.js.map +1 -1
  12. package/dist/agui-recorder.cjs +33 -11
  13. package/dist/agui-recorder.cjs.map +1 -1
  14. package/dist/agui-recorder.d.cts +10 -1
  15. package/dist/agui-recorder.d.cts.map +1 -1
  16. package/dist/agui-recorder.d.ts +10 -1
  17. package/dist/agui-recorder.d.ts.map +1 -1
  18. package/dist/agui-recorder.js +33 -11
  19. package/dist/agui-recorder.js.map +1 -1
  20. package/dist/agui-types.d.cts +1 -0
  21. package/dist/agui-types.d.cts.map +1 -1
  22. package/dist/agui-types.d.ts +1 -0
  23. package/dist/agui-types.d.ts.map +1 -1
  24. package/dist/aimock-cli.cjs +38 -10
  25. package/dist/aimock-cli.cjs.map +1 -1
  26. package/dist/aimock-cli.d.cts +5 -0
  27. package/dist/aimock-cli.d.cts.map +1 -1
  28. package/dist/aimock-cli.d.ts +5 -0
  29. package/dist/aimock-cli.d.ts.map +1 -1
  30. package/dist/aimock-cli.js +38 -10
  31. package/dist/aimock-cli.js.map +1 -1
  32. package/dist/batches.cjs +458 -0
  33. package/dist/batches.cjs.map +1 -0
  34. package/dist/batches.d.cts +57 -0
  35. package/dist/batches.d.cts.map +1 -0
  36. package/dist/batches.d.ts +57 -0
  37. package/dist/batches.d.ts.map +1 -0
  38. package/dist/batches.js +453 -0
  39. package/dist/batches.js.map +1 -0
  40. package/dist/bedrock-converse.cjs +44 -12
  41. package/dist/bedrock-converse.cjs.map +1 -1
  42. package/dist/bedrock-converse.d.cts.map +1 -1
  43. package/dist/bedrock-converse.d.ts.map +1 -1
  44. package/dist/bedrock-converse.js +46 -14
  45. package/dist/bedrock-converse.js.map +1 -1
  46. package/dist/bedrock.cjs +10 -8
  47. package/dist/bedrock.cjs.map +1 -1
  48. package/dist/bedrock.d.cts.map +1 -1
  49. package/dist/bedrock.d.ts.map +1 -1
  50. package/dist/bedrock.js +12 -10
  51. package/dist/bedrock.js.map +1 -1
  52. package/dist/byteplus-video.cjs +3 -3
  53. package/dist/byteplus-video.cjs.map +1 -1
  54. package/dist/byteplus-video.js +4 -4
  55. package/dist/byteplus-video.js.map +1 -1
  56. package/dist/chaos.cjs +625 -72
  57. package/dist/chaos.cjs.map +1 -1
  58. package/dist/chaos.d.cts +164 -7
  59. package/dist/chaos.d.cts.map +1 -1
  60. package/dist/chaos.d.ts +164 -7
  61. package/dist/chaos.d.ts.map +1 -1
  62. package/dist/chaos.js +616 -74
  63. package/dist/chaos.js.map +1 -1
  64. package/dist/cli.cjs +131 -30
  65. package/dist/cli.cjs.map +1 -1
  66. package/dist/cli.js +132 -31
  67. package/dist/cli.js.map +1 -1
  68. package/dist/cohere.cjs +37 -9
  69. package/dist/cohere.cjs.map +1 -1
  70. package/dist/cohere.d.cts.map +1 -1
  71. package/dist/cohere.d.ts.map +1 -1
  72. package/dist/cohere.js +39 -11
  73. package/dist/cohere.js.map +1 -1
  74. package/dist/config-loader.cjs +1 -1
  75. package/dist/config-loader.js +1 -1
  76. package/dist/constants.cjs +8 -0
  77. package/dist/constants.cjs.map +1 -1
  78. package/dist/constants.d.cts +6 -2
  79. package/dist/constants.d.ts +6 -2
  80. package/dist/constants.js +8 -1
  81. package/dist/constants.js.map +1 -1
  82. package/dist/convert.cjs +1 -1
  83. package/dist/convert.cjs.map +1 -1
  84. package/dist/convert.js +1 -1
  85. package/dist/convert.js.map +1 -1
  86. package/dist/echo-text.cjs +65 -0
  87. package/dist/echo-text.cjs.map +1 -0
  88. package/dist/echo-text.d.cts +22 -0
  89. package/dist/echo-text.d.cts.map +1 -0
  90. package/dist/echo-text.d.ts +22 -0
  91. package/dist/echo-text.d.ts.map +1 -0
  92. package/dist/echo-text.js +65 -0
  93. package/dist/echo-text.js.map +1 -0
  94. package/dist/elevenlabs-audio.cjs +3 -3
  95. package/dist/elevenlabs-audio.cjs.map +1 -1
  96. package/dist/elevenlabs-audio.js +4 -4
  97. package/dist/elevenlabs-audio.js.map +1 -1
  98. package/dist/elevenlabs-voice.cjs +1053 -0
  99. package/dist/elevenlabs-voice.cjs.map +1 -0
  100. package/dist/elevenlabs-voice.d.cts +72 -0
  101. package/dist/elevenlabs-voice.d.cts.map +1 -0
  102. package/dist/elevenlabs-voice.d.ts +72 -0
  103. package/dist/elevenlabs-voice.d.ts.map +1 -0
  104. package/dist/elevenlabs-voice.js +1048 -0
  105. package/dist/elevenlabs-voice.js.map +1 -0
  106. package/dist/embeddings.cjs +26 -5
  107. package/dist/embeddings.cjs.map +1 -1
  108. package/dist/embeddings.d.cts +1 -1
  109. package/dist/embeddings.d.cts.map +1 -1
  110. package/dist/embeddings.d.ts +1 -1
  111. package/dist/embeddings.d.ts.map +1 -1
  112. package/dist/embeddings.js +27 -6
  113. package/dist/embeddings.js.map +1 -1
  114. package/dist/fal-audio.cjs +3 -3
  115. package/dist/fal-audio.cjs.map +1 -1
  116. package/dist/fal-audio.js +4 -4
  117. package/dist/fal-audio.js.map +1 -1
  118. package/dist/fal.cjs +28 -4
  119. package/dist/fal.cjs.map +1 -1
  120. package/dist/fal.d.cts +16 -1
  121. package/dist/fal.d.cts.map +1 -1
  122. package/dist/fal.d.ts +16 -1
  123. package/dist/fal.d.ts.map +1 -1
  124. package/dist/fal.js +28 -5
  125. package/dist/fal.js.map +1 -1
  126. package/dist/files.cjs +1069 -0
  127. package/dist/files.cjs.map +1 -0
  128. package/dist/files.d.cts +68 -0
  129. package/dist/files.d.cts.map +1 -0
  130. package/dist/files.d.ts +68 -0
  131. package/dist/files.d.ts.map +1 -0
  132. package/dist/files.js +1056 -0
  133. package/dist/files.js.map +1 -0
  134. package/dist/fine-tuning.cjs +1033 -0
  135. package/dist/fine-tuning.cjs.map +1 -0
  136. package/dist/fine-tuning.d.cts +96 -0
  137. package/dist/fine-tuning.d.cts.map +1 -0
  138. package/dist/fine-tuning.d.ts +96 -0
  139. package/dist/fine-tuning.d.ts.map +1 -0
  140. package/dist/fine-tuning.js +1026 -0
  141. package/dist/fine-tuning.js.map +1 -0
  142. package/dist/fixture-loader-services.cjs +116 -0
  143. package/dist/fixture-loader-services.cjs.map +1 -0
  144. package/dist/fixture-loader-services.d.cts +48 -0
  145. package/dist/fixture-loader-services.d.cts.map +1 -0
  146. package/dist/fixture-loader-services.d.ts +48 -0
  147. package/dist/fixture-loader-services.d.ts.map +1 -0
  148. package/dist/fixture-loader-services.js +114 -0
  149. package/dist/fixture-loader-services.js.map +1 -0
  150. package/dist/fixture-loader.cjs +0 -0
  151. package/dist/fixture-loader.cjs.map +1 -1
  152. package/dist/fixture-loader.d.cts +131 -5
  153. package/dist/fixture-loader.d.cts.map +1 -1
  154. package/dist/fixture-loader.d.ts +131 -5
  155. package/dist/fixture-loader.d.ts.map +1 -1
  156. package/dist/fixture-loader.js +0 -0
  157. package/dist/fixture-loader.js.map +1 -1
  158. package/dist/gemini-embeddings.cjs +44 -4
  159. package/dist/gemini-embeddings.cjs.map +1 -1
  160. package/dist/gemini-embeddings.js +46 -6
  161. package/dist/gemini-embeddings.js.map +1 -1
  162. package/dist/gemini-interactions.cjs +51 -7
  163. package/dist/gemini-interactions.cjs.map +1 -1
  164. package/dist/gemini-interactions.d.cts.map +1 -1
  165. package/dist/gemini-interactions.d.ts.map +1 -1
  166. package/dist/gemini-interactions.js +53 -9
  167. package/dist/gemini-interactions.js.map +1 -1
  168. package/dist/gemini.cjs +19 -8
  169. package/dist/gemini.cjs.map +1 -1
  170. package/dist/gemini.d.cts.map +1 -1
  171. package/dist/gemini.d.ts.map +1 -1
  172. package/dist/gemini.js +21 -10
  173. package/dist/gemini.js.map +1 -1
  174. package/dist/grok-video.cjs +14 -14
  175. package/dist/grok-video.cjs.map +1 -1
  176. package/dist/grok-video.js +15 -15
  177. package/dist/grok-video.js.map +1 -1
  178. package/dist/helpers.cjs +497 -10
  179. package/dist/helpers.cjs.map +1 -1
  180. package/dist/helpers.d.cts +38 -2
  181. package/dist/helpers.d.cts.map +1 -1
  182. package/dist/helpers.d.ts +38 -2
  183. package/dist/helpers.d.ts.map +1 -1
  184. package/dist/helpers.js +487 -12
  185. package/dist/helpers.js.map +1 -1
  186. package/dist/images.cjs +57 -125
  187. package/dist/images.cjs.map +1 -1
  188. package/dist/images.d.cts.map +1 -1
  189. package/dist/images.d.ts.map +1 -1
  190. package/dist/images.js +58 -126
  191. package/dist/images.js.map +1 -1
  192. package/dist/index.cjs +71 -9
  193. package/dist/index.d.cts +17 -7
  194. package/dist/index.d.ts +17 -7
  195. package/dist/index.js +21 -11
  196. package/dist/jest.cjs +24 -12
  197. package/dist/jest.cjs.map +1 -1
  198. package/dist/jest.d.cts +6 -3
  199. package/dist/jest.d.cts.map +1 -1
  200. package/dist/jest.d.ts +6 -3
  201. package/dist/jest.d.ts.map +1 -1
  202. package/dist/jest.js +25 -13
  203. package/dist/jest.js.map +1 -1
  204. package/dist/journal.cjs +61 -4
  205. package/dist/journal.cjs.map +1 -1
  206. package/dist/journal.d.cts +60 -3
  207. package/dist/journal.d.cts.map +1 -1
  208. package/dist/journal.d.ts +60 -3
  209. package/dist/journal.d.ts.map +1 -1
  210. package/dist/journal.js +61 -5
  211. package/dist/journal.js.map +1 -1
  212. package/dist/live-fixture.cjs +1192 -0
  213. package/dist/live-fixture.cjs.map +1 -0
  214. package/dist/live-fixture.js +1187 -0
  215. package/dist/live-fixture.js.map +1 -0
  216. package/dist/live-recorder.cjs +256 -0
  217. package/dist/live-recorder.cjs.map +1 -0
  218. package/dist/live-recorder.js +254 -0
  219. package/dist/live-recorder.js.map +1 -0
  220. package/dist/live-replay.cjs +286 -0
  221. package/dist/live-replay.cjs.map +1 -0
  222. package/dist/live-replay.js +285 -0
  223. package/dist/live-replay.js.map +1 -0
  224. package/dist/live-sanitize.cjs +196 -0
  225. package/dist/live-sanitize.cjs.map +1 -0
  226. package/dist/live-sanitize.js +196 -0
  227. package/dist/live-sanitize.js.map +1 -0
  228. package/dist/live-types.d.cts +71 -0
  229. package/dist/live-types.d.cts.map +1 -0
  230. package/dist/live-types.d.ts +71 -0
  231. package/dist/live-types.d.ts.map +1 -0
  232. package/dist/llmock.cjs +132 -49
  233. package/dist/llmock.cjs.map +1 -1
  234. package/dist/llmock.d.cts +51 -5
  235. package/dist/llmock.d.cts.map +1 -1
  236. package/dist/llmock.d.ts +51 -5
  237. package/dist/llmock.d.ts.map +1 -1
  238. package/dist/llmock.js +133 -50
  239. package/dist/llmock.js.map +1 -1
  240. package/dist/mcp-fakes-mount.cjs +216 -0
  241. package/dist/mcp-fakes-mount.cjs.map +1 -0
  242. package/dist/mcp-fakes-mount.js +210 -0
  243. package/dist/mcp-fakes-mount.js.map +1 -0
  244. package/dist/mcp-fakes.cjs +1619 -0
  245. package/dist/mcp-fakes.cjs.map +1 -0
  246. package/dist/mcp-fakes.d.cts +101 -0
  247. package/dist/mcp-fakes.d.cts.map +1 -0
  248. package/dist/mcp-fakes.d.ts +101 -0
  249. package/dist/mcp-fakes.d.ts.map +1 -0
  250. package/dist/mcp-fakes.js +1614 -0
  251. package/dist/mcp-fakes.js.map +1 -0
  252. package/dist/mcp-handler.cjs +331 -17
  253. package/dist/mcp-handler.cjs.map +1 -1
  254. package/dist/mcp-handler.js +330 -18
  255. package/dist/mcp-handler.js.map +1 -1
  256. package/dist/mcp-mock.cjs +217 -49
  257. package/dist/mcp-mock.cjs.map +1 -1
  258. package/dist/mcp-mock.d.cts +66 -1
  259. package/dist/mcp-mock.d.cts.map +1 -1
  260. package/dist/mcp-mock.d.ts +66 -1
  261. package/dist/mcp-mock.d.ts.map +1 -1
  262. package/dist/mcp-mock.js +218 -50
  263. package/dist/mcp-mock.js.map +1 -1
  264. package/dist/mcp-stub.cjs +5 -1
  265. package/dist/mcp-stub.d.cts +3 -1
  266. package/dist/mcp-stub.d.ts +3 -1
  267. package/dist/mcp-stub.js +3 -1
  268. package/dist/mcp-types.d.cts +6 -0
  269. package/dist/mcp-types.d.ts +6 -0
  270. package/dist/message-text.cjs +192 -0
  271. package/dist/message-text.cjs.map +1 -0
  272. package/dist/message-text.d.cts +31 -0
  273. package/dist/message-text.d.cts.map +1 -0
  274. package/dist/message-text.d.ts +31 -0
  275. package/dist/message-text.d.ts.map +1 -0
  276. package/dist/message-text.js +184 -0
  277. package/dist/message-text.js.map +1 -0
  278. package/dist/messages.cjs +49 -7
  279. package/dist/messages.cjs.map +1 -1
  280. package/dist/messages.d.cts.map +1 -1
  281. package/dist/messages.d.ts.map +1 -1
  282. package/dist/messages.js +51 -9
  283. package/dist/messages.js.map +1 -1
  284. package/dist/metrics.cjs +278 -45
  285. package/dist/metrics.cjs.map +1 -1
  286. package/dist/metrics.d.cts +17 -7
  287. package/dist/metrics.d.cts.map +1 -1
  288. package/dist/metrics.d.ts +17 -7
  289. package/dist/metrics.d.ts.map +1 -1
  290. package/dist/metrics.js +270 -29
  291. package/dist/metrics.js.map +1 -1
  292. package/dist/moderation.cjs +10 -1
  293. package/dist/moderation.cjs.map +1 -1
  294. package/dist/moderation.d.cts.map +1 -1
  295. package/dist/moderation.d.ts.map +1 -1
  296. package/dist/moderation.js +10 -1
  297. package/dist/moderation.js.map +1 -1
  298. package/dist/ollama.cjs +10 -6
  299. package/dist/ollama.cjs.map +1 -1
  300. package/dist/ollama.d.cts.map +1 -1
  301. package/dist/ollama.d.ts.map +1 -1
  302. package/dist/ollama.js +11 -7
  303. package/dist/ollama.js.map +1 -1
  304. package/dist/openapi.cjs +3405 -0
  305. package/dist/openapi.cjs.map +1 -0
  306. package/dist/openapi.d.cts +30 -0
  307. package/dist/openapi.d.cts.map +1 -0
  308. package/dist/openapi.d.ts +30 -0
  309. package/dist/openapi.d.ts.map +1 -0
  310. package/dist/openapi.js +3404 -0
  311. package/dist/openapi.js.map +1 -0
  312. package/dist/openrouter-video.cjs +9 -9
  313. package/dist/openrouter-video.cjs.map +1 -1
  314. package/dist/openrouter-video.d.cts.map +1 -1
  315. package/dist/openrouter-video.d.ts.map +1 -1
  316. package/dist/openrouter-video.js +10 -10
  317. package/dist/openrouter-video.js.map +1 -1
  318. package/dist/recorder.cjs +54 -10
  319. package/dist/recorder.cjs.map +1 -1
  320. package/dist/recorder.d.cts.map +1 -1
  321. package/dist/recorder.d.ts.map +1 -1
  322. package/dist/recorder.js +52 -12
  323. package/dist/recorder.js.map +1 -1
  324. package/dist/responses.cjs +47 -7
  325. package/dist/responses.cjs.map +1 -1
  326. package/dist/responses.d.cts.map +1 -1
  327. package/dist/responses.d.ts.map +1 -1
  328. package/dist/responses.js +48 -9
  329. package/dist/responses.js.map +1 -1
  330. package/dist/route-registry.cjs +951 -0
  331. package/dist/route-registry.cjs.map +1 -0
  332. package/dist/route-registry.d.cts +33 -0
  333. package/dist/route-registry.d.cts.map +1 -0
  334. package/dist/route-registry.d.ts +33 -0
  335. package/dist/route-registry.d.ts.map +1 -0
  336. package/dist/route-registry.js +866 -0
  337. package/dist/route-registry.js.map +1 -0
  338. package/dist/router.cjs +21 -34
  339. package/dist/router.cjs.map +1 -1
  340. package/dist/router.d.cts +4 -1
  341. package/dist/router.d.cts.map +1 -1
  342. package/dist/router.d.ts +4 -1
  343. package/dist/router.d.ts.map +1 -1
  344. package/dist/router.js +21 -35
  345. package/dist/router.js.map +1 -1
  346. package/dist/server.cjs +1252 -777
  347. package/dist/server.cjs.map +1 -1
  348. package/dist/server.d.cts +5 -1
  349. package/dist/server.d.cts.map +1 -1
  350. package/dist/server.d.ts +5 -1
  351. package/dist/server.d.ts.map +1 -1
  352. package/dist/server.js +1185 -710
  353. package/dist/server.js.map +1 -1
  354. package/dist/speech.cjs +6 -4
  355. package/dist/speech.cjs.map +1 -1
  356. package/dist/speech.js +7 -5
  357. package/dist/speech.js.map +1 -1
  358. package/dist/suite.cjs +1 -1
  359. package/dist/suite.js +1 -1
  360. package/dist/transcription.cjs +6 -6
  361. package/dist/transcription.cjs.map +1 -1
  362. package/dist/transcription.d.cts.map +1 -1
  363. package/dist/transcription.d.ts.map +1 -1
  364. package/dist/transcription.js +7 -7
  365. package/dist/transcription.js.map +1 -1
  366. package/dist/types.cjs +18 -0
  367. package/dist/types.cjs.map +1 -0
  368. package/dist/types.d.cts +320 -17
  369. package/dist/types.d.cts.map +1 -1
  370. package/dist/types.d.ts +320 -17
  371. package/dist/types.d.ts.map +1 -1
  372. package/dist/types.js +17 -0
  373. package/dist/types.js.map +1 -0
  374. package/dist/validate-cli.cjs +983 -0
  375. package/dist/validate-cli.cjs.map +1 -0
  376. package/dist/validate-cli.js +982 -0
  377. package/dist/validate-cli.js.map +1 -0
  378. package/dist/vector-stores.cjs +1180 -0
  379. package/dist/vector-stores.cjs.map +1 -0
  380. package/dist/vector-stores.d.cts +106 -0
  381. package/dist/vector-stores.d.cts.map +1 -0
  382. package/dist/vector-stores.d.ts +106 -0
  383. package/dist/vector-stores.d.ts.map +1 -0
  384. package/dist/vector-stores.js +1164 -0
  385. package/dist/vector-stores.js.map +1 -0
  386. package/dist/vector-types.d.cts.map +1 -1
  387. package/dist/vector-types.d.ts.map +1 -1
  388. package/dist/veo-video.cjs +13 -13
  389. package/dist/veo-video.cjs.map +1 -1
  390. package/dist/veo-video.js +14 -14
  391. package/dist/veo-video.js.map +1 -1
  392. package/dist/video.cjs +23 -4
  393. package/dist/video.cjs.map +1 -1
  394. package/dist/video.d.cts +1 -1
  395. package/dist/video.d.cts.map +1 -1
  396. package/dist/video.d.ts +1 -1
  397. package/dist/video.d.ts.map +1 -1
  398. package/dist/video.js +24 -5
  399. package/dist/video.js.map +1 -1
  400. package/dist/vitest.cjs +23 -11
  401. package/dist/vitest.cjs.map +1 -1
  402. package/dist/vitest.d.cts +5 -2
  403. package/dist/vitest.d.cts.map +1 -1
  404. package/dist/vitest.d.ts +5 -2
  405. package/dist/vitest.d.ts.map +1 -1
  406. package/dist/vitest.js +25 -13
  407. package/dist/vitest.js.map +1 -1
  408. package/dist/watcher.cjs +2 -1
  409. package/dist/watcher.cjs.map +1 -1
  410. package/dist/watcher.js +2 -1
  411. package/dist/watcher.js.map +1 -1
  412. package/dist/ws-framing.cjs +150 -35
  413. package/dist/ws-framing.cjs.map +1 -1
  414. package/dist/ws-framing.d.cts +18 -3
  415. package/dist/ws-framing.d.cts.map +1 -1
  416. package/dist/ws-framing.d.ts +18 -3
  417. package/dist/ws-framing.d.ts.map +1 -1
  418. package/dist/ws-framing.js +151 -36
  419. package/dist/ws-framing.js.map +1 -1
  420. package/dist/ws-gemini-live.cjs +2 -2
  421. package/dist/ws-gemini-live.js +2 -2
  422. package/dist/ws-live.cjs +401 -0
  423. package/dist/ws-live.cjs.map +1 -0
  424. package/dist/ws-live.js +400 -0
  425. package/dist/ws-live.js.map +1 -0
  426. package/dist/ws-realtime.cjs +46 -2
  427. package/dist/ws-realtime.cjs.map +1 -1
  428. package/dist/ws-realtime.d.cts.map +1 -1
  429. package/dist/ws-realtime.d.ts.map +1 -1
  430. package/dist/ws-realtime.js +46 -2
  431. package/dist/ws-realtime.js.map +1 -1
  432. package/dist/ws-responses.cjs +16 -4
  433. package/dist/ws-responses.cjs.map +1 -1
  434. package/dist/ws-responses.js +16 -4
  435. package/dist/ws-responses.js.map +1 -1
  436. package/dist/ws-upstream.cjs +118 -0
  437. package/dist/ws-upstream.cjs.map +1 -0
  438. package/dist/ws-upstream.js +115 -0
  439. package/dist/ws-upstream.js.map +1 -0
  440. package/fixtures/openai-live-client.json +390 -0
  441. package/fixtures/openai-live-managed.json +709 -0
  442. package/package.json +4 -1
package/dist/llmock.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Journal } from "./journal.js";
2
- import { AudioResponse, ChaosConfig, EmbeddingFixtureOpts, FalQueueOpts, Fixture, FixtureFileEntry, FixtureFileResponse, FixtureMatch, FixtureOpts, ImageResponse, JournalEntry, MockServerOptions, Mountable, RecordConfig, ResponseFactory, TranscriptionResponse, VideoResponse } from "./types.js";
2
+ import { LiveTranscript } from "./live-types.js";
3
+ import { AudioResponse, ChaosConfig, EmbeddingFixtureOpts, FalQueueOpts, Fixture, FixtureFileEntry, FixtureFileResponse, FixtureMatch, FixtureOpts, ImageResponse, JournalEntry, MockServerOptions, Mountable, RecordConfig, ResponseFactory, TranscriptionResponse, VideoResponse, VoiceDesignResponse } from "./types.js";
3
4
  import { ResolvedInboundAuth } from "./api-key-auth.js";
4
5
  import { SearchResult } from "./search.js";
5
6
  import { RerankResult } from "./rerank.js";
@@ -12,16 +13,48 @@ declare class LLMock {
12
13
  private rerankFixtures;
13
14
  private moderationFixtures;
14
15
  private mounts;
16
+ /** `mcpFakes` blocks loaded before `start()`, handed to the server at start (W2). */
17
+ private mcpFakeBuffer;
18
+ /** MCPMocks the server or a load auto-mounted (W3, W6), for the L6 check. */
15
19
  private serverInstance;
16
20
  private options;
17
21
  private readonly resolvedInboundAuth?;
18
22
  constructor(options?: MockServerOptions, resolvedInboundAuth?: ResolvedInboundAuth);
23
+ private normalizeFixture;
19
24
  addFixture(fixture: Fixture): this;
20
25
  addFixtures(fixtures: Fixture[]): this;
21
26
  prependFixture(fixture: Fixture): this;
22
27
  getFixtures(): readonly Fixture[];
28
+ /**
29
+ * Load a fixture file: its LLM fixtures and its `mcpFakes` blocks (F4).
30
+ * Before `start()` the blocks are buffered and handed to the server at
31
+ * start (W2); after it they go to the MCPMock serving each block's `mount`
32
+ * path, auto-mounted when none does (W6). A block that cannot be honored
33
+ * throws a `FixtureLoadError` and nothing from the file is added.
34
+ */
23
35
  loadFixtureFile(filePath: string): this;
36
+ /** As {@link loadFixtureFile}, for every fixture file under `dirPath`. */
24
37
  loadFixtureDir(dirPath: string): this;
38
+ /**
39
+ * Add a load's fakes (all or nothing), then its LLM fixtures. Before start
40
+ * the fakes are checked as the start-time hand-off will check them, with
41
+ * the blocks already buffered and the mounts added so far, so a file whose
42
+ * fakes would be rejected adds nothing. A mount added after the load can
43
+ * still make `start()` reject.
44
+ */
45
+ private acceptLoaded;
46
+ /**
47
+ * W6 for a load after start. Every group of blocks (by `mount` path) is
48
+ * checked before any mount is touched: a path held by a mount that is not
49
+ * an MCPMock is a mount conflict, and each group is first added to a
50
+ * throwaway store. Groups for an existing MCPMock are then added to it (its
51
+ * own add is all or nothing and finds collisions with its loaded ids);
52
+ * groups for a free path are added last, to a new auto-mounted MCPMock,
53
+ * wired as W4. The add warnings (L8) are logged at `warn`.
54
+ */
55
+ private addFakesAfterStart;
56
+ /** R4, R5: unload the fakes of every mount and the pre-start buffer. */
57
+ private unloadMcpFakes;
25
58
  /**
26
59
  * Add fixtures from a JSON string or pre-parsed array of fixture entries.
27
60
  * Validates all fixtures and throws if any have severity "error".
@@ -29,6 +62,7 @@ declare class LLMock {
29
62
  addFixturesFromJSON(input: string | FixtureFileEntry[]): this;
30
63
  clearFixtures(): this;
31
64
  on(match: FixtureMatch, response: FixtureFileResponse | ResponseFactory, opts?: FixtureOpts): this;
65
+ onLive(match: Omit<FixtureMatch, "endpoint">, transcript: LiveTranscript, opts?: FixtureOpts): this;
32
66
  onMessage(pattern: string | RegExp, response: FixtureFileResponse | ResponseFactory, opts?: FixtureOpts): this;
33
67
  onEmbedding(pattern: string | RegExp, response: FixtureFileResponse | ResponseFactory, opts?: EmbeddingFixtureOpts): this;
34
68
  onJsonOutput(pattern: string | RegExp, jsonContent: object | string, opts?: FixtureOpts): this;
@@ -44,6 +78,7 @@ declare class LLMock {
44
78
  onSoundEffect(text: string | RegExp, response: AudioResponse): this;
45
79
  onMusic(prompt: string | RegExp, response: AudioResponse): this;
46
80
  onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this;
81
+ onElevenLabsVoiceDesign(description: string | RegExp, response: VoiceDesignResponse): this;
47
82
  onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this;
48
83
  onFalQueue(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this;
49
84
  onFalRun(modelOrPrompt: string | RegExp, response: unknown, opts?: FalQueueOpts): this;
@@ -66,8 +101,8 @@ declare class LLMock {
66
101
  /**
67
102
  * Queue a one-shot error that will be returned for the next matching
68
103
  * request, then automatically removed. Implemented as an internal fixture
69
- * with a `predicate` that always matches (so it fires first) and spliced
70
- * at the front of the fixture list.
104
+ * inserted at the front of the fixture list; see `queueOneShotError` for
105
+ * the endpoint gate and the served-not-evaluated consumption rule.
71
106
  */
72
107
  nextRequestError(status: number, errorBody?: {
73
108
  message?: string;
@@ -77,7 +112,15 @@ declare class LLMock {
77
112
  mount(path: string, handler: Mountable): this;
78
113
  getRequests(): JournalEntry[];
79
114
  getLastRequest(): JournalEntry | null;
115
+ /**
116
+ * Clear the request journal. Fixture match-counts (sequencing state) are
117
+ * left intact — use `resetMatchCounts()` for those.
118
+ */
80
119
  clearRequests(): void;
120
+ /**
121
+ * Reset fixture match counts, and the MCP fakes consumption state of every
122
+ * mount (R6), for `testId` or for all test ids. Fakes stay loaded.
123
+ */
81
124
  resetMatchCounts(testId?: string): this;
82
125
  /**
83
126
  * Set the server-wide chaos baseline. Writes through to a RUNNING server as
@@ -107,8 +150,10 @@ declare class LLMock {
107
150
  * NOT ALL OF THIS IS PER-INSTANCE. `performFullReset` clears module-global
108
151
  * state as well: the Gemini interaction and event-id counters
109
152
  * (`resetInteractionCounter` / `resetEventIdCounter` in
110
- * `./gemini-interactions.js`) and the fal.ai job/queue maps (`falJobs`,
111
- * `falQueueStates`). With two `LLMock` instances live in one process,
153
+ * `./gemini-interactions.js`), the fal.ai job/queue maps (`falJobs`,
154
+ * `falQueueStates`), the fine-tuning job store (`clearFineTuningStore`),
155
+ * and the ElevenLabs Voice Design store (`clearElevenLabsVoices`). With two
156
+ * `LLMock` instances live in one process,
112
157
  * `a.reset()` rewinds the Gemini id sequence that `b` is mid-way through —
113
158
  * `b` then re-emits `aimock-int-0` / `evt_1`, ids it has already handed
114
159
  * out — and drops `b`'s in-flight fal jobs. Give each instance its own
@@ -119,6 +164,7 @@ declare class LLMock {
119
164
  */
120
165
  reset(): this;
121
166
  start(): Promise<string>;
167
+ closeLiveSessions(testId?: string): this;
122
168
  stop(): Promise<void>;
123
169
  get journal(): Journal;
124
170
  get url(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"llmock.d.ts","names":[],"sources":["../src/llmock.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"llmock.d.ts","names":[],"sources":["../src/llmock.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/llmock.js CHANGED
@@ -1,6 +1,12 @@
1
- import { INJECTED_STATUS_RANGE, entryToFixture, isInjectableStatus, loadFixtureFile, loadFixturesFromDir, normalizeResponse, validateFixtures } from "./fixture-loader.js";
1
+ import { build, msg, quote } from "./message-text.js";
2
+ import { isLiveResponse } from "./helpers.js";
3
+ import { normalizeLiveFixture, normalizeLiveOptions } from "./live-fixture.js";
4
+ import { INJECTED_STATUS_RANGE, clearFixtureQueue, entryToFixture, isInjectableStatus, normalizeResponse, queueOneShotError, validateFixtures } from "./fixture-loader.js";
2
5
  import { imageResponseToFalJson, videoResponseToFalJson } from "./fal.js";
6
+ import { voiceDesignToJson } from "./elevenlabs-voice.js";
7
+ import { ensureFakeMount, isAutoMount, planFileFakes } from "./mcp-fakes-mount.js";
3
8
  import { createServer, createServerWithResolvedAuth, performFullReset } from "./server.js";
9
+ import { loadFixtureFileWithServices, loadFixturesFromDirWithServices } from "./fixture-loader-services.js";
4
10
 
5
11
  //#region src/llmock.ts
6
12
  var LLMock = class LLMock {
@@ -9,37 +15,104 @@ var LLMock = class LLMock {
9
15
  rerankFixtures = [];
10
16
  moderationFixtures = [];
11
17
  mounts = [];
18
+ /** `mcpFakes` blocks loaded before `start()`, handed to the server at start (W2). */
19
+ mcpFakeBuffer = [];
20
+ /** MCPMocks the server or a load auto-mounted (W3, W6), for the L6 check. */
12
21
  serverInstance = null;
13
22
  options;
14
23
  resolvedInboundAuth;
15
24
  constructor(options, resolvedInboundAuth) {
16
25
  this.options = options ?? {};
26
+ if (this.options.live !== void 0) normalizeLiveOptions(this.options.live);
17
27
  this.resolvedInboundAuth = resolvedInboundAuth;
18
28
  }
29
+ normalizeFixture(fixture) {
30
+ if (isLiveResponse(fixture.response) || fixture.match.endpoint === "openai-live" && typeof fixture.response !== "function") return {
31
+ ...fixture,
32
+ match: { ...fixture.match },
33
+ response: normalizeLiveFixture(fixture.response, this.options.live)
34
+ };
35
+ return fixture;
36
+ }
19
37
  addFixture(fixture) {
20
- this.fixtures.push(fixture);
38
+ this.fixtures.push(this.normalizeFixture(fixture));
21
39
  return this;
22
40
  }
23
41
  addFixtures(fixtures) {
24
- this.fixtures.push(...fixtures);
42
+ this.fixtures.push(...fixtures.map((fixture) => this.normalizeFixture(fixture)));
25
43
  return this;
26
44
  }
27
45
  prependFixture(fixture) {
28
- this.fixtures.unshift(fixture);
46
+ this.fixtures.unshift(this.normalizeFixture(fixture));
29
47
  return this;
30
48
  }
31
49
  getFixtures() {
32
50
  return this.fixtures;
33
51
  }
52
+ /**
53
+ * Load a fixture file: its LLM fixtures and its `mcpFakes` blocks (F4).
54
+ * Before `start()` the blocks are buffered and handed to the server at
55
+ * start (W2); after it they go to the MCPMock serving each block's `mount`
56
+ * path, auto-mounted when none does (W6). A block that cannot be honored
57
+ * throws a `FixtureLoadError` and nothing from the file is added.
58
+ */
34
59
  loadFixtureFile(filePath) {
35
- this.fixtures.push(...loadFixtureFile(filePath));
36
- return this;
60
+ return this.acceptLoaded(loadFixtureFileWithServices(filePath, void 0, this.options.live));
37
61
  }
62
+ /** As {@link loadFixtureFile}, for every fixture file under `dirPath`. */
38
63
  loadFixtureDir(dirPath) {
39
- this.fixtures.push(...loadFixturesFromDir(dirPath));
64
+ return this.acceptLoaded(loadFixturesFromDirWithServices(dirPath, void 0, this.options.live));
65
+ }
66
+ /**
67
+ * Add a load's fakes (all or nothing), then its LLM fixtures. Before start
68
+ * the fakes are checked as the start-time hand-off will check them, with
69
+ * the blocks already buffered and the mounts added so far, so a file whose
70
+ * fakes would be rejected adds nothing. A mount added after the load can
71
+ * still make `start()` reject.
72
+ */
73
+ acceptLoaded(loaded) {
74
+ if (loaded.mcpFakes.length > 0) if (this.serverInstance) this.addFakesAfterStart(this.serverInstance, loaded.mcpFakes);
75
+ else {
76
+ planFileFakes(this.mounts, [...this.mcpFakeBuffer, ...loaded.mcpFakes], new Set(loaded.mcpFakes));
77
+ this.mcpFakeBuffer.push(...loaded.mcpFakes);
78
+ }
79
+ this.fixtures.push(...loaded.fixtures);
40
80
  return this;
41
81
  }
42
82
  /**
83
+ * W6 for a load after start. Every group of blocks (by `mount` path) is
84
+ * checked before any mount is touched: a path held by a mount that is not
85
+ * an MCPMock is a mount conflict, and each group is first added to a
86
+ * throwaway store. Groups for an existing MCPMock are then added to it (its
87
+ * own add is all or nothing and finds collisions with its loaded ids);
88
+ * groups for a free path are added last, to a new auto-mounted MCPMock,
89
+ * wired as W4. The add warnings (L8) are logged at `warn`.
90
+ */
91
+ addFakesAfterStart(server, sources) {
92
+ const { onExisting, onNew } = planFileFakes(this.mounts, sources);
93
+ const logger = server.defaults.logger;
94
+ for (const { handler, group } of onExisting) {
95
+ const result = handler.addMcpFakes?.(group, { kind: "file" });
96
+ for (const warning of result?.warnings ?? []) logger.warn(warning.message);
97
+ }
98
+ const registry = server.defaults.registry;
99
+ for (const { path, group } of onNew) {
100
+ const target = ensureFakeMount(this.mounts, path, {
101
+ journal: server.journal,
102
+ ...registry ? { registry } : {},
103
+ logger
104
+ }, logger);
105
+ if ("conflict" in target) continue;
106
+ const result = target.handler.addMcpFakes?.(group, { kind: "file" });
107
+ for (const warning of result?.warnings ?? []) logger.warn(warning.message);
108
+ }
109
+ }
110
+ /** R4, R5: unload the fakes of every mount and the pre-start buffer. */
111
+ unloadMcpFakes() {
112
+ this.mcpFakeBuffer.length = 0;
113
+ for (const { handler } of this.mounts) handler.clearMcpFakes?.();
114
+ }
115
+ /**
43
116
  * Add fixtures from a JSON string or pre-parsed array of fixture entries.
44
117
  * Validates all fixtures and throws if any have severity "error".
45
118
  */
@@ -51,23 +124,31 @@ var LLMock = class LLMock {
51
124
  throw new Error(`addFixturesFromJSON: invalid JSON — ${err instanceof Error ? err.message : String(err)}`);
52
125
  }
53
126
  else entries = input;
54
- const converted = entries.map((e) => entryToFixture(e));
55
- const errors = validateFixtures(converted).filter((i) => i.severity === "error");
127
+ if (!Array.isArray(entries)) throw new TypeError("addFixturesFromJSON: expected an array of fixture entries; use loadFixtureFile for a {fixtures:[...]} file");
128
+ const converted = entries.map((e) => entryToFixture(e, void 0, this.options.live));
129
+ const errors = validateFixtures(converted, this.options.live).filter((i) => i.severity === "error");
56
130
  if (errors.length > 0) throw new Error(`Fixture validation failed: ${JSON.stringify(errors)}`);
57
131
  this.fixtures.push(...converted);
58
132
  return this;
59
133
  }
60
134
  clearFixtures() {
61
- this.fixtures.length = 0;
135
+ clearFixtureQueue(this.fixtures);
136
+ this.unloadMcpFakes();
62
137
  return this;
63
138
  }
64
139
  on(match, response, opts) {
65
140
  return this.addFixture({
66
141
  match,
67
- response: typeof response === "function" ? response : normalizeResponse(response),
142
+ response: typeof response === "function" ? response : normalizeResponse(response, this.options.live),
68
143
  ...opts
69
144
  });
70
145
  }
146
+ onLive(match, transcript, opts) {
147
+ return this.on({
148
+ ...match,
149
+ endpoint: "openai-live"
150
+ }, { live: transcript }, opts);
151
+ }
71
152
  onMessage(pattern, response, opts) {
72
153
  return this.on({ userMessage: pattern }, response, opts);
73
154
  }
@@ -165,6 +246,15 @@ var LLMock = class LLMock {
165
246
  response
166
247
  });
167
248
  }
249
+ onElevenLabsVoiceDesign(description, response) {
250
+ return this.addFixture({
251
+ match: {
252
+ userMessage: description,
253
+ endpoint: "elevenlabs-voice-design"
254
+ },
255
+ response: voiceDesignToJson(response)
256
+ });
257
+ }
168
258
  onFalAudio(prompt, response, model) {
169
259
  return this.addFixture({
170
260
  match: {
@@ -233,41 +323,16 @@ var LLMock = class LLMock {
233
323
  /**
234
324
  * Queue a one-shot error that will be returned for the next matching
235
325
  * request, then automatically removed. Implemented as an internal fixture
236
- * with a `predicate` that always matches (so it fires first) and spliced
237
- * at the front of the fixture list.
326
+ * inserted at the front of the fixture list; see `queueOneShotError` for
327
+ * the endpoint gate and the served-not-evaluated consumption rule.
238
328
  */
239
329
  nextRequestError(status, errorBody) {
240
330
  if (!isInjectableStatus(status)) throw new RangeError(`nextRequestError: invalid status ${String(status)} — must be ${INJECTED_STATUS_RANGE}`);
241
- const errorResponse = {
242
- error: {
243
- message: errorBody?.message ?? "Injected error",
244
- type: errorBody?.type ?? "server_error",
245
- code: errorBody?.code
246
- },
247
- status
248
- };
249
- const errorEndpointCompatible = (req) => {
250
- const reqEndpoint = req._endpointType;
251
- if (reqEndpoint === void 0 || reqEndpoint === "chat" || reqEndpoint === "embedding" || reqEndpoint.startsWith("realtime") || reqEndpoint === "fal") return true;
252
- return false;
253
- };
254
- const fixture = {
255
- match: { predicate: errorEndpointCompatible },
256
- response: errorResponse
257
- };
258
- this.fixtures.unshift(fixture);
259
- const original = fixture.match.predicate;
260
- fixture.match.predicate = (req) => {
261
- const result = original(req);
262
- if (result) {
263
- const idx = this.fixtures.indexOf(fixture);
264
- if (idx !== -1) this.fixtures.splice(idx, 1);
265
- }
266
- return result;
267
- };
331
+ queueOneShotError(this.fixtures, status, errorBody);
268
332
  return this;
269
333
  }
270
334
  mount(path, handler) {
335
+ const shadowedBy = this.serverInstance ? this.mounts.find((m) => isAutoMount(m.handler) && (path === m.path || path === m.path + "/")) : void 0;
271
336
  this.mounts.push({
272
337
  path,
273
338
  handler
@@ -277,6 +342,9 @@ var LLMock = class LLMock {
277
342
  if (handler.setBaseUrl) handler.setBaseUrl(this.serverInstance.url + path);
278
343
  const registry = this.serverInstance.defaults.registry;
279
344
  if (registry && handler.setRegistry) handler.setRegistry(registry);
345
+ const logger = this.serverInstance.defaults.logger;
346
+ if (handler.setLogger) handler.setLogger(logger);
347
+ if (shadowedBy) logger.warn(build(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`));
280
348
  }
281
349
  return this;
282
350
  }
@@ -286,11 +354,20 @@ var LLMock = class LLMock {
286
354
  getLastRequest() {
287
355
  return this.journal.getLast();
288
356
  }
357
+ /**
358
+ * Clear the request journal. Fixture match-counts (sequencing state) are
359
+ * left intact — use `resetMatchCounts()` for those.
360
+ */
289
361
  clearRequests() {
290
- this.journal.clear();
362
+ this.journal.clearEntries();
291
363
  }
364
+ /**
365
+ * Reset fixture match counts, and the MCP fakes consumption state of every
366
+ * mount (R6), for `testId` or for all test ids. Fakes stay loaded.
367
+ */
292
368
  resetMatchCounts(testId) {
293
369
  if (this.serverInstance) this.serverInstance.journal.clearMatchCounts(testId);
370
+ for (const { handler } of this.mounts) handler.resetScenarioState?.(testId);
294
371
  return this;
295
372
  }
296
373
  /**
@@ -335,8 +412,10 @@ var LLMock = class LLMock {
335
412
  * NOT ALL OF THIS IS PER-INSTANCE. `performFullReset` clears module-global
336
413
  * state as well: the Gemini interaction and event-id counters
337
414
  * (`resetInteractionCounter` / `resetEventIdCounter` in
338
- * `./gemini-interactions.js`) and the fal.ai job/queue maps (`falJobs`,
339
- * `falQueueStates`). With two `LLMock` instances live in one process,
415
+ * `./gemini-interactions.js`), the fal.ai job/queue maps (`falJobs`,
416
+ * `falQueueStates`), the fine-tuning job store (`clearFineTuningStore`),
417
+ * and the ElevenLabs Voice Design store (`clearElevenLabsVoices`). With two
418
+ * `LLMock` instances live in one process,
340
419
  * `a.reset()` rewinds the Gemini id sequence that `b` is mid-way through —
341
420
  * `b` then re-emits `aimock-int-0` / `evt_1`, ids it has already handed
342
421
  * out — and drops `b`'s in-flight fal jobs. Give each instance its own
@@ -349,22 +428,26 @@ var LLMock = class LLMock {
349
428
  this.searchFixtures.length = 0;
350
429
  this.rerankFixtures.length = 0;
351
430
  this.moderationFixtures.length = 0;
431
+ this.unloadMcpFakes();
352
432
  performFullReset(this.fixtures, this.serverInstance);
353
433
  return this;
354
434
  }
355
435
  async start() {
356
436
  if (this.serverInstance) throw new Error("Server already started");
357
- this.serverInstance = await (this.resolvedInboundAuth ? createServerWithResolvedAuth(this.fixtures, this.options, this.resolvedInboundAuth, this.mounts, {
437
+ const serviceFixtures = {
358
438
  search: this.searchFixtures,
359
439
  rerank: this.rerankFixtures,
360
- moderation: this.moderationFixtures
361
- }) : createServer(this.fixtures, this.options, this.mounts, {
362
- search: this.searchFixtures,
363
- rerank: this.rerankFixtures,
364
- moderation: this.moderationFixtures
365
- }));
440
+ moderation: this.moderationFixtures,
441
+ mcpFakes: [...this.mcpFakeBuffer]
442
+ };
443
+ this.serverInstance = await (this.resolvedInboundAuth ? createServerWithResolvedAuth(this.fixtures, this.options, this.resolvedInboundAuth, this.mounts, serviceFixtures) : createServer(this.fixtures, this.options, this.mounts, serviceFixtures));
444
+ this.mcpFakeBuffer.length = 0;
366
445
  return this.serverInstance.url;
367
446
  }
447
+ closeLiveSessions(testId) {
448
+ this.serverInstance?.closeLiveSessions(testId);
449
+ return this;
450
+ }
368
451
  async stop() {
369
452
  if (!this.serverInstance) throw new Error("Server not started");
370
453
  const { server } = this.serverInstance;
@@ -1 +1 @@
1
- {"version":3,"file":"llmock.js","names":[],"sources":["../src/llmock.ts"],"sourcesContent":["import type {\n AudioResponse,\n ChaosConfig,\n EmbeddingFixtureOpts,\n FalQueueOpts,\n Fixture,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureMatch,\n FixtureOpts,\n FixtureResponse,\n ImageResponse,\n MockServerOptions,\n Mountable,\n RecordConfig,\n ResponseFactory,\n TranscriptionResponse,\n VideoResponse,\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 loadFixtureFile,\n loadFixturesFromDir,\n entryToFixture,\n normalizeResponse,\n validateFixtures,\n} from \"./fixture-loader.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\";\n\nexport class LLMock {\n private fixtures: Fixture[] = [];\n private searchFixtures: SearchFixture[] = [];\n private rerankFixtures: RerankFixture[] = [];\n private moderationFixtures: ModerationFixture[] = [];\n private mounts: Array<{ path: string; handler: Mountable }> = [];\n private serverInstance: ServerInstance | null = null;\n private options: MockServerOptions;\n private readonly resolvedInboundAuth?: ResolvedInboundAuth;\n\n constructor(options?: MockServerOptions, resolvedInboundAuth?: ResolvedInboundAuth) {\n this.options = options ?? {};\n this.resolvedInboundAuth = resolvedInboundAuth;\n }\n\n // ---- Fixture management ----\n\n addFixture(fixture: Fixture): this {\n this.fixtures.push(fixture);\n return this;\n }\n\n addFixtures(fixtures: Fixture[]): this {\n this.fixtures.push(...fixtures);\n return this;\n }\n\n prependFixture(fixture: Fixture): this {\n this.fixtures.unshift(fixture);\n return this;\n }\n\n getFixtures(): readonly Fixture[] {\n return this.fixtures;\n }\n\n loadFixtureFile(filePath: string): this {\n this.fixtures.push(...loadFixtureFile(filePath));\n return this;\n }\n\n loadFixtureDir(dirPath: string): this {\n this.fixtures.push(...loadFixturesFromDir(dirPath));\n return this;\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 const converted = entries.map((e) => entryToFixture(e));\n const issues = validateFixtures(converted);\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 // Uses length = 0 to preserve array reference identity — the running\n // server reads this same array on every request.\n clearFixtures(): this {\n this.fixtures.length = 0;\n return this;\n }\n\n // ---- Convenience ----\n\n on(\n match: FixtureMatch,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.addFixture({\n match,\n response: typeof response === \"function\" ? response : normalizeResponse(response),\n ...opts,\n });\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 match: { userMessage: prompt, endpoint: \"image\" },\n response,\n });\n }\n\n onSpeech(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: input, endpoint: \"speech\" },\n response,\n });\n }\n\n onTranscription(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"transcription\" },\n response,\n });\n }\n\n onTranslation(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"translation\" },\n response,\n });\n }\n\n onVideo(prompt: string | RegExp, response: VideoResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"video\" },\n response,\n });\n }\n\n onAudio(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({ match: { userMessage: input }, response });\n }\n\n onSoundEffect(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onMusic(prompt: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"elevenlabs-tts\" },\n response,\n });\n }\n\n onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"fal-audio\", ...(model ? { model } : {}) },\n response,\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 match: { model: modelOrPrompt, endpoint: \"fal\" },\n response: { json: response, ...(billableUnits != null ? { billableUnits } : {}) },\n ...fixtureOpts,\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 * with a `predicate` that always matches (so it fires first) and spliced\n * at the front of the fixture list.\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 const errorResponse: FixtureResponse = {\n error: {\n message: errorBody?.message ?? \"Injected error\",\n type: errorBody?.type ?? \"server_error\",\n code: errorBody?.code,\n },\n status,\n };\n // An injected error is only a valid response for endpoints that can carry\n // an error envelope. Mirror the router's endpoint-compat table\n // (matchFixtureDiagnostic in router.ts): error responses are compatible\n // with chat / embedding / realtime* / fal and with requests that carry no\n // endpoint type, but NOT with multimedia endpoints (image, speech, video,\n // transcription, …). Gating consumption on this prevents an incompatible\n // request from matching the predicate and splicing — and thereby\n // destroying — a one-shot error intended for a different endpoint before\n // the router's own compat check would have skipped it.\n const errorEndpointCompatible = (req: import(\"./types.js\").ChatCompletionRequest) => {\n const reqEndpoint = req._endpointType as string | undefined;\n if (\n reqEndpoint === undefined ||\n reqEndpoint === \"chat\" ||\n reqEndpoint === \"embedding\" ||\n reqEndpoint.startsWith(\"realtime\") ||\n reqEndpoint === \"fal\"\n ) {\n return true;\n }\n return false;\n };\n const fixture: Fixture = {\n match: { predicate: errorEndpointCompatible },\n response: errorResponse,\n };\n // Insert at front so it matches before everything else\n this.fixtures.unshift(fixture);\n // Remove after first match — the journal records it so tests can assert.\n // Only consume (and splice) when the request endpoint is compatible; an\n // incompatible request returns false here, falls through to other\n // fixtures, and leaves this error pending for its intended endpoint.\n const original = fixture.match.predicate!;\n fixture.match.predicate = (req) => {\n const result = original(req);\n if (result) {\n // Remove synchronously on first match to prevent race conditions\n const idx = this.fixtures.indexOf(fixture);\n if (idx !== -1) this.fixtures.splice(idx, 1);\n }\n return result;\n };\n return this;\n }\n\n // ---- Mounts ----\n\n mount(path: string, handler: Mountable): this {\n this.mounts.push({ path, handler });\n\n // If server is already running, wire up journal, registry, and baseUrl immediately\n // 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 }\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 clearRequests(): void {\n this.journal.clear();\n }\n\n resetMatchCounts(testId?: string): this {\n if (this.serverInstance) {\n this.serverInstance.journal.clearMatchCounts(testId);\n }\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 // ---- 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`) and the fal.ai job/queue maps (`falJobs`,\n * `falQueueStates`). With two `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 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 this.serverInstance = await (this.resolvedInboundAuth\n ? createServerWithResolvedAuth(\n this.fixtures,\n this.options,\n this.resolvedInboundAuth,\n this.mounts,\n {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n },\n )\n : createServer(this.fixtures, this.options, this.mounts, {\n search: this.searchFixtures,\n rerank: this.rerankFixtures,\n moderation: this.moderationFixtures,\n }));\n return this.serverInstance.url;\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 } from \"./helpers.js\";\nimport type {\n AudioResponse,\n ChaosConfig,\n EmbeddingFixtureOpts,\n FalQueueOpts,\n Fixture,\n FixtureFileEntry,\n FixtureFileResponse,\n FixtureMatch,\n FixtureOpts,\n ImageResponse,\n McpFakeSource,\n MockServerOptions,\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 validateFixtures,\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 { build, msg, quote } from \"./message-text.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\nexport class LLMock {\n private fixtures: 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 this.options = options ?? {};\n if (this.options.live !== undefined) normalizeLiveOptions(this.options.live);\n this.resolvedInboundAuth = resolvedInboundAuth;\n }\n\n // ---- Fixture management ----\n\n private normalizeFixture(fixture: Fixture): Fixture {\n if (\n isLiveResponse(fixture.response) ||\n (fixture.match.endpoint === \"openai-live\" && typeof fixture.response !== \"function\")\n ) {\n return {\n ...fixture,\n match: { ...fixture.match },\n response: normalizeLiveFixture(fixture.response, this.options.live),\n };\n }\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 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 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 },\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((e) => entryToFixture(e, undefined, this.options.live));\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.unloadMcpFakes();\n return this;\n }\n\n // ---- Convenience ----\n\n on(\n match: FixtureMatch,\n response: FixtureFileResponse | ResponseFactory,\n opts?: FixtureOpts,\n ): this {\n return this.addFixture({\n match,\n response:\n typeof response === \"function\" ? response : normalizeResponse(response, this.options.live),\n ...opts,\n });\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 match: { userMessage: prompt, endpoint: \"image\" },\n response,\n });\n }\n\n onSpeech(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: input, endpoint: \"speech\" },\n response,\n });\n }\n\n onTranscription(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"transcription\" },\n response,\n });\n }\n\n onTranslation(response: TranscriptionResponse): this {\n return this.addFixture({\n match: { endpoint: \"translation\" },\n response,\n });\n }\n\n onVideo(prompt: string | RegExp, response: VideoResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"video\" },\n response,\n });\n }\n\n onAudio(input: string | RegExp, response: AudioResponse): this {\n return this.addFixture({ match: { userMessage: input }, response });\n }\n\n onSoundEffect(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onMusic(prompt: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"audio-gen\" },\n response,\n });\n }\n\n onElevenLabsTTS(text: string | RegExp, response: AudioResponse): this {\n return this.addFixture({\n match: { userMessage: text, endpoint: \"elevenlabs-tts\" },\n response,\n });\n }\n\n onElevenLabsVoiceDesign(description: string | RegExp, response: VoiceDesignResponse): this {\n return this.addFixture({\n match: { userMessage: description, endpoint: \"elevenlabs-voice-design\" },\n response: voiceDesignToJson(response),\n });\n }\n\n onFalAudio(prompt: string | RegExp, response: AudioResponse, model?: string): this {\n return this.addFixture({\n match: { userMessage: prompt, endpoint: \"fal-audio\", ...(model ? { model } : {}) },\n response,\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 match: { model: modelOrPrompt, endpoint: \"fal\" },\n response: { json: response, ...(billableUnits != null ? { billableUnits } : {}) },\n ...fixtureOpts,\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 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 // ---- 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 // 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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"}