@copilotkit/aimock 1.44.0 → 1.45.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 (272) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +31 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +312 -39
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +313 -40
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +1 -0
  25. package/dist/chaos.js +1 -1
  26. package/dist/cli.cjs +152 -5
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +155 -8
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +132 -71
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +133 -72
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.cjs +62 -4
  37. package/dist/config-loader.cjs.map +1 -1
  38. package/dist/config-loader.d.cts +37 -4
  39. package/dist/config-loader.d.cts.map +1 -1
  40. package/dist/config-loader.d.ts +37 -4
  41. package/dist/config-loader.d.ts.map +1 -1
  42. package/dist/config-loader.js +62 -4
  43. package/dist/config-loader.js.map +1 -1
  44. package/dist/fakes-plugin.cjs +131 -0
  45. package/dist/fakes-plugin.cjs.map +1 -0
  46. package/dist/fakes-plugin.d.cts +23 -0
  47. package/dist/fakes-plugin.d.cts.map +1 -0
  48. package/dist/fakes-plugin.d.ts +23 -0
  49. package/dist/fakes-plugin.d.ts.map +1 -0
  50. package/dist/fakes-plugin.js +127 -0
  51. package/dist/fakes-plugin.js.map +1 -0
  52. package/dist/fixture-loader-services.cjs +1 -1
  53. package/dist/fixture-loader-services.cjs.map +1 -1
  54. package/dist/fixture-loader-services.js +1 -1
  55. package/dist/fixture-loader-services.js.map +1 -1
  56. package/dist/fixture-loader.cjs +389 -27
  57. package/dist/fixture-loader.cjs.map +1 -1
  58. package/dist/fixture-loader.d.cts +47 -3
  59. package/dist/fixture-loader.d.cts.map +1 -1
  60. package/dist/fixture-loader.d.ts +47 -3
  61. package/dist/fixture-loader.d.ts.map +1 -1
  62. package/dist/fixture-loader.js +384 -29
  63. package/dist/fixture-loader.js.map +1 -1
  64. package/dist/gemini-interactions.cjs +250 -52
  65. package/dist/gemini-interactions.cjs.map +1 -1
  66. package/dist/gemini-interactions.d.cts.map +1 -1
  67. package/dist/gemini-interactions.d.ts.map +1 -1
  68. package/dist/gemini-interactions.js +251 -53
  69. package/dist/gemini-interactions.js.map +1 -1
  70. package/dist/gemini.cjs +226 -37
  71. package/dist/gemini.cjs.map +1 -1
  72. package/dist/gemini.d.cts.map +1 -1
  73. package/dist/gemini.d.ts.map +1 -1
  74. package/dist/gemini.js +227 -38
  75. package/dist/gemini.js.map +1 -1
  76. package/dist/helpers.cjs +881 -7
  77. package/dist/helpers.cjs.map +1 -1
  78. package/dist/helpers.d.cts +85 -4
  79. package/dist/helpers.d.cts.map +1 -1
  80. package/dist/helpers.d.ts +85 -4
  81. package/dist/helpers.d.ts.map +1 -1
  82. package/dist/helpers.js +839 -8
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/index.cjs +9 -0
  85. package/dist/index.d.cts +7 -5
  86. package/dist/index.d.ts +7 -5
  87. package/dist/index.js +4 -3
  88. package/dist/jest.cjs +31 -7
  89. package/dist/jest.cjs.map +1 -1
  90. package/dist/jest.d.cts +43 -3
  91. package/dist/jest.d.cts.map +1 -1
  92. package/dist/jest.d.ts +43 -3
  93. package/dist/jest.d.ts.map +1 -1
  94. package/dist/jest.js +33 -9
  95. package/dist/jest.js.map +1 -1
  96. package/dist/journal.cjs +135 -13
  97. package/dist/journal.cjs.map +1 -1
  98. package/dist/journal.d.cts +38 -4
  99. package/dist/journal.d.cts.map +1 -1
  100. package/dist/journal.d.ts +38 -4
  101. package/dist/journal.d.ts.map +1 -1
  102. package/dist/journal.js +135 -13
  103. package/dist/journal.js.map +1 -1
  104. package/dist/live-sanitize.cjs +4 -32
  105. package/dist/live-sanitize.cjs.map +1 -1
  106. package/dist/live-sanitize.js +4 -32
  107. package/dist/live-sanitize.js.map +1 -1
  108. package/dist/llmock.cjs +123 -30
  109. package/dist/llmock.cjs.map +1 -1
  110. package/dist/llmock.d.cts +16 -1
  111. package/dist/llmock.d.cts.map +1 -1
  112. package/dist/llmock.d.ts +16 -1
  113. package/dist/llmock.d.ts.map +1 -1
  114. package/dist/llmock.js +125 -32
  115. package/dist/llmock.js.map +1 -1
  116. package/dist/mcp-fakes-mount.cjs +1 -0
  117. package/dist/mcp-fakes-mount.cjs.map +1 -1
  118. package/dist/mcp-fakes-mount.js +1 -0
  119. package/dist/mcp-fakes-mount.js.map +1 -1
  120. package/dist/mcp-fakes-report.cjs +111 -0
  121. package/dist/mcp-fakes-report.cjs.map +1 -0
  122. package/dist/mcp-fakes-report.d.cts +40 -0
  123. package/dist/mcp-fakes-report.d.cts.map +1 -0
  124. package/dist/mcp-fakes-report.d.ts +40 -0
  125. package/dist/mcp-fakes-report.d.ts.map +1 -0
  126. package/dist/mcp-fakes-report.js +107 -0
  127. package/dist/mcp-fakes-report.js.map +1 -0
  128. package/dist/mcp-fakes.cjs +331 -8
  129. package/dist/mcp-fakes.cjs.map +1 -1
  130. package/dist/mcp-fakes.d.cts +406 -3
  131. package/dist/mcp-fakes.d.cts.map +1 -1
  132. package/dist/mcp-fakes.d.ts +406 -3
  133. package/dist/mcp-fakes.d.ts.map +1 -1
  134. package/dist/mcp-fakes.js +331 -8
  135. package/dist/mcp-fakes.js.map +1 -1
  136. package/dist/mcp-handler.cjs +209 -16
  137. package/dist/mcp-handler.cjs.map +1 -1
  138. package/dist/mcp-handler.d.cts +49 -0
  139. package/dist/mcp-handler.d.cts.map +1 -0
  140. package/dist/mcp-handler.d.ts +49 -0
  141. package/dist/mcp-handler.d.ts.map +1 -0
  142. package/dist/mcp-handler.js +207 -17
  143. package/dist/mcp-handler.js.map +1 -1
  144. package/dist/mcp-mock.cjs +112 -1
  145. package/dist/mcp-mock.cjs.map +1 -1
  146. package/dist/mcp-mock.d.cts +33 -2
  147. package/dist/mcp-mock.d.cts.map +1 -1
  148. package/dist/mcp-mock.d.ts +33 -2
  149. package/dist/mcp-mock.d.ts.map +1 -1
  150. package/dist/mcp-mock.js +112 -1
  151. package/dist/mcp-mock.js.map +1 -1
  152. package/dist/mcp-recorder.cjs +1224 -0
  153. package/dist/mcp-recorder.cjs.map +1 -0
  154. package/dist/mcp-recorder.d.cts +108 -0
  155. package/dist/mcp-recorder.d.cts.map +1 -0
  156. package/dist/mcp-recorder.d.ts +108 -0
  157. package/dist/mcp-recorder.d.ts.map +1 -0
  158. package/dist/mcp-recorder.js +1215 -0
  159. package/dist/mcp-recorder.js.map +1 -0
  160. package/dist/messages.cjs +362 -56
  161. package/dist/messages.cjs.map +1 -1
  162. package/dist/messages.d.cts.map +1 -1
  163. package/dist/messages.d.ts.map +1 -1
  164. package/dist/messages.js +363 -58
  165. package/dist/messages.js.map +1 -1
  166. package/dist/misbehavior.cjs +1523 -0
  167. package/dist/misbehavior.cjs.map +1 -0
  168. package/dist/misbehavior.d.cts +43 -0
  169. package/dist/misbehavior.d.cts.map +1 -0
  170. package/dist/misbehavior.d.ts +43 -0
  171. package/dist/misbehavior.d.ts.map +1 -0
  172. package/dist/misbehavior.js +1511 -0
  173. package/dist/misbehavior.js.map +1 -0
  174. package/dist/ollama.cjs +310 -112
  175. package/dist/ollama.cjs.map +1 -1
  176. package/dist/ollama.d.cts.map +1 -1
  177. package/dist/ollama.d.ts.map +1 -1
  178. package/dist/ollama.js +311 -113
  179. package/dist/ollama.js.map +1 -1
  180. package/dist/record-sanitize.cjs +231 -0
  181. package/dist/record-sanitize.cjs.map +1 -0
  182. package/dist/record-sanitize.js +224 -0
  183. package/dist/record-sanitize.js.map +1 -0
  184. package/dist/recorder.cjs +106 -5
  185. package/dist/recorder.cjs.map +1 -1
  186. package/dist/recorder.d.cts +2 -1
  187. package/dist/recorder.d.cts.map +1 -1
  188. package/dist/recorder.d.ts +2 -1
  189. package/dist/recorder.d.ts.map +1 -1
  190. package/dist/recorder.js +107 -7
  191. package/dist/recorder.js.map +1 -1
  192. package/dist/responses.cjs +667 -171
  193. package/dist/responses.cjs.map +1 -1
  194. package/dist/responses.d.cts +5 -13
  195. package/dist/responses.d.cts.map +1 -1
  196. package/dist/responses.d.ts +5 -13
  197. package/dist/responses.d.ts.map +1 -1
  198. package/dist/responses.js +665 -174
  199. package/dist/responses.js.map +1 -1
  200. package/dist/router.cjs +24 -2
  201. package/dist/router.cjs.map +1 -1
  202. package/dist/router.d.cts.map +1 -1
  203. package/dist/router.d.ts.map +1 -1
  204. package/dist/router.js +25 -4
  205. package/dist/router.js.map +1 -1
  206. package/dist/server.cjs +572 -76
  207. package/dist/server.cjs.map +1 -1
  208. package/dist/server.d.cts.map +1 -1
  209. package/dist/server.d.ts.map +1 -1
  210. package/dist/server.js +574 -78
  211. package/dist/server.js.map +1 -1
  212. package/dist/stream-collapse.cjs +236 -34
  213. package/dist/stream-collapse.cjs.map +1 -1
  214. package/dist/stream-collapse.d.cts +39 -4
  215. package/dist/stream-collapse.d.cts.map +1 -1
  216. package/dist/stream-collapse.d.ts +39 -4
  217. package/dist/stream-collapse.d.ts.map +1 -1
  218. package/dist/stream-collapse.js +235 -35
  219. package/dist/stream-collapse.js.map +1 -1
  220. package/dist/types.cjs.map +1 -1
  221. package/dist/types.d.cts +315 -4
  222. package/dist/types.d.cts.map +1 -1
  223. package/dist/types.d.ts +315 -4
  224. package/dist/types.d.ts.map +1 -1
  225. package/dist/types.js.map +1 -1
  226. package/dist/validate-cli.cjs +36 -4
  227. package/dist/validate-cli.cjs.map +1 -1
  228. package/dist/validate-cli.js +37 -5
  229. package/dist/validate-cli.js.map +1 -1
  230. package/dist/vector-types.d.ts.map +1 -1
  231. package/dist/version.cjs +45 -0
  232. package/dist/version.cjs.map +1 -0
  233. package/dist/version.js +44 -0
  234. package/dist/version.js.map +1 -0
  235. package/dist/vitest.cjs +66 -10
  236. package/dist/vitest.cjs.map +1 -1
  237. package/dist/vitest.d.cts +35 -4
  238. package/dist/vitest.d.cts.map +1 -1
  239. package/dist/vitest.d.ts +35 -4
  240. package/dist/vitest.d.ts.map +1 -1
  241. package/dist/vitest.js +67 -11
  242. package/dist/vitest.js.map +1 -1
  243. package/dist/watcher.cjs +6 -2
  244. package/dist/watcher.cjs.map +1 -1
  245. package/dist/watcher.js +6 -2
  246. package/dist/watcher.js.map +1 -1
  247. package/dist/ws-gemini-live.cjs +210 -101
  248. package/dist/ws-gemini-live.cjs.map +1 -1
  249. package/dist/ws-gemini-live.d.cts +9 -3
  250. package/dist/ws-gemini-live.d.cts.map +1 -1
  251. package/dist/ws-gemini-live.d.ts +9 -3
  252. package/dist/ws-gemini-live.d.ts.map +1 -1
  253. package/dist/ws-gemini-live.js +211 -102
  254. package/dist/ws-gemini-live.js.map +1 -1
  255. package/dist/ws-realtime.cjs +175 -62
  256. package/dist/ws-realtime.cjs.map +1 -1
  257. package/dist/ws-realtime.d.cts +8 -3
  258. package/dist/ws-realtime.d.cts.map +1 -1
  259. package/dist/ws-realtime.d.ts +8 -3
  260. package/dist/ws-realtime.d.ts.map +1 -1
  261. package/dist/ws-realtime.js +176 -63
  262. package/dist/ws-realtime.js.map +1 -1
  263. package/dist/ws-responses.cjs +109 -16
  264. package/dist/ws-responses.cjs.map +1 -1
  265. package/dist/ws-responses.d.cts +8 -12
  266. package/dist/ws-responses.d.cts.map +1 -1
  267. package/dist/ws-responses.d.ts +8 -12
  268. package/dist/ws-responses.d.ts.map +1 -1
  269. package/dist/ws-responses.js +111 -18
  270. package/dist/ws-responses.js.map +1 -1
  271. package/package.json +10 -2
  272. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":["http"],"sources":["../src/server.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n Fixture,\n FixtureFileEntry,\n ChatCompletionRequest,\n ChaosConfig,\n ChaosDefaults,\n HandlerDefaults,\n JournalEntry,\n MockServerOptions,\n Mountable,\n RecordProviderKey,\n} from \"./types.js\";\nimport { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport {\n validateFixtures,\n entryToFixture,\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n queueOneShotError,\n isOneShotError,\n claimOneShotError,\n clearFixtureQueue,\n releaseOneShotError,\n FixtureLoadError,\n} from \"./fixture-loader.js\";\nimport { writeSSEStream, writeErrorResponse } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport {\n buildTextChunks,\n buildToolCallChunks,\n buildTextCompletion,\n buildToolCallCompletion,\n buildContentWithToolCallsChunks,\n buildContentWithToolCallsCompletion,\n buildUsageChunk,\n resolveUsage,\n resolveFixtureBlockOutcome,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n serializeErrorResponse,\n isAudioResponse,\n isResponseFactory,\n isVideoResponse,\n isTranscriptionResponse,\n isImageResponse,\n isEmbeddingResponse,\n isJSONResponse,\n flattenHeaders,\n isJsonObject,\n validateToolsField,\n getTestId,\n resolveTestId,\n readBody,\n readBodyBufferBounded,\n RequestBodyTooLargeError,\n resolveRequestId,\n markMintedRequestId,\n resolveResponse,\n resolveStrictMode,\n wouldProxyMiss,\n resolveReasoningForModel,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n getContext,\n describeMatch,\n} from \"./helpers.js\";\nimport { DEFAULT_TEST_ID } from \"./constants.js\";\nimport {\n isOpenRouterPath,\n buildOpenRouterCandidates,\n resolveOpenRouterShaping,\n shapeOpenRouterCompletion,\n shapeOpenRouterChunks,\n serializeOpenRouterError,\n handleOpenRouterModels,\n handleOpenRouterKey,\n handleOpenRouterCredits,\n} from \"./openrouter-chat.js\";\nimport type {\n FixtureResponse,\n ErrorResponse,\n ChatCompletion,\n SSEChunk,\n ResponseOverrides,\n} from \"./types.js\";\nimport { handleResponses } from \"./responses.js\";\nimport { handleMessages } from \"./messages.js\";\nimport { handleGemini } from \"./gemini.js\";\nimport { handleGeminiEmbedContent } from \"./gemini-embeddings.js\";\nimport { handleBedrock, handleBedrockStream } from \"./bedrock.js\";\nimport { handleConverse, handleConverseStream } from \"./bedrock-converse.js\";\nimport {\n handleGeminiInteractions,\n resetInteractionCounter,\n resetEventIdCounter,\n} from \"./gemini-interactions.js\";\nimport { handleEmbeddings } from \"./embeddings.js\";\nimport { handleImages, handleImageEdit, handleImageVariations } from \"./images.js\";\nimport { handleSpeech } from \"./speech.js\";\nimport { handleTranscription } from \"./transcription.js\";\nimport { handleVideoCreate, VideoStateMap } from \"./video.js\";\nimport {\n handleOpenRouterVideoCreate,\n handleOpenRouterVideoStatus,\n handleOpenRouterVideoContent,\n handleOpenRouterVideoModels,\n OpenRouterVideoJobMap,\n OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES,\n} from \"./openrouter-video.js\";\nimport { handleVeoVideoCreate, handleVeoVideoStatus, VeoVideoJobMap } from \"./veo-video.js\";\nimport { handleGrokVideoCreate, handleGrokVideoStatus, GrokVideoJobMap } from \"./grok-video.js\";\nimport {\n handleBytePlusVideoCreate,\n handleBytePlusVideoStatus,\n BytePlusVideoJobMap,\n} from \"./byteplus-video.js\";\nimport { handleElevenLabsAudio, handleElevenLabsTTS } from \"./elevenlabs-audio.js\";\nimport {\n handleElevenLabsVoiceDesign,\n handleElevenLabsVoiceCreate,\n handleElevenLabsVoiceGet,\n handleElevenLabsVoiceDelete,\n clearElevenLabsVoices,\n} from \"./elevenlabs-voice.js\";\nimport { handleFalQueue, falJobs } from \"./fal-audio.js\";\nimport { handleFal, falQueueStates, falWillHandle } from \"./fal.js\";\nimport { handleOllama, handleOllamaGenerate, handleOllamaEmbeddings } from \"./ollama.js\";\nimport { handleCohere, handleCohereEmbed } from \"./cohere.js\";\nimport { handleSearch, type SearchFixture } from \"./search.js\";\nimport { handleRerank, type RerankFixture } from \"./rerank.js\";\nimport { handleModeration, type ModerationFixture } from \"./moderation.js\";\nimport {\n handleBatchesCreate,\n handleBatchesList,\n handleBatchesRetrieve,\n handleBatchesCancel,\n clearBatchStore,\n} from \"./batches.js\";\nimport {\n handleFilesCreate,\n handleFilesList,\n handleFilesRetrieve,\n handleFilesContent,\n handleFilesDelete,\n clearFileStore,\n FILES_BODY_DRAIN_MAX_BYTES,\n FILES_BODY_MAX_BYTES,\n FILES_BODY_OVERSIZED,\n} from \"./files.js\";\nimport {\n handleFineTuningCreate,\n handleFineTuningList,\n handleFineTuningRetrieve,\n handleFineTuningCancel,\n handleFineTuningEvents,\n clearFineTuningStore,\n} from \"./fine-tuning.js\";\nimport {\n handleVectorStoresCreate,\n handleVectorStoresList,\n handleVectorStoresRetrieve,\n handleVectorStoresModify,\n handleVectorStoresDelete,\n handleVectorStoreFilesCreate,\n handleVectorStoreFilesList,\n handleVectorStoreFilesRetrieve,\n handleVectorStoreFilesDelete,\n handleVectorFileBatchesCreate,\n handleVectorFileBatchesRetrieve,\n handleVectorFileBatchesCancel,\n handleVectorFileBatchesFiles,\n handleVectorStoresSearch,\n clearVectorStoreStore,\n} from \"./vector-stores.js\";\nimport { upgradeToWebSocket, type WebSocketConnection } from \"./ws-framing.js\";\nimport { handleLiveSession } from \"./ws-live.js\";\nimport { normalizeLiveOptions } from \"./live-fixture.js\";\nimport { handleWebSocketResponses } from \"./ws-responses.js\";\nimport { handleWebSocketRealtime } from \"./ws-realtime.js\";\nimport { handleWebSocketGeminiLive } from \"./ws-gemini-live.js\";\nimport { Logger } from \"./logger.js\";\nimport {\n applyChaosAction,\n awaitChaosLatency,\n describeUnwritableReason,\n evaluateChaos,\n responseGoneReason,\n isChaosScope,\n resolveChaosConfig,\n resetChaosWarnings,\n parseChaosField,\n CHAOS_FIELDS,\n CHAOS_FIELD_NAMES,\n} from \"./chaos.js\";\nimport { buildOpenApiDocument, CATALOG_ROUTES } from \"./openapi.js\";\n// Route paths/patterns are the router's single source of truth — shared with\n// the machine-readable catalog (`route-registry.ts` → `openapi.ts`), so the\n// catalog cannot drift from the dispatcher. Every literal and pattern matched\n// below comes from this module: adding a surface means adding it there, and\n// `matchRouteDefinition` (used by the terminal-404 drift guard) resolves\n// against the same table the catalog is derived from.\nimport {\n BATCHES_PATH,\n BATCHES_ID_RE,\n BATCHES_CANCEL_RE,\n COMPLETIONS_PATH,\n RESPONSES_PATH,\n REALTIME_PATH,\n LIVE_PATH,\n GEMINI_LIVE_PATH,\n MESSAGES_PATH,\n EMBEDDINGS_PATH,\n COHERE_CHAT_PATH,\n COHERE_EMBED_PATH,\n SEARCH_PATH,\n RERANK_PATH,\n MODERATIONS_PATH,\n IMAGES_PATH,\n IMAGES_EDIT_PATH,\n IMAGES_VARIATIONS_PATH,\n SPEECH_PATH,\n TRANSCRIPTIONS_PATH,\n TRANSLATIONS_PATH,\n VIDEOS_PATH,\n GROK_VIDEO_SUBMIT_PATH,\n GROK_VIDEO_STATUS_RE,\n VEO_PREDICT_LRO_RE,\n VEO_OPERATION_RE,\n GEMINI_PREDICT_RE,\n ELEVENLABS_SOUND_GENERATION_PATH,\n ELEVENLABS_TTS_RE,\n ELEVENLABS_MUSIC_RE,\n ELEVENLABS_VOICE_DESIGN_PATH,\n ELEVENLABS_VOICE_CREATE_PATH,\n ELEVENLABS_VOICE_RE,\n FAL_QUEUE_SUBMIT_RE,\n FAL_QUEUE_REQUESTS_RE,\n FAL_RUN_RE,\n FAL_ROUTE_RE,\n GEMINI_INTERACTIONS_PATH,\n GEMINI_PATH_RE,\n GEMINI_EMBED_RE,\n AZURE_DEPLOYMENT_RE,\n BEDROCK_INVOKE_RE,\n BEDROCK_STREAM_RE,\n BEDROCK_CONVERSE_RE,\n BEDROCK_CONVERSE_STREAM_RE,\n VERTEX_AI_RE,\n OLLAMA_CHAT_PATH,\n OLLAMA_GENERATE_PATH,\n OLLAMA_EMBEDDINGS_PATH,\n OLLAMA_EMBED_PATH,\n OLLAMA_TAGS_PATH,\n OPENROUTER_VIDEOS_PATH,\n OPENROUTER_VIDEO_MODELS_PATH,\n OPENROUTER_MODELS_PATH,\n OPENROUTER_KEY_PATH,\n OPENROUTER_CREDITS_PATH,\n OPENROUTER_VIDEO_CONTENT_RE,\n OPENROUTER_VIDEO_STATUS_RE,\n HEALTH_PATH,\n READY_PATH,\n METRICS_PATH,\n MODELS_PATH,\n REQUESTS_PATH,\n FILES_PATH,\n FILES_ID_RE,\n FILES_CONTENT_RE,\n VECTOR_STORES_PATH,\n VECTOR_STORES_SEARCH_RE,\n VECTOR_STORES_BATCH_FILES_RE,\n VECTOR_STORES_BATCH_CANCEL_RE,\n VECTOR_STORES_BATCH_RE,\n VECTOR_STORES_FILE_RE,\n VECTOR_STORES_ID_RE,\n VECTOR_STORES_FILES_RE,\n VECTOR_STORES_FILE_BATCHES_RE,\n BYTEPLUS_VIDEO_SUBMIT_RE,\n BYTEPLUS_VIDEO_STATUS_RE,\n FINE_TUNING_JOBS_PATH,\n FINE_TUNING_ID_RE,\n FINE_TUNING_CANCEL_RE,\n FINE_TUNING_EVENTS_RE,\n CONTROL_PREFIX,\n matchRouteDefinition,\n} from \"./route-registry.js\";\nimport { createMetricsRegistry, normalizePathLabel, DESTROYED_STATUS_LABEL } from \"./metrics.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport {\n resolveInboundAuth,\n markAuthenticatedRequest,\n validateRequestApiKey,\n writeApiKeyHttpRejection,\n writeApiKeyUpgradeRejection,\n type ResolvedInboundAuth,\n} from \"./api-key-auth.js\";\nimport type { McpFakeSource } from \"./types.js\";\nimport {\n ensureFakeMount,\n findFakeMount,\n handOffMcpFakes,\n isFakeMount,\n mountConflictDetail,\n type MountList,\n} from \"./mcp-fakes-mount.js\";\nimport { MCP_FAKES_DEFAULT_MOUNT, McpFakeStore, McpFakesAddError, blockIdOf } from \"./mcp-fakes.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { build, msg, quote } from \"./message-text.js\";\n\nconst liveClosers = new WeakMap<HandlerDefaults, (testId?: string) => void>();\n\nexport interface ServerInstance {\n closeLiveSessions(testId?: string): void;\n server: http.Server;\n journal: Journal;\n url: string;\n defaults: HandlerDefaults;\n videoStates: VideoStateMap;\n openRouterVideoJobs: OpenRouterVideoJobMap;\n veoVideoJobs: VeoVideoJobMap;\n grokVideoJobs: GrokVideoJobMap;\n bytePlusVideoJobs: BytePlusVideoJobMap;\n}\n\nconst DEFAULT_CHUNK_SIZE = 20;\n\n// OpenAI-compatible endpoint suffixes for path prefix normalization.\n// Providers like BigModel (/v4/) use non-standard base URL prefixes.\n// Only includes endpoints that third-party OpenAI-compatible providers are\n// likely to serve — excludes provider-specific paths (/messages, /realtime)\n// and endpoints unlikely to appear behind non-standard prefixes\n// (/moderations, /videos, /models).\nconst COMPAT_SUFFIXES = [\n \"/chat/completions\",\n \"/embeddings\",\n \"/responses\",\n \"/audio/speech\",\n \"/audio/transcriptions\",\n \"/audio/translations\",\n \"/images/generations\",\n \"/images/edits\",\n \"/images/variations\",\n];\n\n/**\n * Normalize OpenAI-compatible paths with arbitrary prefixes.\n * Strips /openai/ prefix and rewrites paths ending in known suffixes to /v1/<suffix>.\n * Skips /v1/ (already standard) and /v2/ (Cohere convention).\n */\nfunction normalizeCompatPath(pathname: string, logger?: Logger): string {\n // Strip /openai/ prefix (Groq/OpenAI-compat alias)\n if (pathname.startsWith(\"/openai/\")) {\n pathname = pathname.slice(\"/openai\".length);\n }\n\n // Normalize arbitrary prefixes to /v1/\n if (!pathname.startsWith(\"/v1/\") && !pathname.startsWith(\"/v2/\")) {\n for (const suffix of COMPAT_SUFFIXES) {\n if (pathname.endsWith(suffix)) {\n if (logger) logger.debug(`Path normalized: ${pathname} → /v1${suffix}`);\n pathname = \"/v1\" + suffix;\n break;\n }\n }\n }\n\n return pathname;\n}\n\n// OpenRouter async video lifecycle (/api/v1/videos). Dispatch order matters:\n// content RE → models exact → status RE → submit exact. The status RE's\n// `[^/]+` segment would otherwise swallow the `models` listing path. The\n// content/status REs are shared with the route registry and metrics.ts\n// path-label normalization (imported above).\n\nconst DEFAULT_MODELS = [\n \"gpt-4\",\n \"gpt-4o\",\n \"claude-3-5-sonnet-20241022\",\n \"gemini-2.0-flash\",\n \"text-embedding-3-small\",\n];\n\nconst CORS_HEADERS: Record<string, string> = {\n \"Access-Control-Allow-Origin\": \"*\",\n // Every method the dispatcher serves: PUT is dispatched for\n // `/fal/queue/requests/{requestId}` (status/cancel/result), so a preflight\n // that omits it makes browsers refuse that call.\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"*\",\n // Response headers are invisible to cross-origin JS unless exposed. The\n // journal's pagination total is a response header (the body stays a bare\n // array for back-compat), so a browser harness needs this to read it.\n \"Access-Control-Expose-Headers\": \"X-Total-Count, X-Request-Id\",\n};\n\nfunction setCorsHeaders(res: http.ServerResponse): void {\n for (const [key, value] of Object.entries(CORS_HEADERS)) {\n res.setHeader(key, value);\n }\n}\n\nfunction handleOptions(res: http.ServerResponse): void {\n setCorsHeaders(res);\n res.writeHead(204);\n res.end();\n}\n\nfunction handleNotFound(res: http.ServerResponse, message: string): void {\n setCorsHeaders(res);\n writeErrorResponse(res, 404, JSON.stringify({ error: { message, type: \"not_found\" } }));\n}\n\n// ---------------------------------------------------------------------------\n// /__aimock/* control API — used by aimock-pytest and other test harnesses\n// to manage fixtures, journal, and error injection without restarting the\n// server.\n// ---------------------------------------------------------------------------\n\n/** The complete `GET /__aimock/fixtures` query-param vocabulary; anything else 400s. */\nconst FIXTURES_PARAMS: ReadonlySet<string> = new Set([\"include\"]);\n\n/** The complete `GET /__aimock/journal` query-param vocabulary; anything else 400s. */\nconst JOURNAL_PARAMS: ReadonlySet<string> = new Set([\n \"limit\",\n \"offset\",\n \"path\",\n \"method\",\n \"status\",\n \"service\",\n \"testId\",\n \"requestId\",\n]);\n\n/**\n * The per-server state a full reset clears. `ServerInstance` structurally\n * satisfies this, so `LLMock.reset()` and the control-API full-reset route\n * share a single definition of \"everything\" instead of two lists that drift.\n */\nexport interface FullResetTargets {\n journal: Journal;\n videoStates: VideoStateMap;\n openRouterVideoJobs: OpenRouterVideoJobMap;\n veoVideoJobs: VeoVideoJobMap;\n grokVideoJobs: GrokVideoJobMap;\n bytePlusVideoJobs: BytePlusVideoJobMap;\n defaults: HandlerDefaults;\n /**\n * The server's mounts. A full reset unloads every MCP fake on them (R1, R2);\n * the entry-id counters and MCP sessions are kept.\n */\n mounts?: MountList;\n}\n\n/**\n * Perform a full reset: clear the fixtures array, the journal (entries *and*\n * per-test fixture match-counts, i.e. sequence position), the video and fal.ai\n * job/queue state, the fine-tuning store (jobs, their append-only event logs,\n * their poll counts, the create-time suffixes their model names are built from,\n * and the module's monotonic clock), the ElevenLabs Voice Design store, the\n * Gemini interaction/event-id counters, and any runtime chaos override\n * (reverting to the construction-time chaos config), then re-zero the\n * `aimock_fixtures_loaded` gauge.\n *\n * `targets` is `null` when no server is running (an in-process `reset()` before\n * `start()`). The process-global generation state is reset either way, since it\n * is not owned by any one server instance.\n *\n * Shared by `POST /__aimock/reset` (canonical), its deprecated\n * `POST /__aimock/reset/fixtures` alias, and `LLMock.reset()`.\n */\nexport function performFullReset(fixtures: Fixture[], targets: FullResetTargets | null): void {\n // Also invalidates one-shot claims parked in flight (see `clearFixtureQueue`).\n clearFixtureQueue(fixtures);\n falJobs.clear();\n falQueueStates.clear();\n clearBatchStore();\n clearElevenLabsVoices();\n clearFileStore();\n clearFineTuningStore();\n clearVectorStoreStore();\n resetInteractionCounter();\n resetEventIdCounter();\n if (!targets) return;\n liveClosers.get(targets.defaults)?.();\n targets.journal.clear();\n // Chaos warning latches are per-server state too: a suite that resets between\n // tests must see a bad static chaos value reported again, not inherit the\n // latch the previous test left armed. Scoped by the server's logger, so this\n // clears THIS server's latch and cannot re-arm a concurrent server's.\n resetChaosWarnings(targets.defaults.logger);\n // Drop any runtime chaos override installed via POST /__aimock/chaos, so the\n // server returns to the chaos configuration it was STARTED with. Reset is the\n // isolation barrier every parallel harness leans on; chaos leaking past it\n // poisons later tests with 500s that look like application bugs.\n targets.defaults.chaos = undefined;\n targets.videoStates.clear();\n targets.openRouterVideoJobs.clear();\n targets.veoVideoJobs.clear();\n targets.grokVideoJobs.clear();\n targets.bytePlusVideoJobs.clear();\n for (const { handler } of targets.mounts ?? []) handler.clearMcpFakes?.();\n if (targets.defaults.registry) {\n targets.defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n}\n\n/**\n * JSON-safe redaction for control-API inspection output. Functions (fixture\n * `predicate`s, response factories) and RegExps do not survive\n * JSON.stringify as anything useful, so they become marker strings.\n */\nfunction redactForInspection(value: unknown): unknown {\n if (typeof value === \"function\") return \"[function]\";\n if (value instanceof RegExp) return String(value);\n if (Array.isArray(value)) return value.map(redactForInspection);\n if (value !== null && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n out[key] = redactForInspection(entry);\n }\n return out;\n }\n return value;\n}\n\n/**\n * One-line kind label for a fixture response used by\n * `GET /__aimock/fixtures?include=fixtures` (e.g. \"text\", \"error\").\n * Response factories are reported as \"factory\".\n *\n * Discriminates with the same `is*Response` guards the request handlers use,\n * in the same order — NOT by inspecting keys. Every response shape extends\n * `ResponseOverrides` (`id`/`created`/`model`/`usage`), so a recorded fixture's\n * first key is usually an envelope override rather than the discriminant. The\n * audio-before-content/toolCalls order is the ORDERING CONTRACT documented on\n * `AudioResponse` in types.ts: those shapes structurally overlap.\n */\nfunction fixtureResponseKind(response: Fixture[\"response\"]): string {\n if (isResponseFactory(response)) return \"factory\";\n if (isErrorResponse(response)) return \"error\";\n if (isAudioResponse(response)) return \"audio\";\n if (isVideoResponse(response)) return \"video\";\n if (isTranscriptionResponse(response)) return \"transcription\";\n if (isImageResponse(response)) return \"image\";\n if (isEmbeddingResponse(response)) return \"embedding\";\n if (isJSONResponse(response)) return \"json\";\n if (isContentWithToolCallsResponse(response)) return \"contentWithToolCalls\";\n if (isToolCallResponse(response)) return \"toolCalls\";\n if (isTextResponse(response)) return \"text\";\n return \"unknown\";\n}\n\n/**\n * The testId a journal entry was scoped under — `resolveTestId` applied to the\n * journaled headers and path, i.e. the SAME function that scoped the request\n * (fixture match-counts, chaos) when it arrived. Node folds a repeated\n * `X-Test-Id` into one string (\"a, a\") before either side sees it, and the\n * request is counted and chaos-evaluated under that folded string, so the\n * `?testId=` filter matches it verbatim too: no token-splitting here that the\n * scoping path does not also do. (Splitting on \",\" additionally broke every\n * legitimately comma-bearing id.) A raw `path.includes(\"testId=t1\")` both\n * prefix-collides with `t10` and matches unrelated params like `notTestId`.\n *\n * An MCP mount records the test id it resolved on the entry (I9, B3): a\n * decoded header or query value, or the one bound to the session at\n * `initialize`. That value wins; LLM entries carry none and are attributed as\n * before.\n */\nfunction journalEntryTestId(entry: JournalEntry): string {\n return entry.testId ?? resolveTestId(entry.headers, entry.path);\n}\n\n/**\n * The testId a chaos override is stored under, and read back with — resolved by\n * `getTestId`, i.e. `X-Test-Id` header then `?testId=`, exactly as\n * `resolveScopedDefaults` resolves the traffic being evaluated. A control call\n * and the requests it is meant to affect can then never land in different\n * scopes. `DEFAULT_TEST_ID` (neither header nor param) means the server-wide\n * baseline.\n *\n * Returns `null` when `X-Test-Id` is PRESENT but blank. `String(testId ?? \"\")`\n * in a harness produces that trivially, and silently treating it as \"untagged\"\n * would install a server-wide baseline that fails every other test — the exact\n * cross-test leak per-testId scoping exists to prevent. Callers must 400.\n */\nfunction chaosScopeId(req: http.IncomingMessage): string | null {\n const headerValue = req.headers[\"x-test-id\"];\n const raw = Array.isArray(headerValue) ? headerValue[0] : headerValue;\n if (typeof raw === \"string\" && raw.trim() === \"\") return null;\n return getTestId(req);\n}\n\n/** 400 for a control call whose `X-Test-Id` is present but blank. */\nfunction writeBlankTestId(res: http.ServerResponse): true {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'X-Test-Id': header is present but empty\" }));\n return true;\n}\n\n/**\n * The chaos config in effect for one testId: its override, else the baseline —\n * one or the other, never the two merged. Mirrors `resolveScopedDefaults` in\n * chaos.ts, so what `GET /__aimock/chaos` reports for a scope is exactly what\n * that scope's traffic is evaluated against.\n */\nfunction effectiveChaos(defaults: HandlerDefaults, scopeId: string): ChaosConfig {\n // `has`, not truthiness — an installed-but-empty override is a selection (see\n // `resolveScopedDefaults`), so it must shadow the baseline here too or `GET`\n // would report a config the traffic is not evaluated against.\n if (defaults.chaosByTestId?.has(scopeId)) return defaults.chaosByTestId.get(scopeId) ?? {};\n const current = defaults.chaos;\n if (!current) return {};\n return isChaosScope(current) ? (current.base ?? {}) : current;\n}\n\n/** The `GET /__aimock/mcp/fakes` query-param vocabulary; anything else 400s. */\nconst MCP_FAKES_PARAMS = new Set([\"testId\", \"context\", \"mount\"]);\n\n/** A block's `mount` path, read without running getters; the add validates it. */\nfunction controlFakeMountOf(raw: unknown): string {\n if (typeof raw !== \"object\" || raw === null) return MCP_FAKES_DEFAULT_MOUNT;\n const value: unknown = Object.getOwnPropertyDescriptor(raw, \"mount\")?.value;\n return typeof value === \"string\" ? value : MCP_FAKES_DEFAULT_MOUNT;\n}\n\n/** The blocks of one control-API `mcpFakes` value that go to one mount path. */\ninterface ControlFakeGroup {\n path: string;\n /** Position of each block in the request's `mcpFakes` value. */\n positions: number[];\n sources: McpFakeSource[];\n}\n\n/** What the after-start auto-mount of a control-API add is wired with (W6, as W4). */\ninterface ControlFakeWiring {\n journal: Journal;\n defaults: HandlerDefaults;\n}\n\n/**\n * Check one `POST /__aimock/fixtures` `mcpFakes` value against the live\n * mounts (F10, W6) without changing anything. Returns every error in input\n * order (an empty list when the value can be added), and `apply`, which adds\n * the blocks (auto-mounting an MCPMock where no mount serves a block's path)\n * and returns the number of blocks added.\n *\n * The whole value is checked before any mount is touched, and the check\n * never adds to a real mount: each group is added to a throwaway store,\n * whose errors are the ones reported (it numbers the add `control-api#1`, as\n * a new mount would; for an existing MCPMock the rejected group is re-run on\n * its atomic add, so the errors name that mount's next `<n>`, I7). A group\n * whose path no request to it can reach (a mount that is not an MCPMock\n * serves it, an MCPMock answers it as its root, or it is under the control\n * prefix) is a mount conflict (one error per block).\n */\nfunction planControlApiFakes(\n raw: unknown,\n mounts: MountList,\n): { errors: FixtureLoadError[]; apply(wiring: ControlFakeWiring): number } {\n const items: Array<{ position: number; source: McpFakeSource }> = Array.isArray(raw)\n ? raw.map((block: unknown, position) => ({\n position,\n source: { source: \"control-api\", blockIndex: position, raw: block },\n }))\n : [{ position: 0, source: { source: \"control-api\", blockIndex: null, raw } }];\n\n const groups = new Map<string, ControlFakeGroup>();\n // An empty `mcpFakes` array is one (bad) add to the default mount.\n if (items.length === 0) {\n groups.set(MCP_FAKES_DEFAULT_MOUNT, {\n path: MCP_FAKES_DEFAULT_MOUNT,\n positions: [],\n sources: [],\n });\n }\n for (const { position, source } of items) {\n const path = controlFakeMountOf(source.raw);\n const group = groups.get(path) ?? { path, positions: [], sources: [] };\n group.positions.push(position);\n group.sources.push(source);\n groups.set(path, group);\n }\n\n const found: Array<{ position: number; error: FixtureLoadError }> = [];\n /** The paths `apply` auto-mounts, in order. */\n const pending: string[] = [];\n for (const group of groups.values()) {\n const target = findFakeMount(mounts, group.path, pending);\n if (target.kind === \"conflict\") {\n group.positions.forEach((position) => {\n const where = Array.isArray(raw) ? msg`mcpFakes[${position}]` : msg`mcpFakes`;\n found.push({\n position,\n error: new FixtureLoadError({\n rule: \"mcp-fakes/mount-conflict\",\n file: null,\n blockId: null,\n entryId: null,\n detail: msg`${where}: ${mountConflictDetail(group.path, target)}`,\n }),\n });\n });\n continue;\n }\n let failure = addFailure(() => new McpFakeStore().add(group.sources, { kind: \"control-api\" }));\n if (target.kind === \"none\") pending.push(group.path);\n if (!failure) continue;\n // The throwaway numbers the add `control-api#1`; an existing MCPMock's\n // errors must name its own next `<n>` (I7). Its add is atomic (a throw\n // adds nothing and consumes no `<n>`), so the same rejected input is\n // re-run on it for the numbered errors. A mount with any other add is\n // never called here (A2).\n if (target.kind === \"mcp\" && target.handler.addMcpFakes === MCPMock.prototype.addMcpFakes) {\n const handler = target.handler;\n failure =\n addFailure(() => handler.addMcpFakes?.(group.sources, { kind: \"control-api\" })) ?? failure;\n }\n for (const error of failure.errors) {\n found.push({ position: positionOf(error, group), error });\n }\n }\n found.sort((a, b) => a.position - b.position);\n\n return {\n errors: found.map((f) => f.error),\n apply(wiring: ControlFakeWiring): number {\n let added = 0;\n for (const group of groups.values()) {\n const target = ensureFakeMount(\n mounts,\n group.path,\n {\n journal: wiring.journal,\n registry: wiring.defaults.registry,\n logger: wiring.defaults.logger,\n },\n wiring.defaults.logger,\n );\n // The plan found no conflict, and nothing else runs in between.\n if (\"conflict\" in target) continue;\n const result = target.handler.addMcpFakes?.(group.sources, { kind: \"control-api\" });\n for (const warning of result?.warnings ?? []) wiring.defaults.logger.warn(warning.message);\n added += group.sources.length;\n }\n return added;\n },\n };\n}\n\n/** The `McpFakesAddError` that `add` throws, or `null` when it adds. */\nfunction addFailure(add: () => unknown): McpFakesAddError | null {\n try {\n add();\n return null;\n } catch (err) {\n if (err instanceof McpFakesAddError) return err;\n throw err;\n }\n}\n\n/**\n * The request position of the block an add error names. The add numbers a\n * run-time group's blocks by their place in the group (`[<j>]`), or gives no\n * index to a single-object value; an error tied to no block sorts with the\n * group's first block.\n */\nfunction positionOf(error: FixtureLoadError, group: ControlFakeGroup): number {\n const first = group.positions[0] ?? 0;\n if (error.blockId == null || error.file === null) return first;\n const at = group.positions.findIndex(\n (_, j) => error.blockId === blockIdOf(error.file ?? \"\", \"\", j),\n );\n return at === -1 ? first : group.positions[at];\n}\n\n/** The listing half of an MCP mount, as `MCPMock` has it. */\ninterface FakesSnapshotSource {\n fakesSnapshot: MCPMock[\"fakesSnapshot\"];\n}\n\nfunction hasFakesSnapshot(handler: Mountable): handler is Mountable & FakesSnapshotSource {\n return \"fakesSnapshot\" in handler && typeof handler.fakesSnapshot === \"function\";\n}\n\n/**\n * `GET /__aimock/mcp/fakes` (spec 6.5, I9): for each MCP mount (or the one\n * named by `mount`), the blocks that apply to the requested test id and\n * context, with every entry id and its consumed state for that test id.\n * A mount is listed when it takes fakes (it implements `addMcpFakes`, the\n * check every other fakes path uses); one with no `fakesSnapshot` lists no\n * blocks.\n */\nfunction listControlApiFakes(\n mounts: MountList,\n testId: string | null,\n context: string | null,\n mount: string | null,\n): Array<{ mount: string; blocks: ReturnType<MCPMock[\"fakesSnapshot\"]> }> | null {\n const listed = mounts.flatMap(({ path, handler }) =>\n isFakeMount(handler) && (mount === null || path === mount)\n ? [\n {\n mount: path,\n blocks: hasFakesSnapshot(handler) ? handler.fakesSnapshot(testId, context) : [],\n },\n ]\n : [],\n );\n return mount !== null && listed.length === 0 ? null : listed;\n}\n\n/**\n * Handle requests under `/__aimock/`. Returns `true` if the request was\n * handled, `false` if the path doesn't match the control prefix.\n */\nasync function handleControlAPI(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n searchParams: URLSearchParams,\n fixtures: Fixture[],\n journal: Journal,\n videoStates: VideoStateMap,\n openRouterVideoJobs: OpenRouterVideoJobMap,\n veoVideoJobs: VeoVideoJobMap,\n grokVideoJobs: GrokVideoJobMap,\n bytePlusVideoJobs: BytePlusVideoJobMap,\n defaults: HandlerDefaults,\n mounts: MountList,\n): Promise<boolean> {\n if (!pathname.startsWith(CONTROL_PREFIX)) return false;\n\n const subPath = pathname.slice(CONTROL_PREFIX.length);\n setCorsHeaders(res);\n\n // GET /__aimock/health\n if (subPath === \"/health\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n return true;\n }\n\n // GET /__aimock/openapi.json — machine-readable route catalog.\n if (subPath === \"/openapi.json\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(buildOpenApiDocument()));\n return true;\n }\n\n // GET /__aimock/routes — flat method+path list for shells.\n if (subPath === \"/routes\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ count: CATALOG_ROUTES.length, routes: CATALOG_ROUTES }));\n return true;\n }\n\n // GET /__aimock/journal — optionally filtered/paginated.\n // No query params → full array (historical behaviour, unchanged).\n // Supported params: limit (int >= 0), offset (int >= 0, default 0),\n // path (SUBSTRING), method (exact, case-insensitive), status (int),\n // service (EXACT), testId (resolved exactly as the server resolves it).\n // Anything else is a 400: silently ignoring an unknown param would let\n // `?statusCode=404` return the whole journal and pass a caller's assertion\n // against traffic it never meant to select.\n if (subPath === \"/journal\" && req.method === \"GET\") {\n const bad = (message: string): true => {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: message }));\n return true;\n };\n for (const key of searchParams.keys()) {\n if (!JOURNAL_PARAMS.has(key)) {\n return bad(\n `Unknown query parameter: '${key}'. Supported: ${[...JOURNAL_PARAMS].join(\", \")}`,\n );\n }\n }\n const parseNonNegativeInt = (name: string, fallback: number): number | null => {\n const raw = searchParams.get(name);\n if (raw === null) return fallback;\n if (!/^\\d+$/.test(raw.trim())) return null;\n return Number(raw);\n };\n const limit = parseNonNegativeInt(\"limit\", -1);\n const offset = parseNonNegativeInt(\"offset\", 0);\n if (limit === null) return bad(\"Invalid 'limit': must be an integer >= 0\");\n if (offset === null) return bad(\"Invalid 'offset': must be an integer >= 0\");\n let statusFilter: number | undefined;\n const statusRaw = searchParams.get(\"status\");\n if (statusRaw !== null) {\n if (!/^\\d+$/.test(statusRaw.trim())) return bad(\"Invalid 'status': must be an integer\");\n statusFilter = Number(statusRaw);\n }\n const pathFilter = searchParams.get(\"path\");\n const methodFilter = searchParams.get(\"method\");\n const serviceFilter = searchParams.get(\"service\");\n const testIdFilter = searchParams.get(\"testId\");\n const requestIdFilter = searchParams.get(\"requestId\");\n\n let entries: JournalEntry[] = journal.getAll();\n if (methodFilter !== null) {\n const want = methodFilter.toUpperCase();\n entries = entries.filter((e) => e.method.toUpperCase() === want);\n }\n if (pathFilter !== null) {\n entries = entries.filter((e) => e.path.includes(pathFilter));\n }\n if (statusFilter !== undefined) {\n entries = entries.filter((e) => e.response.status === statusFilter);\n }\n if (serviceFilter !== null) {\n entries = entries.filter((e) => e.service === serviceFilter);\n }\n if (testIdFilter !== null) {\n entries = entries.filter((e) => journalEntryTestId(e) === testIdFilter);\n }\n if (requestIdFilter !== null) {\n entries = entries.filter((e) => e.headers[\"x-request-id\"] === requestIdFilter);\n }\n // Count AFTER filtering but BEFORE pagination, so a paging caller can tell\n // when it is done. It ships as a header because the body is a bare array\n // for back-compat and can never grow an envelope.\n const total = entries.length;\n if (offset > 0) entries = entries.slice(offset);\n if (limit >= 0) entries = entries.slice(0, limit);\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"X-Total-Count\": String(total),\n });\n res.end(JSON.stringify(entries));\n return true;\n }\n\n // GET /__aimock/fixtures — inspect current fixture count. With\n // ?include=fixtures, also dump each fixture's (redacted) match criteria\n // and response kind so harnesses can assert what would match.\n if (subPath === \"/fixtures\" && req.method === \"GET\") {\n // Unknown params 400 for the same reason `/journal` does: a typo like\n // `?incluide=fixtures` must never quietly return the count-only body and\n // pass an assertion against a dump the caller never received.\n for (const key of searchParams.keys()) {\n if (!FIXTURES_PARAMS.has(key)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Unknown query parameter: '${key}'. Supported: ${[...FIXTURES_PARAMS].join(\", \")}`,\n }),\n );\n return true;\n }\n }\n const include = searchParams.get(\"include\");\n if (include === null) {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ count: fixtures.length }));\n return true;\n }\n if (include !== \"fixtures\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'include': expected 'fixtures'\" }));\n return true;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n count: fixtures.length,\n fixtures: fixtures.map((fixture, index) => ({\n index,\n match: redactForInspection(fixture.match),\n // NOT `response` — that name already means the response ITSELF on\n // `Fixture`, and this is only a one-word kind label. A queued\n // one-shot error carries a FACTORY response (the factory performs\n // the idempotent claim), so the shape test alone reports \"factory\"\n // and this surface loses the one signal it exists to give: that an\n // injection is armed. Take the kind from the one-shot MARKER.\n responseKind: isOneShotError(fixture) ? \"error\" : fixtureResponseKind(fixture.response),\n ...(fixture.latency !== undefined ? { latency: fixture.latency } : {}),\n ...(fixture.chaos !== undefined ? { chaos: fixture.chaos } : {}),\n })),\n }),\n );\n return true;\n }\n\n // GET /__aimock/chaos — read the chaos config in effect for THIS caller's\n // testId: its own override if one is installed, else the server-wide\n // baseline (the construction config, or an untagged override).\n if (subPath === \"/chaos\" && req.method === \"GET\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // DELETE /__aimock/chaos — drop the override for this caller's testId (or the\n // server-wide baseline when untagged), falling back to what it shadowed.\n // `POST {}` means \"explicitly no chaos\"; this means \"forget I said anything\".\n //\n // SYMMETRIC with POST: an untagged DELETE drops the untagged baseline ONLY.\n // Dropping every per-testId override too would let one test's cleanup revoke\n // a concurrently-running test's opt-out. `POST /__aimock/reset` is the one\n // route that clears everything.\n if (subPath === \"/chaos\" && req.method === \"DELETE\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n defaults.chaosByTestId?.delete(scopeId);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // POST /__aimock/chaos — replace the server chaos config at runtime (no\n // restart). Accepts any subset of dropRate/malformedRate/disconnectRate as\n // numbers in [0, 1]; `{}` means explicitly no chaos. Unknown fields and\n // out-of-range values are rejected with 400.\n //\n // SCOPED to the caller's testId (`X-Test-Id`, else `?testId=`), like every\n // other mutable axis in the server (fixture match-counts, video job maps): an\n // override installed by test `t1` applies only to traffic resolving to `t1`.\n // An untagged call sets the server-wide baseline. `POST /__aimock/reset`\n // drops all of it, restoring the chaos config the server was STARTED with.\n //\n // REPLACES WHOLESALE — the body is not merged over the config it shadows. A\n // server started with `--chaos-latency 500` that is sent `{ \"dropRate\": 1 }`\n // for `t1` gives `t1` drops and NO latency: restate `latencyMs` to keep it.\n // That is what makes `POST {}` (\"explicitly no chaos\") different from\n // `DELETE` (\"fall back to what I was shadowing\"); under a merge, `POST {}`\n // would be a no-op. The 200 body echoes the config actually in effect for the\n // scope, and any field that WAS in effect and is not restated is named in a\n // warning, so a dropped baseline rate is never silent.\n if (subPath === \"/chaos\" && req.method === \"POST\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/chaos: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/chaos: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid body: expected a JSON object\" }));\n return true;\n }\n // The set of fields and their bounds come from `CHAOS_FIELDS`, and each\n // value is validated by the same `parseChaosField` every other chaos source\n // uses. Re-typing the limits here is how this endpoint used to accept\n // `{ latencyMs: 250.5 }` with a 200 and echo it back from `GET`, while the\n // resolver silently discarded it at request time as a non-integer: the\n // control API reported a config the traffic never saw.\n for (const key of Object.keys(parsed)) {\n if (!(CHAOS_FIELD_NAMES as readonly string[]).includes(key)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Unknown chaos field: '${key}'` }));\n return true;\n }\n }\n const next: ChaosConfig = {};\n for (const key of CHAOS_FIELD_NAMES) {\n const value = parsed[key];\n if (value === undefined) continue;\n // JSON body: the field must be a number. A numeric STRING is a\n // client-side type error here, not a wire spelling to be parsed — the\n // header API is the surface that takes text.\n const accepted = typeof value === \"number\" ? parseChaosField(key, value) : undefined;\n if (accepted === undefined) {\n const shape = CHAOS_FIELDS[key].integer ? \"a whole number of ms\" : \"a number\";\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Invalid '${key}': must be ${shape} between 0 and ${CHAOS_FIELDS[key].max}`,\n }),\n );\n return true;\n }\n next[key] = accepted;\n }\n // The install REPLACES what was in effect for this scope; it does not merge\n // over it. Name every field that was in effect and is not restated, so a\n // baseline rate a test silently loses (the classic case: a server-wide\n // `--chaos-latency` vanishing under a scoped `{ dropRate: 1 }`) shows up in\n // the log instead of as a mystery in the timings.\n const shadowed = effectiveChaos(defaults, scopeId);\n const droppedFields = (Object.keys(shadowed) as (keyof ChaosConfig)[]).filter(\n (key) => shadowed[key] !== undefined && next[key] === undefined,\n );\n if (droppedFields.length > 0) {\n const lost = droppedFields.map((key) => `${key}=${shadowed[key]}`).join(\", \");\n defaults.logger.warn(\n `[chaos] POST /__aimock/chaos (testId '${scopeId}') replaces the chaos config for this ` +\n `scope wholesale, it is not merged: ${lost} no longer applies here. ` +\n `Restate the field in the body to keep it.`,\n );\n }\n defaults.chaosByTestId?.set(scopeId, next);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // GET /__aimock/mcp/fakes — the MCP fakes that apply to a test id/context,\n // per mount, with each entry's consumed state (spec 6.5, I9).\n if (subPath === \"/mcp/fakes\" && req.method === \"GET\") {\n const reply = (status: number, body: unknown): true => {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return true;\n };\n for (const key of searchParams.keys()) {\n if (!MCP_FAKES_PARAMS.has(key)) {\n return reply(400, {\n error: `Unknown query parameter: '${key}'. Supported: ${[...MCP_FAKES_PARAMS].join(\", \")}`,\n });\n }\n }\n // Empty values are not supplied (I1, I2).\n const testId = searchParams.get(\"testId\") || null;\n const context = searchParams.get(\"context\") || null;\n const mount = searchParams.get(\"mount\") || null;\n const listed = listControlApiFakes(mounts, testId, context, mount);\n if (listed === null) {\n return reply(404, { error: build(msg`No MCP mount at ${quote(mount ?? \"\")}`) });\n }\n return reply(200, { testId, context, mounts: listed });\n }\n\n // POST /__aimock/fixtures — add fixtures dynamically\n if (subPath === \"/fixtures\" && req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/fixtures: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: { fixtures?: FixtureFileEntry[]; mcpFakes?: unknown } | null;\n try {\n parsed = JSON.parse(raw) as { fixtures?: FixtureFileEntry[]; mcpFakes?: unknown } | null;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/fixtures: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n\n // F10, B6: `fixtures` is optional when the body carries `mcpFakes`.\n const withFakes =\n typeof parsed === \"object\" && parsed !== null && Object.hasOwn(parsed, \"mcpFakes\");\n if (\n parsed === null ||\n (!Array.isArray(parsed.fixtures) && !(withFakes && parsed.fixtures === undefined))\n ) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: 'Missing or invalid \"fixtures\" array' }));\n return true;\n }\n const entries: FixtureFileEntry[] = Array.isArray(parsed.fixtures) ? parsed.fixtures : [];\n\n const missingMatchIndex = entries.findIndex(\n (entry) =>\n entry !== null && typeof entry === \"object\" && !Array.isArray(entry) && entry.match == null,\n );\n if (missingMatchIndex !== -1) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Fixture at index ${missingMatchIndex} is missing match` }));\n return true;\n }\n\n const invalidMatchIndex = entries.findIndex(\n (entry) =>\n entry !== null &&\n typeof entry === \"object\" &&\n !Array.isArray(entry) &&\n entry.match != null &&\n (typeof entry.match !== \"object\" || Array.isArray(entry.match)),\n );\n if (invalidMatchIndex !== -1) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({ error: `Fixture at index ${invalidMatchIndex}: match must be an object` }),\n );\n return true;\n }\n\n const converted = entries.map((e) => entryToFixture(e));\n const issues = validateFixtures(converted);\n const errors = issues.filter((i) => i.severity === \"error\");\n // The whole body is checked before anything is added (W6): the LLM\n // fixtures, then every `mcpFakes` block against the live mounts.\n const fakes = withFakes ? planControlApiFakes(parsed.mcpFakes, mounts) : null;\n const fakeErrors = fakes?.errors ?? [];\n const validationFailed = (details: unknown[]): true => {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Validation failed\", details }));\n return true;\n };\n if (errors.length > 0 || fakeErrors.length > 0) {\n return validationFailed([...errors, ...fakeErrors.map((e) => e.toJSON())]);\n }\n\n let mcpFakesAdded = 0;\n if (fakes) {\n try {\n mcpFakesAdded = fakes.apply({ journal, defaults });\n } catch (err) {\n if (!(err instanceof McpFakesAddError)) throw err;\n return validationFailed(err.errors.map((e) => e.toJSON()));\n }\n }\n fixtures.push(...converted);\n if (defaults.registry) {\n defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n withFakes ? { added: converted.length, mcpFakesAdded } : { added: converted.length },\n ),\n );\n return true;\n }\n\n // DELETE /__aimock/fixtures — clear all fixtures, and every MCP fake (R3)\n if (subPath === \"/fixtures\" && req.method === \"DELETE\") {\n clearFixtureQueue(fixtures);\n for (const { handler } of mounts) handler.clearMcpFakes?.();\n if (defaults.registry) {\n defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ cleared: true }));\n return true;\n }\n\n const resetTargets = (): FullResetTargets => ({\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\n defaults,\n mounts,\n });\n\n // POST /__aimock/reset — full reset (fixtures, journal entries + fixture\n // match-counts, video/fal job state, Gemini counters)\n if (subPath === \"/reset\" && req.method === \"POST\") {\n performFullReset(fixtures, resetTargets());\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ reset: true }));\n return true;\n }\n\n // POST /__aimock/reset/journal — clear only the request journal entries,\n // preserving fixture match-counts (sequencing state stays intact)\n if (subPath === \"/reset/journal\" && req.method === \"POST\") {\n journal.clearEntries();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ reset: true }));\n return true;\n }\n\n // POST /__aimock/reset/fixtures — DEPRECATED alias for /reset. The name\n // promises a fixtures-only reset but it always performed the full reset;\n // /reset is the honest route. Behaviour is unchanged for existing callers.\n if (subPath === \"/reset/fixtures\" && req.method === \"POST\") {\n performFullReset(fixtures, resetTargets());\n const deprecation =\n \"POST /__aimock/reset/fixtures is deprecated; use POST /__aimock/reset (full reset) or POST /__aimock/reset/journal (journal only)\";\n defaults.logger.warn(\n \"POST /__aimock/reset/fixtures is deprecated; use /__aimock/reset or /__aimock/reset/journal\",\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\", Deprecation: \"true\" });\n res.end(JSON.stringify({ reset: true, deprecated: true, deprecation }));\n return true;\n }\n\n // POST /__aimock/error — queue a one-shot error\n if (subPath === \"/error\" && req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/error: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: { status?: number; body?: { message?: string; type?: string; code?: string } };\n try {\n parsed = JSON.parse(raw) as typeof parsed;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/error: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n\n // Validate the payload — an unchecked `status` reaches\n // `res.writeHead(status)` on the next matched request and throws\n // ERR_HTTP_INVALID_STATUS_CODE for 99, 0, 1000 or 99.5, losing the\n // injected error and degrading to a generic 500.\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid body: expected a JSON object\" }));\n return true;\n }\n // Omitted — or an explicit null, which is how a serializer spells an absent\n // optional — keeps the historic default of 500.\n const status = parsed.status ?? 500;\n if (!isInjectableStatus(status)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid 'status': must be ${INJECTED_STATUS_RANGE}` }));\n return true;\n }\n const errorBody = parsed.body;\n // `body: null` is an absent body, not a malformed one — same rule as the\n // fields below and as `status`. Rejecting it broke a call that worked\n // (main defaulted every field) for a shape any serializer emits for an\n // unset optional.\n if (errorBody !== undefined && errorBody !== null) {\n if (typeof errorBody !== \"object\" || Array.isArray(errorBody)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'body': must be an object\" }));\n return true;\n }\n for (const field of [\"message\", \"type\", \"code\"] as const) {\n const value = errorBody[field];\n // null means absent, not invalid: aimock's own error envelope\n // (`serializeErrorResponse`) emits `code: null`, and so does a real\n // OpenAI error, so a captured body can be pasted back verbatim.\n if (value !== undefined && value !== null && typeof value !== \"string\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid 'body.${field}': must be a string` }));\n return true;\n }\n }\n }\n // Shared with `LLMock.nextRequestError`: same endpoint gate, consumed when\n // served rather than when its predicate is evaluated.\n queueOneShotError(fixtures, status, errorBody ?? undefined);\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ queued: true }));\n return true;\n }\n\n // Unknown control path\n handleNotFound(res, `Unknown control endpoint: ${pathname}`);\n return true;\n}\n\n/**\n * The client tore the connection down before its request body had fully\n * arrived. Node rejects the pending body read with `aborted` (ECONNRESET) and\n * destroys the response, so the rejection surfaces in the handler's read arm\n * looking like any other thrown error. It is caller behaviour, not a server\n * fault: no status can reach the client, so none must be journaled as\n * delivered. A body that blew its size cap also leaves the request destroyed\n * and incomplete, but that one is aimock's own decision, not a peer abort.\n */\nfunction clientAbortedMidBody(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n err: unknown,\n): boolean {\n if (err instanceof RequestBodyTooLargeError) return false;\n return res.destroyed && !req.complete;\n}\n\nasync function handleCompletions(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n modelFallback?: string,\n providerKey?: RecordProviderKey,\n openRouter = false,\n): Promise<void> {\n setCorsHeaders(res);\n\n // Read request body\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"Failed to read request body\";\n // Same classification every `routeError` route applies to this failure: a\n // body that blew its size cap is the CALLER's fault, logged at warn.\n // If the reader destroyed the socket, no status was delivered.\n // This arm catches the read itself\n // rather than letting it reach `routeError`, so it has to say so on its\n // own — and it logs either way, because a read failure answered in\n // silence is a request that vanishes from the logs.\n const clientFault = err instanceof RequestBodyTooLargeError;\n const route = `${req.method ?? \"POST\"} ${req.url ?? COMPLETIONS_PATH}`;\n const clientAbort = clientAbortedMidBody(req, res, err);\n const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);\n if (clientAbort || bodyLimitDisconnect) {\n // The body reader or caller destroyed the socket: nothing can be\n // delivered and nothing crashed. Journal the torn socket the way the proxy arm\n // and chaos `disconnect` do, never a status the client did not get.\n const interruptReason = bodyLimitDisconnect\n ? \"request body exceeded size limit\"\n : \"client aborted\";\n defaults.logger.warn(\n bodyLimitDisconnect ? `${route}: ${msg}` : `${route}: client aborted mid-body (${msg})`,\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status: 0,\n fixture: null,\n interrupted: true,\n interruptReason,\n },\n });\n return;\n }\n const status = clientFault ? 400 : 500;\n if (clientFault) defaults.logger.warn(`${route}: ${msg}`);\n else defaults.logger.error(`${route}: ${msg}`);\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status, fixture: null },\n });\n writeErrorResponse(\n res,\n status,\n openRouter\n ? serializeOpenRouterError(status, `Request body read failed: ${msg}`)\n : JSON.stringify({\n error: {\n message: `Request body read failed: ${msg}`,\n type: clientFault ? \"invalid_request_error\" : \"server_error\",\n },\n }),\n );\n return;\n }\n\n // Parse JSON body\n let body: ChatCompletionRequest;\n try {\n body = JSON.parse(raw) as ChatCompletionRequest;\n } catch (parseErr: unknown) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown parse error\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, `Malformed JSON: ${detail}`)\n : JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n param: null,\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `body.messages` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(body)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, \"Request body must be a JSON object\")\n : JSON.stringify({\n error: {\n message: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Azure deployments may omit model from body — use deployment ID as fallback\n if (modelFallback && !body.model) {\n body.model = modelFallback;\n }\n\n // Validate messages array\n if (!Array.isArray(body.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, \"Missing required parameter: 'messages'\")\n : JSON.stringify({\n error: {\n message: \"Missing required parameter: 'messages'\",\n type: \"invalid_request_error\",\n param: null,\n code: null,\n },\n }),\n );\n return;\n }\n\n const nullMessageIndex = body.messages.findIndex((message) => message === null);\n if (nullMessageIndex !== -1) {\n const message = `Invalid request: messages[${nullMessageIndex}] must be an object`;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, message)\n : JSON.stringify({\n error: {\n message,\n type: \"invalid_request_error\",\n param: null,\n code: null,\n },\n }),\n );\n return;\n }\n\n // Only native OpenAI ingress applies this shape rule; compatible routes\n // retain their own tool conventions. Missing-function shorthand stays valid.\n if (new URL(req.url ?? COMPLETIONS_PATH, \"http://localhost\").pathname === COMPLETIONS_PATH) {\n let toolsError = validateToolsField(body.tools);\n if (!toolsError && Array.isArray(body.tools)) {\n const nullFunctionIndex = body.tools.findIndex((tool) => tool?.function === null);\n if (nullFunctionIndex !== -1) {\n toolsError = `tools[${nullFunctionIndex}].function must not be null`;\n }\n }\n if (toolsError) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({ error: { message: toolsError, type: \"invalid_request_error\" } }),\n );\n return;\n }\n }\n\n const method = req.method ?? \"POST\";\n const path = req.url ?? COMPLETIONS_PATH;\n const flatHeaders = flattenHeaders(req.headers);\n\n // Set endpoint type once early so router/recorder and journal see it\n body._endpointType = \"chat\";\n body._context = getContext(req);\n\n // Match fixture first — chaos resolution depends on fixture-level overrides\n // (headers > fixture.chaos > server defaults), so the fixture has to be\n // known before we can roll with the right config.\n const testId = getTestId(req);\n const matchOptions = recordMatchOptions(\n // In record mode a miss proxies upstream to capture a fresh turn, so an\n // earlier-turn capture must not shadow a longer request via the relaxed\n // turnIndex disambiguator — keep turnIndex a strict gate while recording.\n // This handler's record gate (below) is `defaults.record && providerKey`.\n !!(defaults.record && providerKey),\n defaults.logger,\n );\n\n // OpenRouter `models[]` fallback simulation. When the request arrived on the\n // OpenRouter base AND carries a fallback array, attempt the candidate list\n // `[model, ...models]` in order and serve the FIRST non-error fixture match\n // — an ERROR-fixture candidate simulates a RUNTIME provider failure (429/503)\n // and falls through, exactly as real OpenRouter fails over on a runtime\n // error. The winning slug is echoed back as the response `model` (the only\n // fallback signal a real client sees). `preResolvedResponse` is the winner's\n // already-resolved response so the shared branch below does not re-resolve\n // (and thus does not re-invoke a response factory). Requests without a\n // fallback array take the ordinary single-model match path unchanged.\n //\n // Deliberate non-goal (mock vs real): real OpenRouter rejects an\n // unknown/invalid model in `models[]` up front with a 400 \"not a valid model\n // ID\" and does NOT fail over from it (failover is runtime-error only). aimock\n // is fixture-driven — an unknown model simply matches no fixture (a strict\n // miss / 404), so we do not replicate that up-front 400.\n let fixture: Fixture | null = null;\n let skippedBySequenceOrTurn = 0;\n let preResolvedResponse: FixtureResponse | null = null;\n // The model echoed back in the RESPONSE — the winner of the fallback chain,\n // or the requested model when there is no chain. The client's originally\n // requested `body.model` is left UNTOUCHED so the journaled request records\n // what was actually sent: it is the RESPONSE, not the request, that carries\n // the fallback outcome (`response.model` = winner).\n let responseModel = body.model;\n // Whether the fallback loop already advanced the served fixture's match count\n // (so the shared increment below does not double-count it).\n let fixtureCountIncremented = false;\n const openRouterFallback = openRouter && Array.isArray(body.models) && body.models.length > 0;\n // Select the fixture to serve for `probe`, CLAIMING a one-shot injected error\n // the instant it is selected — synchronously, before any chaos-latency await\n // and before its factory runs — so exactly one request consumes it. A\n // one-shot another in-flight request already claimed is no longer in\n // `fixtures`, so re-running the match falls through to the next candidate.\n const selectFixture = (\n probe: ChatCompletionRequest,\n counts: ReturnType<typeof journal.getFixtureMatchCountsForTest>,\n ): ReturnType<typeof matchFixtureDiagnostic> => {\n for (;;) {\n const attempt = matchFixtureDiagnostic(\n fixtures,\n probe,\n counts,\n defaults.requestTransform,\n matchOptions,\n );\n if (\n attempt.fixture &&\n isOneShotError(attempt.fixture) &&\n !claimOneShotError(fixtures, attempt.fixture)\n ) {\n continue;\n }\n return attempt;\n }\n };\n\n if (openRouterFallback) {\n const candidates = buildOpenRouterCandidates(body);\n // Re-read after each in-loop increment (below). `getFixtureMatchCountsForTest`\n // returns the LIVE cached map only once a map exists for `testId`; on the\n // FIRST request for a testId it returns a fresh TRANSIENT empty map that\n // `incrementFixtureMatchCount` (which lazily creates the cached map) never\n // touches. Without the refresh, a single fixture matched by MULTIPLE\n // candidates in one request would evaluate later candidates against a stale\n // count-0 snapshot — re-matching the same sequenced/turn-gated fixture and\n // over-advancing its count. Refreshing binds `matchCounts` to the live map.\n let matchCounts = journal.getFixtureMatchCountsForTest(testId);\n // Fail-CLOSED gate: `provider.allow_fallbacks: false` suppresses fall-through\n // — only the primary is tried and a primary error fixture is served as\n // terminal. Absent / `true` keeps the default runtime-error fall-through.\n const allowFallbacks = body.provider?.allow_fallbacks !== false;\n let lastErrorFixture: Fixture | null = null;\n let lastErrorResponse: FixtureResponse | null = null;\n // Separable resolver step: a candidate's success/error decision goes through\n // this small lookup (fixture match today) kept OUT of the loop's control\n // flow, so the loop could later resolve a candidate against a live upstream\n // without re-welding the iteration to `matchFixtureDiagnostic`.\n const resolveCandidate = async (\n candidate: string,\n ): Promise<{ fixture: Fixture; response: FixtureResponse; isError: boolean } | null> => {\n const probe: ChatCompletionRequest = { ...body, model: candidate };\n const attempt = selectFixture(probe, matchCounts);\n skippedBySequenceOrTurn = Math.max(skippedBySequenceOrTurn, attempt.skippedBySequenceOrTurn);\n if (!attempt.fixture) return null;\n const response = await resolveResponse(attempt.fixture, probe);\n return { fixture: attempt.fixture, response, isError: isErrorResponse(response) };\n };\n for (const candidate of candidates) {\n const outcome = await resolveCandidate(candidate);\n if (!outcome) {\n // Primary produced no fixture and fall-through is suppressed — stop.\n if (!allowFallbacks) break;\n continue;\n }\n // A candidate whose fixture matched-and-resolved is \"consumed\": advance\n // its match count (INCLUDING error candidates used as failovers) so a\n // sequenced/turn-gated fixture progresses across requests exactly as a\n // single match would — otherwise a sequenced error primary replays the\n // same failover on every request.\n journal.incrementFixtureMatchCount(outcome.fixture, fixtures, testId);\n fixtureCountIncremented = true;\n // Rebind to the now-live cached map so subsequent candidates in THIS\n // request see the increment (see the `let matchCounts` note above).\n matchCounts = journal.getFixtureMatchCountsForTest(testId);\n responseModel = candidate;\n if (outcome.isError) {\n // Per-error-fixture failover gate. An ERROR fixture may set\n // `fallthrough: false` to mark its error CLASS as non-failover-eligible\n // — reproducing OpenRouter serving a 403/generic provider error as\n // terminal instead of advancing to the next `models[]` candidate\n // (openclaw #60191). Absent / `true` keeps the default fall-through.\n // Composes with the request-level `allowFallbacks` gate: fail over only\n // when BOTH allow it (if EITHER says don't, this candidate is terminal).\n const errorFallsThrough = (outcome.response as ErrorResponse).fallthrough !== false;\n if (allowFallbacks && errorFallsThrough) {\n // Runtime provider failure — remember it and fail over to the next.\n lastErrorFixture = outcome.fixture;\n lastErrorResponse = outcome.response;\n continue;\n }\n }\n // Success, or a terminal error (allow_fallbacks:false or fallthrough:false).\n fixture = outcome.fixture;\n preResolvedResponse = outcome.response;\n break;\n }\n if (!fixture && lastErrorFixture) {\n // Every candidate failed — serve the last provider's error (faithful to\n // \"primary and every fallback failed\"). It was already counted above.\n fixture = lastErrorFixture;\n preResolvedResponse = lastErrorResponse;\n }\n } else {\n const single = selectFixture(body, journal.getFixtureMatchCountsForTest(testId));\n fixture = single.fixture;\n skippedBySequenceOrTurn = single.skippedBySequenceOrTurn;\n }\n\n if (fixture) {\n // The fallback loop already advanced the served fixture's count; only the\n // single-match path still needs to increment here (never double-count).\n if (!fixtureCountIncremented) journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n // `JSON.stringify` drops functions/RegExps, so a predicate fixture logged\n // as `{}`; `describeMatch` names every present matcher by kind.\n defaults.logger.debug(\n `Fixture matched: ${describeMatch(fixture.match, fixtures.indexOf(fixture))}`,\n );\n } else {\n const lastUserMsg = body.messages.filter((m) => m.role === \"user\").pop();\n const snippet =\n typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content.slice(0, 80) : \"\";\n defaults.logger.debug(\n `No fixture matched for request (model=${body.model ?? \"?\"}, msg=\"${snippet}\")`,\n );\n }\n\n // Roll chaos once per request. Dispatch by action + path:\n // drop / disconnect → apply immediately; upstream is never called and no\n // response body is produced.\n // malformed, fixture path → write invalid JSON instead of the fixture.\n // malformed, proxy path → proxy to upstream, then swap body via the\n // beforeWriteResponse hook (passed only when the\n // action is malformed, so the hook doesn't need\n // to re-check the action).\n // Deterministic latency is injected BEFORE the terminal actions are rolled,\n // so a configured delay applies to every outcome (served fixture, proxied\n // response, streamed response, and each chaos failure alike) — and, being\n // resolved from the same per-testId scope as the rates, never leaks into a\n // concurrently-running test that did not configure it.\n // Resolved ONCE and threaded into both the latency await and the action roll:\n // re-resolving would re-parse the chaos headers and emit every invalid/out-of-range\n // warning twice per request.\n const chaosConfig = resolveChaosConfig(\n fixture,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n await awaitChaosLatency(\n fixture,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n res,\n chaosConfig,\n );\n // C13: the latency await resolves EARLY when the client hangs up mid-delay\n // (the timer is cancelled off `res`'s `close`). `applyChaosAsync` re-checks\n // writability at exactly this point; a SPLIT gate has to do it itself.\n // Without this the handler carries on and builds, \"serves\" and JOURNALS a\n // full response into a dead socket — a phantom entry for bytes no client\n // ever received.\n const goneAfterLatency = responseGoneReason(res);\n if (goneAfterLatency !== null) {\n // Claimed at selection, but no error body ever reached a client — re-arm\n // so the injection is not burned by a client that walked away.\n releaseOneShotError(fixtures, fixture);\n defaults.logger.debug(\n `[chaos] ${method} ${path}: ${describeUnwritableReason(goneAfterLatency)} after the ` +\n `latency delay — not served, not journalled`,\n );\n return;\n }\n const chaosAction = evaluateChaos(\n fixture,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n chaosConfig,\n );\n const chaosContext = { method, path, headers: flatHeaders, body };\n // With no fixture, the response is aimock's own unless this request was\n // going to be proxied — so the journal source is \"internal\", not \"proxy\",\n // on the non-proxied path. A miss is only proxied when record mode has an\n // upstream for THIS provider and strict is not refusing it first; the\n // shared rule lives in `wouldProxyMiss` (also used by elevenlabs-voice.ts).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const missWouldProxy = wouldProxyMiss(effectiveStrict, defaults.record, providerKey);\n const noFixtureSource = missWouldProxy ? \"proxy\" : \"internal\";\n\n if (chaosAction === \"drop\" || chaosAction === \"disconnect\" || chaosAction === \"rateLimit\") {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n fixture ? \"fixture\" : noFixtureSource,\n defaults.registry,\n defaults.logger,\n );\n // The chaos action, not the fixture, answered this request — a claimed\n // one-shot's error body was never written, so put it back in the queue.\n releaseOneShotError(fixtures, fixture);\n return;\n }\n\n // `malformed` is applied here whenever there is no upstream response to\n // mutate: a matched fixture, or a miss that would not be proxied (the 404\n // and strict-503 paths). Only the proxied no-fixture case defers, to the\n // `beforeWriteResponse` hook below — the same `wouldProxyMiss` rule as the\n // source label above, so a strict-mode miss with an upstream configured is\n // answered here rather than skipped for a 503 that never rolled. Before\n // this, a rolled `malformed` on the no-fixture non-proxied path fell through\n // to a plain 404 — never applied, journalled or counted. With no fixture,\n // nothing here was ever proxied, so the source is aimock itself:\n // `\"internal\"`, never `\"proxy\"`.\n if (chaosAction === \"malformed\" && (fixture || !missWouldProxy)) {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n fixture ? \"fixture\" : \"internal\",\n defaults.registry,\n defaults.logger,\n );\n // Same as the terminal actions above: malformed replaces the body, so a\n // claimed one-shot's error was never served.\n releaseOneShotError(fixtures, fixture);\n return;\n }\n\n if (!fixture) {\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(\n strictNoMatchLogLine(\n req.method ?? \"POST\",\n req.url ?? COMPLETIONS_PATH,\n skippedBySequenceOrTurn,\n ),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n openRouter\n ? serializeOpenRouterError(strictStatus, strictMessage)\n : JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n param: null,\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n // Try record-and-replay proxy if configured\n if (defaults.record && providerKey) {\n // Hook is only passed when chaos wants to mutate the response. When\n // it's passed, it unconditionally applies malformed + journals + tells\n // proxyAndRecord to skip its default relay. The hook has no branching\n // logic — that decision is made here, at the call site.\n const hookOptions =\n chaosAction === \"malformed\"\n ? {\n // Malformed is emitted as a hardcoded invalid-JSON body, so the\n // captured upstream response isn't used here (the parameter is\n // intentionally omitted rather than declared-and-ignored).\n // Future dispatch (phase 3: non-JSON / streaming) will accept\n // the response and branch on contentType.\n beforeWriteResponse: () => {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n chaosContext,\n \"proxy\",\n defaults.registry,\n defaults.logger,\n );\n return true;\n },\n // Streaming responses can't be mutated post-facto (bytes already\n // on the wire). Record the bypass so the rolled action isn't\n // invisible in logs / Prometheus.\n onHookBypassed: (reason: \"sse_streamed\" | \"ndjson_streamed\" | \"binary_streamed\") => {\n defaults.logger.warn(\n `[chaos] malformed bypassed on proxy: upstream returned streaming response (${reason})`,\n );\n defaults.registry?.incrementCounter(\"aimock_chaos_bypassed_total\", {\n action: \"malformed\",\n source: \"proxy\",\n reason,\n });\n },\n }\n : undefined;\n\n // WHO killed a mid-flight stream decides what the journal says, and\n // after the fact the two look identical: `req.aborted`, `req.destroyed`\n // and `res.destroyed` all read the same whether the peer hung up or the\n // recorder tore the response down. The one signal that separates them is\n // the peer's FIN/RST, which arrives on the request socket as `end` (or\n // `error`) and only ever when the CLIENT went away. Removed afterwards:\n // a keep-alive socket outlives this request.\n let clientHungUp = false;\n const noteClientHangUp = (): void => {\n if (!res.writableEnded) clientHungUp = true;\n };\n req.socket?.on(\"end\", noteClientHangUp);\n req.socket?.on(\"error\", noteClientHangUp);\n let outcome: Awaited<ReturnType<typeof proxyAndRecord>>;\n try {\n outcome = await proxyAndRecord(\n req,\n res,\n body,\n providerKey,\n req.url ?? COMPLETIONS_PATH,\n fixtures,\n defaults,\n raw,\n hookOptions,\n );\n } finally {\n req.socket?.off(\"end\", noteClientHangUp);\n req.socket?.off(\"error\", noteClientHangUp);\n }\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n // A stream that died mid-flight still carries the 200 it opened with;\n // mark it interrupted so the journal shows what the client actually\n // got rather than a clean success, and name the side that killed it —\n // a client hang-up is normal caller behaviour, an upstream/recorder\n // tear-down is a fault worth chasing.\n const destroyedMidStream = res.destroyed && !res.writableEnded;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: {\n status: res.statusCode ?? 200,\n fixture: null,\n source: \"proxy\",\n ...(destroyedMidStream\n ? {\n interrupted: true,\n interruptReason: clientHungUp ? \"client aborted\" : \"proxy stream destroyed\",\n }\n : {}),\n },\n });\n return;\n }\n // outcome === \"not_configured\" — nothing was written; fall through to\n // 404, unless a rolled `malformed` is still owed to the client. Nothing\n // was proxied, so the source is `\"internal\"`.\n if (chaosAction === \"malformed\") {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n chaosContext,\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n return;\n }\n }\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n openRouter\n ? serializeOpenRouterError(404, \"No fixture matched\")\n : JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n param: null,\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n // Reuse the response already resolved by the OpenRouter fallback loop (so a\n // response factory is not invoked twice); otherwise resolve it now.\n const response = preResolvedResponse ?? (await resolveResponse(fixture, body));\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n // OpenRouter always accounts usage (cost) in the response, including as the\n // final streaming chunk — the OpenAI `stream_options.include_usage` gate is a\n // deprecated no-op there.\n const includeUsage = body.stream === true && body.stream_options?.include_usage === true;\n const emitStreamingUsage = includeUsage || openRouter;\n\n // Prompt text for streaming usage-chunk token estimation, concatenated from\n // the request messages exactly as the non-streaming completion builders do\n // (see buildTextCompletion et al. in helpers.ts) so both paths estimate the\n // same prompt token count. The streaming usage chunk is then resolved through\n // the SAME helpers.ts `resolveUsage` as the non-streaming path — a single\n // source of truth for \"explicit token override wins, cost-only override still\n // estimates\" (replaces three formerly-duplicated inline `?? 0` copies).\n const streamingPromptText = body.messages\n .map((m) =>\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content.map((p) => p.text ?? \"\").join(\"\")\n : \"\",\n )\n .join(\"\");\n const resolveStreamingUsageTokens = (\n overrides: ResponseOverrides | undefined,\n completionText: string,\n ): { prompt_tokens: number; completion_tokens: number; total_tokens: number } =>\n resolveUsage(overrides, streamingPromptText, completionText);\n\n // OpenRouter response shaping (no-op for OpenAI callers). Applied as a\n // post-pass over the objects the shared OpenAI builders produce so the\n // OpenAI code path is untouched. All OpenRouter-specific field shapes live in\n // openrouter-chat.ts. The fixture's `id` override still wins verbatim (the\n // `gen-` prefix rewrite only applies to auto-generated ids).\n const shapeORCompletion = (\n completion: ChatCompletion,\n overrides: ResponseOverrides | undefined,\n ): ChatCompletion => {\n if (!openRouter) return completion;\n return shapeOpenRouterCompletion(\n completion,\n resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel),\n overrides?.id !== undefined,\n );\n };\n const shapeORChunks = (\n chunks: SSEChunk[],\n usageChunk: SSEChunk | undefined,\n overrides: ResponseOverrides | undefined,\n ): void => {\n if (!openRouter) return;\n const shaping = resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel);\n shapeOpenRouterChunks(chunks, shaping, overrides?.id !== undefined);\n // The final usage chunk shares the stream id and provider; shaping it also\n // augments its usage with cost/cost_details.\n if (usageChunk) shapeOpenRouterChunks([usageChunk], shaping, overrides?.id !== undefined);\n };\n // Opt-in `: OPENROUTER PROCESSING` keepalive comment lines (default off).\n const openRouterProcessing = !!(openRouter && fixture.openRouterProcessing);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status, fixture },\n });\n writeErrorResponse(\n res,\n status,\n openRouter\n ? serializeOpenRouterError(status, response.error.message, response.error.metadata)\n : serializeErrorResponse(response),\n {\n retryAfter: response.retryAfter,\n },\n );\n return;\n }\n\n // Audio responses are not supported on the chat completions endpoint\n if (isAudioResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 422, fixture },\n });\n writeErrorResponse(\n res,\n 422,\n openRouter\n ? serializeOpenRouterError(\n 422,\n \"Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.\",\n )\n : JSON.stringify({\n error: {\n message:\n \"Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Content + tool calls response\n if (isContentWithToolCallsResponse(response)) {\n if (response.webSearches?.length) {\n defaults.logger.warn(\n \"webSearches in fixture response are not supported for Chat Completions API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n responseModel,\n effectiveStrict,\n defaults.logger,\n );\n // Validate authoritative blocks before recording success in either mode.\n // Reuse their normalized payload for nonstream responses and usage estimates.\n const streaming = body.stream === true;\n const blockOutcome =\n response.blocks && response.blocks.length > 0\n ? resolveFixtureBlockOutcome(response.blocks)\n : undefined;\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 200, fixture },\n });\n if (!streaming) {\n const completion = buildContentWithToolCallsCompletion(\n blockOutcome?.content ?? response.content ?? \"\",\n blockOutcome?.toolCalls ?? response.toolCalls ?? [],\n responseModel,\n effReasoning,\n blockOutcome\n ? {\n ...overrides,\n finishReason:\n overrides?.finishReason ?? (blockOutcome.hasToolCalls ? \"tool_calls\" : \"stop\"),\n }\n : overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks = buildContentWithToolCallsChunks(\n blockOutcome?.content ?? response.content ?? \"\",\n blockOutcome?.toolCalls ?? response.toolCalls ?? [],\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n blockOutcome?.ordered,\n );\n // Estimate usage from the same authoritative payload sent to the client.\n const completionText = blockOutcome\n ? blockOutcome.content + blockOutcome.toolCalls.map((tc) => tc.name + tc.arguments).join(\"\")\n : (response.content ?? \"\") +\n (response.toolCalls ?? []).map((tc) => tc.name + tc.arguments).join(\"\");\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0]?.id ?? \"chatcmpl-unknown\",\n overrides?.model ?? responseModel,\n chunks[0]?.created ?? Math.floor(Date.now() / 1000),\n resolveStreamingUsageTokens(overrides, completionText),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n if (response.webSearches?.length) {\n defaults.logger.warn(\n \"webSearches in fixture response are not supported for Chat Completions API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n responseModel,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 200, fixture },\n });\n if (body.stream !== true) {\n const completion = buildTextCompletion(\n response.content,\n responseModel,\n effReasoning,\n overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks = buildTextChunks(\n response.content,\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n );\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0]?.id ?? \"chatcmpl-unknown\",\n overrides?.model ?? responseModel,\n chunks[0]?.created ?? Math.floor(Date.now() / 1000),\n resolveStreamingUsageTokens(overrides, response.content),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n if (response.webSearches?.length) {\n defaults.logger.warn(\n \"webSearches in fixture response are not supported for Chat Completions API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = resolveReasoningForModel(\n response.reasoning,\n responseModel,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 200, fixture },\n });\n if (body.stream !== true) {\n const completion = buildToolCallCompletion(\n response.toolCalls,\n responseModel,\n effReasoning,\n overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks = buildToolCallChunks(\n response.toolCalls,\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n );\n const completionText = response.toolCalls.map((tc) => tc.name + tc.arguments).join(\"\");\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0]?.id ?? \"chatcmpl-unknown\",\n overrides?.model ?? responseModel,\n chunks[0]?.created ?? Math.floor(Date.now() / 1000),\n resolveStreamingUsageTokens(overrides, completionText),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: fixture.recordedTimings,\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Fixture response matched no known type — guard against silent hang\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n openRouter\n ? serializeOpenRouterError(500, \"Fixture response did not match any known type\")\n : JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n\nexport interface ServiceFixtures {\n search: SearchFixture[];\n rerank: RerankFixture[];\n moderation: ModerationFixture[];\n /** MCP fake blocks, handed off at start to the MCPMock serving each block's `mount` (F2). */\n mcpFakes?: McpFakeSource[];\n}\n\n// NOTE: The fixtures array is read by reference on each request. Callers\n// (e.g. LLMock) may mutate it after the server starts and changes will\n// be visible immediately. This is intentional — do not copy the array.\nexport async function createServer(\n fixtures: Fixture[],\n options?: MockServerOptions,\n mounts?: Array<{ path: string; handler: Mountable }>,\n serviceFixtures?: ServiceFixtures,\n): Promise<ServerInstance> {\n const resolvedAuth = resolveInboundAuth({ value: options?.auth, label: \"options.auth\" });\n return createServerWithResolvedAuth(fixtures, options, resolvedAuth, mounts, serviceFixtures);\n}\n\n/** @internal Config startup uses this to avoid parsing a selected auth source twice. */\nexport async function createServerWithResolvedAuth(\n fixtures: Fixture[],\n options: MockServerOptions | undefined,\n resolvedAuth: ResolvedInboundAuth,\n mounts?: Array<{ path: string; handler: Mountable }>,\n serviceFixtures?: ServiceFixtures,\n): Promise<ServerInstance> {\n const logger = new Logger(options?.logLevel ?? \"silent\");\n // Mounts-array rule (spec 5.2): one server-owned array for every use below.\n // A caller's array is that array, so a later `LLMock.mount()` push is seen.\n const mountList = mounts ?? [];\n // F2: hand MCP fakes off before the mount loop; a bad input rejects start().\n // A start that fails later takes the hand-off back, so a retry loads each\n // block once.\n const handOff =\n serviceFixtures?.mcpFakes && serviceFixtures.mcpFakes.length > 0\n ? handOffMcpFakes(mountList, serviceFixtures.mcpFakes, logger)\n : null;\n try {\n return await startServer(\n fixtures,\n options,\n resolvedAuth,\n mountList,\n logger,\n serviceFixtures,\n () => handOff?.commit(),\n );\n } catch (err) {\n handOff?.undo();\n throw err;\n }\n}\n\n/**\n * The server of `createServerWithResolvedAuth`, after the MCP fakes hand-off.\n * `commitHandOff` runs once the server listens; if it throws, the server is\n * closed and start rejects.\n */\nasync function startServer(\n fixtures: Fixture[],\n options: MockServerOptions | undefined,\n resolvedAuth: ResolvedInboundAuth,\n mountList: MountList,\n logger: Logger,\n serviceFixtures: ServiceFixtures | undefined,\n commitHandOff: () => void,\n): Promise<ServerInstance> {\n const host = options?.host ?? \"127.0.0.1\";\n const port = options?.port ?? 0;\n const registry = options?.metrics ? createMetricsRegistry() : undefined;\n const serverOptions = options ?? {};\n // Runtime-mutable server chaos config. Reads fall through to the construction\n // options until POST /__aimock/chaos installs an override, which is scoped to\n // the caller's testId. The untagged baseline lives in the SAME map under\n // DEFAULT_TEST_ID, so \"drop the baseline\" and \"drop one test's override\" are\n // one operation and neither can accidentally take the other's overrides with\n // it; only assigning `undefined` (a full reset) clears the map.\n const chaosByTestId = new Map<string, ChaosConfig>();\n const defaults = {\n latency: serverOptions.latency ?? 0,\n chunkSize: Math.max(1, serverOptions.chunkSize ?? DEFAULT_CHUNK_SIZE),\n replaySpeed: serverOptions.replaySpeed ?? 1.0,\n logger,\n chaosByTestId,\n // Handlers get a SCOPE, not a flat config: chaos.ts picks the override for\n // the request's X-Test-Id and falls back to the baseline.\n get chaos(): ChaosDefaults {\n return {\n base: chaosByTestId.get(DEFAULT_TEST_ID) ?? serverOptions.chaos,\n byTestId: chaosByTestId,\n };\n },\n // Assigning `undefined` drops EVERY runtime override instead of latching an\n // empty one, so the construction-time chaos config is always recoverable\n // (that is what `POST /__aimock/reset` does). `POST {}` still installs a\n // real, empty override: \"explicitly no chaos\".\n set chaos(value: ChaosDefaults | undefined) {\n if (value === undefined) {\n chaosByTestId.clear();\n return;\n }\n const base = isChaosScope(value) ? value.base : value;\n if (base === undefined) chaosByTestId.delete(DEFAULT_TEST_ID);\n else chaosByTestId.set(DEFAULT_TEST_ID, base);\n },\n registry,\n get record() {\n return serverOptions.record;\n },\n get strict() {\n return serverOptions.strict;\n },\n get requestTransform() {\n return serverOptions.requestTransform;\n },\n get falQueue() {\n return serverOptions.falQueue;\n },\n get openRouterVideo() {\n return serverOptions.openRouterVideo;\n },\n get veoVideo() {\n return serverOptions.veoVideo;\n },\n get grokVideo() {\n return serverOptions.grokVideo;\n },\n get bytePlusVideo() {\n return serverOptions.bytePlusVideo;\n },\n };\n\n // Validate chaos defaults through the ONE chaos table, so what startup warns\n // about is exactly what the runtime rejects (same fields, same bounds, same\n // words). The hand-rolled range check this replaces said nothing for\n // `latencyMs: 250.5`, which the runtime then rejected on every request.\n if (options?.chaos) {\n const chaosDefaults = options.chaos as Record<string, unknown>;\n for (const field of CHAOS_FIELD_NAMES) {\n const value = chaosDefaults[field];\n if (value === undefined) continue;\n // Typed config, like the control API's JSON body: a numeric string is a\n // type error, not a wire spelling to be parsed.\n if (typeof value === \"number\" && parseChaosField(field, value) !== undefined) continue;\n const shape = CHAOS_FIELDS[field].integer ? \"a whole number of ms\" : \"a number\";\n logger.warn(\n `Chaos default ${field} value ${JSON.stringify(value)} — must be ${shape} in [0,${CHAOS_FIELDS[field].max}]; rejected at runtime, never clamped: this default is ignored`,\n );\n }\n }\n\n // Validate poll-progression thresholds (resolveProgression treats\n // non-finite values as unset and floors/clamps the rest to >= 0 integers)\n for (const { name, config } of [\n { name: \"falQueue\", config: options?.falQueue },\n { name: \"openRouterVideo\", config: options?.openRouterVideo },\n { name: \"veoVideo\", config: options?.veoVideo },\n { name: \"grokVideo\", config: options?.grokVideo },\n { name: \"bytePlusVideo\", config: options?.bytePlusVideo },\n ]) {\n if (!config) continue;\n for (const field of [\"pollsBeforeInProgress\", \"pollsBeforeCompleted\"] as const) {\n const value = config[field];\n if (value === undefined) continue;\n if (!Number.isFinite(value)) {\n logger.warn(`${name}.${field} (${value}) is not a finite number — treating as unset`);\n } else if (!Number.isInteger(value) || value < 0) {\n logger.warn(\n `${name}.${field} (${value}) is not a non-negative integer — flooring/clamping to a non-negative integer`,\n );\n }\n }\n }\n\n // Validate the recorded-b64 cap: the capture path treats a negative or\n // non-integer record.openRouterVideo.maxContentBytes as the default rather\n // than letting `cap > 0` checks misbehave on negatives or NaN.\n {\n const cap = options?.record?.openRouterVideo?.maxContentBytes;\n if (cap !== undefined && (!Number.isInteger(cap) || cap < 0)) {\n logger.warn(\n `record.openRouterVideo.maxContentBytes (${cap}) is not a non-negative integer — using the default cap (${OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES})`,\n );\n }\n }\n\n // Reject a BytePlus upstream base that already carries Ark's `/api/v3`\n // prefix. `record.providers.byteplus` is an ORIGIN: the video handlers pass\n // the full `/api/v3/contents/generations/tasks[...]` constant to\n // resolveUpstreamUrl, and the chat/images proxies relay the client's raw\n // `req.url` (which is itself `/api/v3/...`). `@tanstack/ai-byteplus@0.3.4`\n // ships `https://ark.ap-southeast.bytepluses.com/api/v3` as its default Ark\n // `base_url` (`BYTEPLUS_ARK_BASE_URL`, which its own author labels\n // \"Docs-derived\" — this repo has not read BytePlus's docs), so pasting that\n // into --provider-byteplus is the expected mistake, and it composes\n // `/api/v3/api/v3/...` on every BytePlus path. The origin+prefix itself IS\n // observed to serve: a keyless GET under it answers 401, not 404.\n //\n // This THROWS rather than silently stripping the suffix, for two reasons.\n // (1) Nothing is being taken away: the doubled form cannot serve any\n // BytePlus request, so there is no working configuration to preserve —\n // whereas a silent strip would make aimock rewrite an operator-supplied URL\n // and would be flatly wrong for the one case where a path-suffixed base is\n // deliberate (a reverse proxy mounted under a path: stripping sends the\n // request to the origin, bypassing the mount). (2) A warn is easy to miss in\n // a mock server's log stream, and the symptom it leaves behind — a relayed\n // upstream 404 — does not name its cause. Fail at startup, where the message\n // can.\n {\n const bytePlusBase = options?.record?.providers?.byteplus;\n if (bytePlusBase !== undefined) {\n let basePath: string | undefined;\n try {\n basePath = new URL(bytePlusBase).pathname;\n } catch {\n // Not parseable as an absolute URL — leave it to the request path to\n // report; this guard only speaks to the prefix-doubling mistake.\n }\n if (basePath !== undefined && /(^|\\/)api\\/v3\\/?$/.test(basePath)) {\n throw new Error(\n `record.providers.byteplus (${bytePlusBase}) ends in /api/v3, but aimock ` +\n `appends the /api/v3 prefix itself — every BytePlus request would go to ` +\n `/api/v3/api/v3/... and fail upstream. Configure the ORIGIN only ` +\n `(e.g. https://ark.ap-southeast.bytepluses.com).`,\n );\n }\n }\n }\n\n /**\n * The in-flight request, scoped to the async execution that serves it.\n * Entered once in the `http.createServer` callback, so every handler —\n * including the ones in other modules that only ever see the shared\n * `journal` — runs inside it.\n */\n const requestScope = new AsyncLocalStorage<http.IncomingMessage>();\n /** The journal entry each request produced, keyed by the request object. */\n const ownJournalEntry = new WeakMap<http.IncomingMessage, JournalEntry>();\n\n // Programmatic default: finite caps so long-running embedders don't inherit\n // an unbounded journal / fixture-count map. Callers that need unbounded\n // retention (e.g. short-lived test harnesses) can opt in by passing 0.\n const journal = new Journal({\n maxEntries: options?.journalMaxEntries ?? 1000,\n fixtureCountsMaxTestIds: options?.fixtureCountsMaxTestIds ?? 500,\n onAdd: (entry) => {\n const req = requestScope.getStore();\n if (req) ownJournalEntry.set(req, entry);\n },\n });\n const videoStates = new VideoStateMap();\n const openRouterVideoJobs = new OpenRouterVideoJobMap();\n const veoVideoJobs = new VeoVideoJobMap();\n const grokVideoJobs = new GrokVideoJobMap();\n const bytePlusVideoJobs = new BytePlusVideoJobMap();\n\n /**\n * The OpenAI error `type` that goes with a status: 4xx is the caller's\n * fault, everything else is ours. Shared by `routeError` and the envelopes\n * it calls so the body can never disagree with the status line.\n */\n function errorTypeForStatus(status: number): string {\n return status >= 400 && status < 500 ? \"invalid_request_error\" : \"server_error\";\n }\n\n /**\n * The newest journal entry this request already produced, or null.\n *\n * Attribution is by the identity of the `IncomingMessage` the entry was\n * written under — never by `x-request-id`. That header is CALLER-supplied\n * (`resolveRequestId` echoes a well-formed one) and nothing makes it\n * unique: a retry, a harness that pins one id, or a load generator sends\n * the same id on many requests, and keying off it made a crash rewrite an\n * EARLIER request's entry while leaving the crashing request untraced. The\n * request object cannot be collided by a caller, so one entry belongs to\n * exactly one request. A handler writes at most one entry; if it writes\n * more, the newest wins, which is the entry the old scan would have found.\n */\n function lastJournalEntryFor(req: http.IncomingMessage): JournalEntry | null {\n return ownJournalEntry.get(req) ?? null;\n }\n\n /**\n * Uniform terminal arm for a route handler that threw. Every route error\n * path logs the route, journals the failure, sets CORS and answers the error\n * envelope — so a handler crash is never invisible in the logs or in\n * `/__aimock/journal`.\n *\n * ONE request produces ONE entry. `res.headersSent` is not the test for that:\n * a handler that journaled its 200 and then threw before `writeHead` has\n * sent no headers, and journaling again would leave two contradicting\n * entries for one request. So the existing entry is looked up by request\n * identity ({@link lastJournalEntryFor}) and AMENDED — status to what the\n * client actually got when the response is still changeable, or interrupted\n * when it isn't — and a fresh entry is\n * added only when the handler journaled nothing. That holds after the\n * response too: a handler that answered and then crashed before its own\n * journal write gets an entry carrying the status already sent, so a\n * post-response crash is never invisible.\n *\n * Once headers are on the wire the status can't change, so the socket is\n * destroyed: a clean `end()` reads as EOF and the client treats a truncated\n * stream as a complete response. The chat-style SSE routes whose clients\n * surface an error frame pass `streamEvent`; that frame is written first,\n * but the tear-down still follows it.\n *\n * A body that blew its size cap is the CALLER's fault, not a server fault:\n * it logs at warn, but if the reader destroyed the socket it journals an\n * interruption with status 0 because no 4xx reached the client. A client\n * that hung up before its body arrived\n * ({@link clientAbortedMidBody}) is not a fault at all: it logs at warn and\n * journals a torn socket (`interrupted`, status 0), never a 500 the client\n * could not have received.\n */\n function routeError(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n err: unknown,\n pathname: string,\n opts?: {\n service?: string;\n /**\n * Provider-shaped error body. Takes the STATUS routeError settled on —\n * a client-fault body cap answers 400, and an envelope that hardcoded\n * 500 would contradict the status line it is sent with.\n */\n envelope?: (msg: string, status: number) => string;\n streamEvent?: (msg: string, status: number) => string;\n },\n ): void {\n const route = `${req.method ?? \"?\"} ${pathname}`;\n const msg = err instanceof Error ? err.message : \"Internal error\";\n const clientFault = err instanceof RequestBodyTooLargeError;\n const clientAbort = clientAbortedMidBody(req, res, err);\n const status = clientFault ? 400 : 500;\n if (clientAbort) logger.warn(`${route}: client aborted mid-body (${msg})`);\n else if (clientFault) logger.warn(`${route}: ${msg}`);\n else logger.error(`${route}: ${msg}`);\n if (err instanceof Error && err.stack) logger.debug(err.stack);\n const existing = lastJournalEntryFor(req);\n const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);\n if ((clientAbort || bodyLimitDisconnect) && !res.headersSent) {\n const interruptReason = bodyLimitDisconnect\n ? \"request body exceeded size limit\"\n : \"client aborted\";\n // Nothing reached the client and nothing crashed: the entry records a\n // torn socket (status 0, same as chaos `disconnect` before headers), and\n // there is no socket left to answer on.\n if (existing) {\n if (!existing.response.interrupted) {\n existing.response.status = 0;\n existing.response.interrupted = true;\n existing.response.interruptReason = interruptReason;\n }\n return;\n }\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n ...(opts?.service ? { service: opts.service } : {}),\n response: {\n status: 0,\n fixture: null,\n source: \"internal\",\n interrupted: true,\n interruptReason,\n },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after body-read interruption: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n return;\n }\n if (!res.headersSent) {\n if (existing) {\n // The handler's own entry, corrected to the status the client gets.\n // `source`/`fixture` are left alone: they record what was going to\n // serve this request, which the crash didn't change.\n existing.response.status = status;\n } else {\n // Wrapped so journaling can never mask the error write below.\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n ...(opts?.service ? { service: opts.service } : {}),\n response: { status, fixture: null, source: \"internal\" },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n }\n setCorsHeaders(res);\n writeErrorResponse(\n res,\n status,\n opts?.envelope\n ? opts.envelope(msg, status)\n : JSON.stringify({\n error: {\n message: msg,\n type: errorTypeForStatus(status),\n },\n }),\n );\n } else {\n // Headers are on the wire, so the status the client got is fixed. If the\n // handler already journaled, mark its entry so the journal and the\n // metrics finish hook agree with the torn socket instead of reporting a\n // clean success. If it journaled nothing (it crashed on the way to\n // journaling, after the response went out), ADD the entry now — a\n // post-response crash must never leave a request without a trace.\n //\n // `interrupted` means the client did not get a complete body. Once\n // `end()` has run it did, so a crash after that point is recorded in\n // `error` with the status that was delivered, never as an interruption.\n const midStreamReason = clientAbort ? \"client aborted\" : \"handler crashed mid-stream\";\n if (existing) {\n if (res.writableEnded) {\n if (existing.response.error === undefined) existing.response.error = msg;\n } else if (!existing.response.interrupted) {\n existing.response.interrupted = true;\n existing.response.interruptReason = midStreamReason;\n }\n } else {\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n ...(opts?.service ? { service: opts.service } : {}),\n response: {\n status: res.statusCode,\n fixture: null,\n source: \"internal\",\n ...(res.writableEnded\n ? { error: msg }\n : { interrupted: true, interruptReason: midStreamReason }),\n },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n }\n // A response that already completed has nothing left to tear down.\n if (res.writableEnded) return;\n if (opts?.streamEvent) {\n try {\n // Destroy once the frame is flushed — written, then torn down, never\n // ended cleanly.\n res.write(opts.streamEvent(msg, status), () => {\n if (!res.destroyed) res.destroy();\n });\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n res.destroy();\n }\n } else {\n res.destroy();\n }\n }\n }\n\n // Share journal and metrics registry with mounted services\n for (const { handler } of mountList) {\n if (handler.setJournal) handler.setJournal(journal);\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n if (handler.setLogger) handler.setLogger(logger);\n }\n\n // Set initial fixtures-loaded gauge\n if (registry) {\n registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => {\n // Delegate to async handler — catch unhandled rejections to prevent Node.js crashes.\n // Run inside the request scope so every journal write made while serving\n // this request (in any handler module) is attributed back to it.\n requestScope.run(req, () => {\n handleHttpRequest(req, res).catch((err: unknown) => {\n routeError(req, res, err, req.url ?? \"?\");\n });\n });\n });\n\n async function handleHttpRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n // Record start time for metrics\n const startTime = registry ? process.hrtime.bigint() : 0n;\n\n // Request-id propagation: echo a well-formed caller id, else mint one.\n // Normalized back onto `req.headers` so every downstream\n // `flattenHeaders` journal snapshot carries it with zero per-handler\n // edits, and echoed on the response for trace correlation. A MINTED id is\n // aimock's own invention and must never reach a real provider, so the\n // provenance is marked for `buildForwardHeaders` to strip on egress; a\n // caller-supplied id is the caller's header and forwards untouched.\n const { id: requestId, generated: requestIdMinted } = resolveRequestId(req.headers);\n req.headers[\"x-request-id\"] = requestId;\n markMintedRequestId(req, requestIdMinted);\n res.setHeader(\"X-Request-Id\", requestId);\n\n let pathname = \"\";\n\n // Instrument response completion for metrics. The callbacks read pathname\n // via closure after normalizeCompatPath has rewritten it, so metrics\n // record the canonical /v1/... path. Registered BEFORE the URL is parsed:\n // a request whose target or `Host` header will not parse is answered 400,\n // and hooking after the parse would leave that response\n // uncounted. It reaches `normalizePathLabel` with the empty pre-parse\n // pathname and lands in `{unknown}`, like every other pre-routing reject.\n //\n // Two terminal events, one count. `finish` fires only when the body was\n // ended; a response torn down by `res.destroy()` — the `disconnect` chaos\n // action, a body-cap reset, a catch-arm teardown — never finishes and only\n // ever emits `close`. Those were invisible to `/metrics`, so the request\n // total under-counted by exactly the failures worth watching. `close`\n // also follows every `finish`, hence the guard: a normal response counts\n // once, under its status; a destroyed one counts once, as `destroyed`.\n if (registry) {\n let recorded = false;\n const recordOutcome = (status: string): void => {\n if (recorded) return;\n recorded = true;\n try {\n // Read the mount table at record time, not at start: `LLMock.mount()`\n // after `start()` pushes onto this same array, and a snapshot taken\n // here at startup labelled that (correctly routed) traffic `{unknown}`.\n const normalizedPath = normalizePathLabel(\n pathname,\n mountList.map((m) => m.path),\n );\n const method = req.method ?? \"UNKNOWN\";\n registry.incrementCounter(\"aimock_requests_total\", {\n method,\n path: normalizedPath,\n status,\n });\n const elapsed = Number(process.hrtime.bigint() - startTime) / 1e9;\n registry.observeHistogram(\n \"aimock_request_duration_seconds\",\n { method, path: normalizedPath },\n elapsed,\n );\n } catch (err) {\n defaults.logger.warn(\"metrics instrumentation error\", err);\n }\n };\n res.on(\"finish\", () => recordOutcome(String(res.statusCode)));\n res.on(\"close\", () => {\n if (!res.writableFinished) recordOutcome(DESTROYED_STATUS_LABEL);\n });\n }\n\n // Parse the URL pathname (strip query string)\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n } catch (err: unknown) {\n const route = `${req.method ?? \"?\"} ${req.url ?? \"?\"}`;\n const msg = err instanceof Error ? err.message : \"Internal error\";\n logger.error(`${route}: ${msg}`);\n if (err instanceof Error && err.stack) logger.debug(err.stack);\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null, source: \"internal\" },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n setCorsHeaders(res);\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Invalid request target\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n pathname = parsedUrl.pathname;\n // Capture the ORIGINAL path before normalizeCompatPath rewrites it — the\n // OpenRouter `/api/v1/` base is the detection signal and would otherwise be\n // erased (`/api/v1/chat/completions` → `/v1/chat/completions`).\n const originalPathname = pathname;\n const isOpenRouter = isOpenRouterPath(originalPathname);\n // BytePlus Ark attribution, GATED ON CONFIGURATION. A path prefix is not\n // evidence of a vendor — the COMPAT_SUFFIXES comment above exists precisely\n // because arbitrary vendors ride arbitrary prefixes (BigModel uses /v4/).\n // Ungated, anyone serving an OpenAI-compatible vendor under /api/v3 with\n // `record.providers.openai` configured would suddenly look up a byteplus\n // upstream, find none, and lose record mode entirely. Requiring a\n // configured byteplus upstream makes the new behavior reachable only for\n // the user who asked for it.\n const isBytePlusArk =\n defaults.record?.providers.byteplus !== undefined && originalPathname.startsWith(\"/api/v3/\");\n\n // Browser CORS preflights do not carry application credentials. A bare\n // OPTIONS is still a route request and must pass the normal auth boundary.\n if (\n req.method === \"OPTIONS\" &&\n (!resolvedAuth.policy.enabled ||\n (req.headers.origin !== undefined &&\n req.headers[\"access-control-request-method\"] !== undefined))\n ) {\n handleOptions(res);\n return;\n }\n\n const isPublicProbe =\n req.method === \"GET\" &&\n (pathname === HEALTH_PATH || pathname === READY_PATH || pathname === METRICS_PATH);\n if (!isPublicProbe) {\n if (!validateRequestApiKey(req, resolvedAuth.policy).ok) {\n writeApiKeyHttpRejection(res, setCorsHeaders);\n return;\n }\n markAuthenticatedRequest(req, resolvedAuth.policy);\n }\n\n // Control API — must be checked before mounts and path rewrites\n if (pathname.startsWith(CONTROL_PREFIX)) {\n await handleControlAPI(\n req,\n res,\n pathname,\n parsedUrl.searchParams,\n fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\n defaults,\n mountList,\n );\n return;\n }\n\n // Dispatch to mounted services before any path rewrites\n for (const { path: mountPath, handler } of mountList) {\n if (pathname === mountPath || pathname.startsWith(mountPath + \"/\")) {\n const subPath = pathname.slice(mountPath.length) || \"/\";\n const handled = await handler.handleRequest(req, res, subPath);\n if (handled) return;\n }\n }\n\n // Ollama /api/* routes must be dispatched BEFORE normalizeCompatPath, which\n // rewrites any path ending in /embeddings to /v1/embeddings. The /api/chat,\n // /api/generate, and /api/embed paths are unaffected (their suffixes aren't\n // in COMPAT_SUFFIXES), but /api/embeddings would collide with the OpenAI\n // handler. /api/embed is the current Ollama endpoint\n // (https://github.com/ollama/ollama/blob/main/docs/api.md); /api/embeddings\n // is the legacy path kept for backwards-compatibility. Both route to the\n // same handler.\n if (pathname === OLLAMA_CHAT_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleOllama(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (pathname === OLLAMA_GENERATE_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleOllamaGenerate(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (\n (pathname === OLLAMA_EMBEDDINGS_PATH || pathname === OLLAMA_EMBED_PATH) &&\n req.method === \"POST\"\n ) {\n try {\n const raw = await readBody(req);\n await handleOllamaEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (pathname === OLLAMA_TAGS_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n const modelIds = new Set<string>();\n for (const f of fixtures) {\n if (f.match.model && typeof f.match.model === \"string\") {\n modelIds.add(f.match.model);\n }\n }\n const ids = modelIds.size > 0 ? [...modelIds] : DEFAULT_MODELS;\n const models = ids.map((name) => ({\n name,\n model: name,\n modified_at: new Date().toISOString(),\n size: 0,\n digest: \"\",\n details: {},\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ models }));\n return;\n }\n\n // OpenRouter async video lifecycle (/api/v1/videos). Like the Ollama\n // /api/* routes above, dispatched before normalizeCompatPath. Order:\n // content RE → models exact → status RE → submit exact (the status RE's\n // `[^/]+` segment would otherwise swallow the `models` listing path; the\n // content path's extra `/content` segment can never match it).\n\n // GET /api/v1/videos/{jobId}/content — download the generated bytes\n const openRouterVideoContentMatch = pathname.match(OPENROUTER_VIDEO_CONTENT_RE);\n if (openRouterVideoContentMatch && req.method === \"GET\") {\n try {\n await handleOpenRouterVideoContent(\n req,\n res,\n openRouterVideoContentMatch[1],\n journal,\n defaults,\n setCorsHeaders,\n openRouterVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /api/v1/videos/models — video model listing (must precede the\n // status RE, whose [^/]+ segment would otherwise capture \"models\")\n if (pathname === OPENROUTER_VIDEO_MODELS_PATH && req.method === \"GET\") {\n try {\n await handleOpenRouterVideoModels(req, res, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /api/v1/videos/{jobId} — poll job status\n const openRouterVideoStatusMatch = pathname.match(OPENROUTER_VIDEO_STATUS_RE);\n if (openRouterVideoStatusMatch && req.method === \"GET\") {\n try {\n await handleOpenRouterVideoStatus(\n req,\n res,\n openRouterVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n openRouterVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /api/v1/videos — submit a video generation job (202 Accepted)\n if (pathname === OPENROUTER_VIDEOS_PATH && req.method === \"POST\") {\n // CORS headers before the body is read: a readBody throw (e.g. the\n // body-size cap) lands in the catch below, which must not write a 500\n // that is opaque to browser clients. The handler re-applies the same\n // headers (setHeader is idempotent).\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleOpenRouterVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n openRouterVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // ── BytePlus Ark (Seedance) async video task lifecycle ──────────────────\n // Registered in the PRE-REWRITE band, alongside the OpenRouter video routes\n // above: normalizeCompatPath does not currently claim these paths, but the\n // Ollama block documents that hazard and the mount dispatch also runs\n // pre-rewrite, so keeping every raw-path route in one band keeps one rule.\n //\n // The REs anchor an ENUMERATED optional `/api/v3` prefix (see metrics.ts).\n // That matters here specifically because this band runs ~1,100 lines ahead\n // of every fal branch, so a wildcard prefix would take\n // `/fal/contents/generations/tasks` away from the fal proxy.\n //\n // Status is tested BEFORE submit and each is method-guarded, so a future\n // DELETE .../tasks/{id} falls through to 404 rather than being mis-served.\n const bytePlusVideoStatusMatch = pathname.match(BYTEPLUS_VIDEO_STATUS_RE);\n if (bytePlusVideoStatusMatch && req.method === \"GET\") {\n try {\n await handleBytePlusVideoStatus(\n req,\n res,\n bytePlusVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (BYTEPLUS_VIDEO_SUBMIT_RE.test(pathname) && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleBytePlusVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // OpenRouter discovery endpoints. Dispatched BEFORE normalizeCompatPath\n // (which does not rewrite these — /models etc. are excluded from\n // COMPAT_SUFFIXES — so they would otherwise 404), mirroring the\n // /api/v1/videos ordering above. Read-only metadata; no body.\n if (pathname === OPENROUTER_MODELS_PATH && req.method === \"GET\") {\n handleOpenRouterModels(req, res, fixtures, journal, defaults, setCorsHeaders);\n return;\n }\n if (pathname === OPENROUTER_KEY_PATH && req.method === \"GET\") {\n handleOpenRouterKey(req, res, journal, setCorsHeaders);\n return;\n }\n if (pathname === OPENROUTER_CREDITS_PATH && req.method === \"GET\") {\n handleOpenRouterCredits(req, res, journal, setCorsHeaders);\n return;\n }\n\n // Azure OpenAI: /openai/deployments/{id}/{operation} → /v1/{operation} (chat/completions, embeddings)\n // Must be checked BEFORE the generic /openai/ prefix strip\n let azureDeploymentId: string | undefined;\n const azureMatch = pathname.match(AZURE_DEPLOYMENT_RE);\n if (azureMatch && req.method === \"POST\") {\n azureDeploymentId = azureMatch[1];\n const operation = azureMatch[2];\n pathname = `/v1/${operation}`;\n }\n\n // Normalize OpenAI-compatible paths (strip /openai/ prefix + rewrite arbitrary prefixes)\n if (!azureDeploymentId) {\n pathname = normalizeCompatPath(pathname, logger);\n }\n\n // Health / readiness probes\n if (pathname === HEALTH_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n if (mountList.length > 0) {\n const services: Record<string, unknown> = {\n llm: { status: \"ok\", fixtures: fixtures.length },\n };\n for (const { path: mountPath, handler } of mountList) {\n if (handler.health) {\n const name = mountPath.replace(/^\\//, \"\");\n services[name] = handler.health();\n }\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", services }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n }\n return;\n }\n\n if (pathname === READY_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ready\" }));\n return;\n }\n\n // Prometheus metrics\n if (pathname === METRICS_PATH && req.method === \"GET\") {\n if (!registry) {\n handleNotFound(res, \"Not found\");\n return;\n }\n setCorsHeaders(res);\n res.writeHead(200, { \"Content-Type\": \"text/plain; version=0.0.4; charset=utf-8\" });\n res.end(registry.serialize());\n return;\n }\n\n // Models listing\n if (pathname === MODELS_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n const modelIds = new Set<string>();\n for (const f of fixtures) {\n if (f.match.model && typeof f.match.model === \"string\") {\n modelIds.add(f.match.model);\n }\n }\n const ids = modelIds.size > 0 ? [...modelIds] : DEFAULT_MODELS;\n const data = ids.map((id) => ({\n id,\n object: \"model\" as const,\n created: 1686935002,\n owned_by: \"aimock\",\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ object: \"list\", data }));\n return;\n }\n\n // Batches API — cancel RE before id RE (the id RE would swallow /cancel).\n // Cancel takes no payload — the `openai` SDK posts an empty body — but the\n // body is still read, and discarded, before the handler runs. Reading it is\n // what applies `readBody`'s 10 MB ceiling: a POST route that never touches\n // the stream lets node quietly dump whatever the client sends, so this one\n // route would accept an unbounded upload while the create route beside it\n // (the sibling pattern followed here, down to the error arm) rejects the\n // same bytes.\n const batchesCancelMatch = pathname.match(BATCHES_CANCEL_RE);\n if (batchesCancelMatch && req.method === \"POST\") {\n try {\n await readBody(req);\n await handleBatchesCancel(\n req,\n res,\n batchesCancelMatch[1],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"batches\" });\n }\n return;\n }\n const batchesIdMatch = pathname.match(BATCHES_ID_RE);\n if (batchesIdMatch && req.method === \"GET\") {\n try {\n await handleBatchesRetrieve(req, res, batchesIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"batches\" });\n }\n return;\n }\n if (pathname === BATCHES_PATH && req.method === \"GET\") {\n try {\n await handleBatchesList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"batches\" });\n }\n return;\n }\n if (pathname === BATCHES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleBatchesCreate(req, res, raw, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"batches\",\n });\n }\n return;\n }\n\n // Files API mock — dispatch order matters: content RE → id RE → collection.\n // The id RE's `[^/]+` would otherwise swallow `/content`, and the\n // collection exact match must not claim an id path.\n //\n // Every branch is method-guarded, so an unhandled method on a files path\n // (`PATCH /v1/files/{id}`, and also `HEAD`, which nothing here implements)\n // falls through to the shared 404. That is this server's convention, not a\n // files-specific gap: there is no `405` anywhere in this file, the BytePlus\n // block above documents the same fallthrough by name, and measured against\n // a live server `HEAD /health` and `PATCH /v1/models` answer 404 exactly\n // like their files equivalents. Answering 405 + `Allow` here — or serving\n // HEAD — would make files the only surface in the mock that behaves that\n // way, which is a bigger inconsistency than the one it fixes. Changing it\n // is a server-wide change and belongs in its own pass.\n const filesContentMatch = pathname.match(FILES_CONTENT_RE);\n if (filesContentMatch && req.method === \"GET\") {\n try {\n await handleFilesContent(req, res, filesContentMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n const filesIdMatch = pathname.match(FILES_ID_RE);\n if (filesIdMatch && req.method === \"GET\") {\n try {\n await handleFilesRetrieve(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n if (filesIdMatch && req.method === \"DELETE\") {\n try {\n await handleFilesDelete(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n if (pathname === FILES_PATH && req.method === \"GET\") {\n // `purpose` is NOT read here. It used to be, with `searchParams.get`,\n // which silently first-wins a repeat and hands `\"\"` through for\n // `?purpose=`; the files module reads all four list parameters itself so\n // one rule covers them all.\n try {\n await handleFilesList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n if (pathname === FILES_PATH && req.method === \"POST\") {\n try {\n // A Buffer, not readBody's string: a multipart upload can carry\n // arbitrary binary and a utf8 decode here would corrupt it before\n // files.ts ever sees the bytes. Every other route keeps using readBody\n // unchanged.\n //\n // Bounded, not readBodyBuffer: this route must answer a\n // 400 for a body that is *over* its content cap, and readBodyBuffer's\n // only answer to over-size is destroying the socket — which the caller\n // reads as ECONNRESET, with no status and no CORS. Here the bound is\n // on memory, not on the socket. See the constants' doc comments.\n const body = await readBodyBufferBounded(\n req,\n FILES_BODY_MAX_BYTES,\n FILES_BODY_DRAIN_MAX_BYTES,\n );\n await handleFilesCreate(\n req,\n res,\n body.buffer ?? FILES_BODY_OVERSIZED,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"files\",\n });\n }\n return;\n }\n\n // Fine-tuning jobs — cancel/events REs before id RE.\n // Cancel takes no payload — the `openai` SDK posts an empty body — but the\n // body is still read, and discarded, before the handler runs. Reading it is\n // what applies `readBody`'s 10 MB ceiling: a POST route that never touches\n // the stream lets node quietly dump whatever the client sends, so this one\n // route would accept an unbounded upload while the create route beside it\n // (the sibling pattern followed here, down to the error arm) rejects the\n // same bytes.\n const ftCancelMatch = pathname.match(FINE_TUNING_CANCEL_RE);\n if (ftCancelMatch && req.method === \"POST\") {\n try {\n await readBody(req);\n await handleFineTuningCancel(req, res, ftCancelMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"fine-tuning\",\n });\n }\n return;\n }\n const ftEventsMatch = pathname.match(FINE_TUNING_EVENTS_RE);\n if (ftEventsMatch && req.method === \"GET\") {\n try {\n await handleFineTuningEvents(req, res, ftEventsMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"fine-tuning\" });\n }\n return;\n }\n const ftIdMatch = pathname.match(FINE_TUNING_ID_RE);\n if (ftIdMatch && req.method === \"GET\") {\n try {\n await handleFineTuningRetrieve(req, res, ftIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"fine-tuning\" });\n }\n return;\n }\n if (pathname === FINE_TUNING_JOBS_PATH && req.method === \"GET\") {\n try {\n await handleFineTuningList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"fine-tuning\" });\n }\n return;\n }\n if (pathname === FINE_TUNING_JOBS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleFineTuningCreate(req, res, raw, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"fine-tuning\",\n });\n }\n return;\n }\n\n // Vector Stores — most-specific REs before the id RE, collection last.\n // The id RE's `[^/]+` would otherwise swallow `/files`, `/search` and\n // the file-batch suffixes, and the collection exact match must not claim\n // an id path. Every branch is method-guarded so unhandled methods fall\n // through to the shared 404, the server-wide convention (see the files\n // block above).\n const vsSearchMatch = pathname.match(VECTOR_STORES_SEARCH_RE);\n if (vsSearchMatch && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVectorStoresSearch(\n req,\n res,\n vsSearchMatch[1],\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsBatchFilesMatch = pathname.match(VECTOR_STORES_BATCH_FILES_RE);\n if (vsBatchFilesMatch && req.method === \"GET\") {\n try {\n await handleVectorFileBatchesFiles(\n req,\n res,\n vsBatchFilesMatch[1],\n vsBatchFilesMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsBatchCancelMatch = pathname.match(VECTOR_STORES_BATCH_CANCEL_RE);\n if (vsBatchCancelMatch && req.method === \"POST\") {\n try {\n await readBody(req);\n await handleVectorFileBatchesCancel(\n req,\n res,\n vsBatchCancelMatch[1],\n vsBatchCancelMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsBatchMatch = pathname.match(VECTOR_STORES_BATCH_RE);\n if (vsBatchMatch && req.method === \"GET\") {\n try {\n await handleVectorFileBatchesRetrieve(\n req,\n res,\n vsBatchMatch[1],\n vsBatchMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsFileMatch = pathname.match(VECTOR_STORES_FILE_RE);\n if (vsFileMatch && req.method === \"GET\") {\n try {\n await handleVectorStoreFilesRetrieve(\n req,\n res,\n vsFileMatch[1],\n vsFileMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (vsFileMatch && req.method === \"DELETE\") {\n try {\n await handleVectorStoreFilesDelete(\n req,\n res,\n vsFileMatch[1],\n vsFileMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n // Note: VECTOR_STORES_ID_RE only matches the exact 3-segment id path,\n // so it can never swallow the /files, /search or /file_batches suffixes\n // handled above — no extra depth guards needed.\n const vsIdMatch = pathname.match(VECTOR_STORES_ID_RE);\n if (vsIdMatch && req.method === \"GET\") {\n try {\n await handleVectorStoresRetrieve(req, res, vsIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (vsIdMatch && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVectorStoresModify(\n req,\n res,\n vsIdMatch[1],\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (vsIdMatch && req.method === \"DELETE\") {\n try {\n await handleVectorStoresDelete(req, res, vsIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (VECTOR_STORES_FILES_RE.test(pathname) && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n const storeId = pathname.split(\"/\")[3];\n await handleVectorStoreFilesCreate(\n req,\n res,\n storeId,\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (VECTOR_STORES_FILES_RE.test(pathname) && req.method === \"GET\") {\n try {\n const storeId = pathname.split(\"/\")[3];\n await handleVectorStoreFilesList(req, res, storeId, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (VECTOR_STORES_FILE_BATCHES_RE.test(pathname) && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n const storeId = pathname.split(\"/\")[3];\n await handleVectorFileBatchesCreate(\n req,\n res,\n storeId,\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (pathname === VECTOR_STORES_PATH && req.method === \"GET\") {\n try {\n await handleVectorStoresList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (pathname === VECTOR_STORES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVectorStoresCreate(req, res, raw, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n\n // Journal inspection endpoints\n if (pathname === REQUESTS_PATH) {\n setCorsHeaders(res);\n if (req.method === \"GET\") {\n const limitParam = parsedUrl.searchParams.get(\"limit\");\n let opts: { limit: number } | undefined;\n if (limitParam) {\n const limit = Number(limitParam);\n if (!/^\\+?\\d+$/.test(limitParam.trim()) || !Number.isSafeInteger(limit) || limit <= 0) {\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Invalid limit parameter: \"${limitParam}\"`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n opts = { limit };\n }\n const entries = journal.getAll(opts);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(entries));\n return;\n }\n if (req.method === \"DELETE\") {\n // Clear only the request journal entries, preserving fixture\n // match-counts (sequencing state). Clearing the request log must not\n // silently rewind sequenced fixtures. For a full reset (entries +\n // match-counts), use POST /__aimock/reset.\n journal.clearEntries();\n res.writeHead(204);\n res.end();\n return;\n }\n handleNotFound(res, \"Not found\");\n return;\n }\n\n // POST /v1/responses — OpenAI Responses API\n if (pathname === RESPONSES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleResponses(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) =>\n `event: error\\ndata: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v1/messages — Anthropic Claude Messages API\n if (pathname === MESSAGES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleMessages(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) =>\n `event: error\\ndata: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v2/chat — Cohere v2 Chat API\n if (pathname === COHERE_CHAT_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleCohere(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) =>\n `event: error\\ndata: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v2/embed — Cohere v2 Embed API\n if (pathname === COHERE_EMBED_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleCohereEmbed(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/embeddings — OpenAI Embeddings API\n if (pathname === EMBEDDINGS_PATH && req.method === \"POST\") {\n try {\n const deploymentId = azureDeploymentId;\n const embeddingsProvider: RecordProviderKey = azureDeploymentId ? \"azure\" : \"openai\";\n let raw = await readBody(req);\n // Azure deployments may omit model from body — use deployment ID as fallback\n if (deploymentId) {\n try {\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (!parsed.model) {\n parsed.model = deploymentId;\n raw = JSON.stringify(parsed);\n }\n } catch (err) {\n if (!(err instanceof SyntaxError)) {\n defaults.logger.error(\n `Unexpected error in Azure model injection: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n // Fall through for parse errors — let handleEmbeddings report them\n }\n }\n await handleEmbeddings(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n embeddingsProvider,\n originalPathname === EMBEDDINGS_PATH,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/images/generations — OpenAI Image Generation API\n if (pathname === IMAGES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleImages(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"openai\",\n undefined,\n isBytePlusArk ? \"byteplus\" : undefined,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/images/edits — OpenAI Image Edit API (multipart/form-data)\n if (pathname === IMAGES_EDIT_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleImageEdit(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/images/variations — OpenAI Image Variations API (multipart/form-data)\n if (pathname === IMAGES_VARIATIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleImageVariations(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/audio/speech — OpenAI TTS API\n if (pathname === SPEECH_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleSpeech(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/audio/transcriptions — OpenAI Transcription API\n if (pathname === TRANSCRIPTIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleTranscription(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/audio/translations — OpenAI Translation API\n if (pathname === TRANSLATIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleTranscription(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"translation\",\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/videos/generations — xAI Grok Imagine video submit. A distinct\n // exact path from Sora's POST /v1/videos (no collision). Must precede the\n // Sora GET status RE which would otherwise parse `generations` as an id on\n // a GET — but this is a POST, so the guard is method-level here and\n // `id !== \"generations\"` in the GET block below. (T0: stub filled in T2.)\n if (pathname === GROK_VIDEO_SUBMIT_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleGrokVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n grokVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/videos — Video Generation API\n if (pathname === VIDEOS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n videoStates,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /v1/videos/{id} — Grok-first video status check. Grok Imagine and\n // Sora share this path: handleGrokVideoStatus does a job-map-first lookup\n // and falls through to the UNCHANGED Sora handleVideoStatus on a Grok miss\n // (disjoint id namespaces → unambiguous). The `id !== \"generations\"` guard\n // keeps the Grok submit literal out of the status RE. (T0: the Grok job map\n // is always empty, so every GET delegates to Sora — behavior-preserving.)\n const grokVideoStatusMatch = pathname.match(GROK_VIDEO_STATUS_RE);\n if (grokVideoStatusMatch && grokVideoStatusMatch[1] !== \"generations\" && req.method === \"GET\") {\n try {\n await handleGrokVideoStatus(\n req,\n res,\n grokVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n grokVideoJobs,\n videoStates,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/models/{model}:predictLongRunning — Google Veo video submit.\n // Anchored on `:predictLongRunning`, so it never collides with the Gemini\n // `:predict` Imagen route below. (T0: handler is a stub filled in T1.)\n const veoPredictMatch = pathname.match(VEO_PREDICT_LRO_RE);\n if (veoPredictMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleVeoVideoCreate(\n req,\n res,\n raw,\n veoPredictMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n veoVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /v1beta/operations/{name} — Google Veo video status poll.\n // (T0: handler is a stub filled in T1.)\n const veoOperationMatch = pathname.match(VEO_OPERATION_RE);\n if (veoOperationMatch && req.method === \"GET\") {\n try {\n await handleVeoVideoStatus(\n req,\n res,\n veoOperationMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n veoVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/models/{model}:predict — Gemini Imagen API\n const geminiPredictMatch = pathname.match(GEMINI_PREDICT_RE);\n if (geminiPredictMatch && req.method === \"POST\") {\n const predictModel = geminiPredictMatch[1];\n try {\n const raw = await readBody(req);\n await handleImages(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"gemini\",\n predictModel,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/interactions — Google Gemini Interactions API\n if (pathname === GEMINI_INTERACTIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleGeminiInteractions(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v1beta/models/{model}:embedContent — Google Gemini Embedding\n const geminiEmbedMatch = pathname.match(GEMINI_EMBED_RE);\n if (geminiEmbedMatch && req.method === \"POST\") {\n const embedModel = geminiEmbedMatch[1];\n try {\n const raw = await readBody(req);\n await handleGeminiEmbedContent(\n req,\n res,\n raw,\n embedModel,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/models/{model}:(generateContent|streamGenerateContent) — Google Gemini\n const geminiMatch = pathname.match(GEMINI_PATH_RE);\n if (geminiMatch && req.method === \"POST\") {\n const geminiModel = geminiMatch[1];\n const streaming = geminiMatch[2] === \"streamGenerateContent\";\n try {\n const raw = await readBody(req);\n await handleGemini(\n req,\n res,\n raw,\n geminiModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v1/projects/{project}/locations/{location}/publishers/google/models/{model}:(generateContent|streamGenerateContent) — Vertex AI\n const vertexMatch = pathname.match(VERTEX_AI_RE);\n if (vertexMatch && req.method === \"POST\") {\n const vertexModel = vertexMatch[1];\n const streaming = vertexMatch[2] === \"streamGenerateContent\";\n try {\n const raw = await readBody(req);\n await handleGemini(\n req,\n res,\n raw,\n vertexModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"vertexai\",\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /model/{modelId}/invoke — AWS Bedrock Claude API\n const bedrockMatch = pathname.match(BEDROCK_INVOKE_RE);\n if (bedrockMatch && req.method === \"POST\") {\n const bedrockModelId = bedrockMatch[1];\n try {\n const raw = await readBody(req);\n await handleBedrock(\n req,\n res,\n raw,\n bedrockModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /model/{modelId}/invoke-with-response-stream — AWS Bedrock Claude streaming\n const bedrockStreamMatch = pathname.match(BEDROCK_STREAM_RE);\n if (bedrockStreamMatch && req.method === \"POST\") {\n const bedrockModelId = bedrockStreamMatch[1];\n try {\n const raw = await readBody(req);\n await handleBedrockStream(\n req,\n res,\n raw,\n bedrockModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /model/{modelId}/converse — AWS Bedrock Converse API\n const converseMatch = pathname.match(BEDROCK_CONVERSE_RE);\n if (converseMatch && req.method === \"POST\") {\n const converseModelId = converseMatch[1];\n try {\n const raw = await readBody(req);\n await handleConverse(\n req,\n res,\n raw,\n converseModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /model/{modelId}/converse-stream — AWS Bedrock Converse streaming API\n const converseStreamMatch = pathname.match(BEDROCK_CONVERSE_STREAM_RE);\n if (converseStreamMatch && req.method === \"POST\") {\n const converseStreamModelId = converseStreamMatch[1];\n try {\n const raw = await readBody(req);\n await handleConverseStream(\n req,\n res,\n raw,\n converseStreamModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /search — Web Search API (Tavily-compatible)\n if (pathname === SEARCH_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleSearch(\n req,\n res,\n raw,\n serviceFixtures?.search ?? [],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"search\",\n });\n }\n return;\n }\n\n // POST /v2/rerank — Reranking API (Cohere rerank-compatible)\n if (pathname === RERANK_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleRerank(\n req,\n res,\n raw,\n serviceFixtures?.rerank ?? [],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"rerank\",\n });\n }\n return;\n }\n\n // POST /v1/moderations — Moderation API (OpenAI-compatible)\n if (pathname === MODERATIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleModeration(\n req,\n res,\n raw,\n serviceFixtures?.moderation ?? [],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"moderation\",\n });\n }\n return;\n }\n\n // POST /v1/sound-generation — ElevenLabs Sound Generation API\n if (pathname === ELEVENLABS_SOUND_GENERATION_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleElevenLabsAudio(req, res, raw, fixtures, defaults, journal, \"sound-generation\");\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/text-to-voice/design — ElevenLabs Voice Design (must precede create)\n if (pathname === ELEVENLABS_VOICE_DESIGN_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleElevenLabsVoiceDesign(req, res, raw, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"elevenlabs-voice\" });\n }\n return;\n }\n\n // POST /v1/text-to-voice — save a designed preview as a permanent voice\n if (pathname === ELEVENLABS_VOICE_CREATE_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleElevenLabsVoiceCreate(req, res, raw, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"elevenlabs-voice\" });\n }\n return;\n }\n\n // GET|DELETE /v1/voices/{voice_id} — slot management after Voice Design save\n const elevenLabsVoiceMatch = pathname.match(ELEVENLABS_VOICE_RE);\n if (elevenLabsVoiceMatch && (req.method === \"GET\" || req.method === \"DELETE\")) {\n setCorsHeaders(res);\n // The id arrives percent-encoded on the wire while the voice store is\n // keyed by the id exactly as it appears in JSON, so the raw path segment\n // made any id carrying a space or a slash permanently unreachable.\n // `decodeURIComponent` throws `URIError` on a malformed escape — that is\n // a bad request, not a server fault, so it is answered 400 rather than\n // falling into the 500 handler below.\n let voiceId: string;\n try {\n voiceId = decodeURIComponent(elevenLabsVoiceMatch[1]);\n } catch {\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Invalid voice id '${elevenLabsVoiceMatch[1]}': malformed percent-encoding`,\n type: \"invalid_request_error\",\n },\n }),\n );\n // Journaled AFTER the write, like every other terminal arm in this\n // batch: the caller's answer never waits on bookkeeping. Tagged with\n // the service so this rejection is selectable under\n // `?service=elevenlabs-voice` with the rest of the route's branches —\n // it was the one voice branch that left no journal entry at all.\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n service: \"elevenlabs-voice\",\n body: null,\n response: { status: 400, fixture: null },\n });\n return;\n }\n try {\n if (req.method === \"GET\") {\n await handleElevenLabsVoiceGet(req, res, voiceId, fixtures, defaults, journal);\n } else {\n await handleElevenLabsVoiceDelete(req, res, voiceId, fixtures, defaults, journal);\n }\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"elevenlabs-voice\" });\n }\n return;\n }\n\n // POST /v1/text-to-speech/{voice_id} — ElevenLabs TTS API\n const elevenLabsTTSMatch = pathname.match(ELEVENLABS_TTS_RE);\n if (elevenLabsTTSMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n const voiceId = elevenLabsTTSMatch[1];\n try {\n const raw = await readBody(req);\n await handleElevenLabsTTS(req, res, raw, fixtures, defaults, journal, voiceId);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/music/(generation|variation|remix|extend) — ElevenLabs Music API\n const musicMatch = pathname.match(ELEVENLABS_MUSIC_RE);\n if (musicMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n const musicSubType = musicMatch[1] ?? \"music\";\n try {\n const raw = await readBody(req);\n await handleElevenLabsAudio(req, res, raw, fixtures, defaults, journal, musicSubType);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // Body read by the general fal handler; preserved so legacy fal-audio\n // routes below don't double-consume the stream on passthrough.\n let falBody: string | undefined;\n\n // /fal/* with `x-fal-target-host` header — general fal.ai routing\n // (queue.fal.run, fal.run, rest.fal.ai, rest.alpha.fal.ai).\n // Matches the requestMiddleware path-mirror convention used by\n // @fal-ai/client when proxyUrl can't be honoured server-side.\n if (FAL_ROUTE_RE.test(pathname) && req.headers[\"x-fal-target-host\"]) {\n setCorsHeaders(res);\n try {\n falBody = req.method === \"POST\" || req.method === \"PUT\" ? await readBody(req) : \"\";\n const raw = falBody;\n // Chaos is rolled EXACTLY ONCE per fal request. This gate owns the roll\n // only when the general handler is actually going to own the request;\n // if `handleFal` would return \"passthrough\" the request continues to\n // the legacy `/fal/queue/...` / `/fal/run/...` routes below, and THEIR\n // `applyChaosAsync` (or the queue-requests gate) is the single roll.\n // Rolling here unconditionally would double-roll every passthrough\n // (observed: 0.72 effective drop rate for a configured 0.5).\n //\n // The deterministic latency is awaited BEFORE the roll, so a configured\n // delay applies to every outcome on this path — served state, proxied\n // response and each chaos failure alike — exactly as the completions\n // path does, and resolved from the same per-testId scope as the rates.\n //\n // `source` is \"internal\": the roll happens before any fixture match or\n // upstream call, so nothing was going to serve this but aimock's own\n // fal logic. Mirrors the veo/grok/openrouter lifecycle gates.\n if (falWillHandle(req, pathname)) {\n // Resolved ONCE and threaded into both the latency await and the\n // action roll — re-resolving would re-parse the chaos headers and\n // warn twice per request. `res` is passed so a client that hangs up\n // mid-delay CANCELS the pending timer instead of leaving the handler\n // waiting out the full latency. Both mirror the completions path.\n const chaosConfig = resolveChaosConfig(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n await awaitChaosLatency(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n res,\n chaosConfig,\n );\n // C13: the latency await resolves EARLY when the client hangs up\n // mid-delay (the timer is cancelled off `res`'s `close`).\n // `applyChaosAsync` re-checks writability at exactly this point; a\n // SPLIT gate has to do it itself. Without this the handler carries\n // on and builds, \"serves\" and JOURNALS a full response into a dead\n // socket — a phantom entry for bytes no client ever received.\n const goneAfterLatency = responseGoneReason(res);\n if (goneAfterLatency !== null) {\n defaults.logger.debug(\n `[chaos] ${req.method ?? \"GET\"} ${pathname}: ` +\n `${describeUnwritableReason(goneAfterLatency)} after the latency delay — ` +\n `not served, not journalled`,\n );\n return;\n }\n const chaosAction = evaluateChaos(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n chaosConfig,\n );\n if (chaosAction) {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n {\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n },\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n return;\n }\n }\n const outcome = await handleFal(req, res, raw, pathname, fixtures, defaults, journal);\n if (outcome === \"handled\") return;\n // passthrough: fall through to legacy fal-audio routes below\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n return;\n }\n }\n\n // POST /fal/queue/submit/{model} — fal.ai Queue Submit\n const falQueueSubmitMatch = pathname.match(FAL_QUEUE_SUBMIT_RE);\n if (falQueueSubmitMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = falBody ?? (await readBody(req));\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /fal/queue/requests/{requestId} — fal.ai Queue Status/Result\n const falQueueRequestsMatch = pathname.match(FAL_QUEUE_REQUESTS_RE);\n if (\n falQueueRequestsMatch &&\n (req.method === \"GET\" || req.method === \"POST\" || req.method === \"PUT\")\n ) {\n setCorsHeaders(res);\n try {\n const raw =\n req.method === \"POST\" || req.method === \"PUT\" ? (falBody ?? (await readBody(req))) : \"{}\";\n // Status / cancel / result are pure state lookups: `handleFalQueue`\n // rolls no chaos for them, so this gate is their single roll. Latency\n // first, then the roll — same order as every other handler path.\n // `source` is \"internal\" (no fixture, no upstream: aimock's own queue\n // state was going to serve this), matching the veo status gate.\n // Resolved ONCE and threaded into both the latency await and the action\n // roll; `res` makes the delay cancellable on client disconnect. Same\n // shape as the completions path and the `x-fal-target-host` gate above.\n const chaosConfig = resolveChaosConfig(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n await awaitChaosLatency(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n res,\n chaosConfig,\n );\n // C13: the latency await resolves EARLY when the client hangs up\n // mid-delay (the timer is cancelled off `res`'s `close`).\n // `applyChaosAsync` re-checks writability at exactly this point; a\n // SPLIT gate has to do it itself. Without this the handler carries on\n // and builds, \"serves\" and JOURNALS a full response into a dead\n // socket — a phantom entry for bytes no client ever received.\n const goneAfterLatency = responseGoneReason(res);\n if (goneAfterLatency !== null) {\n defaults.logger.debug(\n `[chaos] ${req.method ?? \"GET\"} ${pathname}: ` +\n `${describeUnwritableReason(goneAfterLatency)} after the latency delay — ` +\n `not served, not journalled`,\n );\n return;\n }\n const chaosAction = evaluateChaos(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n chaosConfig,\n );\n if (chaosAction) {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n {\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n },\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n return;\n }\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /fal/run/{model} — fal.ai Synchronous Run\n const falRunMatch = pathname.match(FAL_RUN_RE);\n if (falRunMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = falBody ?? (await readBody(req));\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/chat/completions — Chat Completions API\n if (pathname !== COMPLETIONS_PATH) {\n // Registry drift guard: the catalog claims every ROUTE_DEFINITIONS\n // entry is mounted. If the registry matches a request the dispatcher\n // just fell through, the two have drifted — warn loudly (the 404\n // stands; this never changes serving behavior). Exempt: /metrics 404s\n // by design when the server runs with `metrics: false`.\n const catalogMatch = matchRouteDefinition(req.method ?? \"\", pathname);\n if (catalogMatch && !(pathname === METRICS_PATH && !registry)) {\n defaults.logger.warn(\n `Route drift: ${req.method ?? \"?\"} ${pathname} matches the route catalog ` +\n `(${catalogMatch.method} ${catalogMatch.path} — ${catalogMatch.description}) ` +\n `but no dispatcher branch served it. The catalog entry or the dispatcher ` +\n `is stale — see route-registry.ts.`,\n );\n }\n handleNotFound(res, \"Not found\");\n return;\n }\n if (req.method !== \"POST\") {\n handleNotFound(res, \"Not found\");\n return;\n }\n\n // OpenRouter callers (original path under /api/v1/) get the OpenRouter\n // provider key + response shaping; OpenAI (/v1/...) callers are unchanged.\n const completionsProvider: RecordProviderKey = azureDeploymentId\n ? \"azure\"\n : isOpenRouter\n ? \"openrouter\"\n : isBytePlusArk\n ? \"byteplus\"\n : \"openai\";\n try {\n await handleCompletions(\n req,\n res,\n fixtures,\n journal,\n defaults,\n azureDeploymentId,\n completionsProvider,\n isOpenRouter,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n envelope: (m, status) =>\n isOpenRouter\n ? serializeOpenRouterError(status, m)\n : JSON.stringify({\n error: { message: m, type: errorTypeForStatus(status) },\n }),\n streamEvent: (m, status) =>\n `data: ${\n isOpenRouter\n ? serializeOpenRouterError(status, m)\n : JSON.stringify({ error: { message: m, type: errorTypeForStatus(status) } })\n }\\n\\n`,\n });\n }\n }\n\n // ─── WebSocket upgrade handling ──────────────────────────────────────────\n\n const activeConnections = new Set<WebSocketConnection>();\n const liveLimits = normalizeLiveOptions(options?.live);\n const liveSessions = new Map<symbol, { testId: string; dispose: () => void }>();\n const closeLiveSessions = (testId?: string) => {\n for (const session of [...liveSessions.values()]) {\n if (testId === undefined || session.testId === testId) session.dispose();\n }\n };\n liveClosers.set(defaults, closeLiveSessions);\n\n server.on(\n \"upgrade\",\n (req: http.IncomingMessage, socket: import(\"node:net\").Socket, head: Buffer) => {\n handleUpgradeRequest(req, socket, head).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.warn(`Unhandled upgrade error: ${msg}`);\n if (!socket.destroyed) socket.destroy();\n });\n },\n );\n\n /**\n * Body bytes the platform already parsed onto `req` for an upgrade request.\n *\n * Node >= 26 delivers an upgrade request's body here and leaves `head`\n * empty; Node <= 24 leaves the body in `head` and ends `req` with nothing.\n * The stream has already ended in both cases, so this resolves on the next\n * tick either way — it never waits on the network.\n */\n function drainParsedRequestBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n let settled = false;\n const done = (): void => {\n if (settled) return;\n settled = true;\n resolve(Buffer.concat(chunks));\n };\n req.on(\"data\", (c: Buffer) => chunks.push(c));\n req.on(\"end\", done);\n req.on(\"error\", done);\n req.on(\"close\", done);\n req.resume();\n });\n }\n\n async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n // `Upgrade: h2c` + `Connection: Upgrade` on plain requests — including\n // ones with a body — to probe for HTTP/2 cleartext support. Only actual\n // WebSocket upgrades belong on this path.\n //\n // Node fires \"upgrade\" instead of \"request\" for any `Connection: Upgrade`,\n // whatever protocol is named, and the request never reaches the normal\n // pipeline. Rather than reimplementing body parsing, rebuild the request\n // line and headers with `Upgrade`/`Connection` dropped — the only thing\n // that made this look like an upgrade — replay them onto the socket, and\n // let Node re-parse the connection from scratch as an ordinary request.\n //\n // WHERE THE BODY LIVES DEPENDS ON THE NODE VERSION, and both cases must be\n // replayed or the re-parsed request stalls forever waiting on a\n // `Content-Length` worth of bytes that will never arrive:\n //\n // - Node <= 24 detaches the parser at \"upgrade\", so `req` yields nothing\n // and any body bytes already read land in `head` (or, if the client\n // sent them later, still arrive on the socket afterwards).\n // - Node >= 26 parses the body onto `req` and leaves `head` EMPTY. The\n // bytes are not on the socket either — draining `req` is the only way\n // to get them back.\n //\n // Draining `req` is safe on both: on the older behaviour it ends\n // immediately with zero bytes, so the concat below is a no-op there and\n // `head` carries the body as before.\n if ((req.headers.upgrade ?? \"\").toLowerCase() !== \"websocket\") {\n const parsedBody = await drainParsedRequestBody(req);\n const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\\r\\n`;\n const headerLines: string[] = [];\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n if (/^(?:upgrade|connection)$/i.test(req.rawHeaders[i])) continue;\n headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);\n }\n const rebuilt = Buffer.from(requestLine + headerLines.join(\"\\r\\n\") + \"\\r\\n\\r\\n\");\n socket.unshift(Buffer.concat([rebuilt, parsedBody, head]));\n server.emit(\"connection\", socket);\n return;\n }\n\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.warn(`Unhandled upgrade error: ${msg}`);\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n\");\n return;\n }\n let pathname = parsedUrl.pathname;\n\n if (!validateRequestApiKey(req, resolvedAuth.policy).ok) {\n writeApiKeyUpgradeRejection(socket);\n return;\n }\n\n // Dispatch to mounted services before any path rewrites\n for (const { path: mountPath, handler } of mountList) {\n if (\n (pathname === mountPath || pathname.startsWith(mountPath + \"/\")) &&\n handler.handleUpgrade\n ) {\n const subPath = pathname.slice(mountPath.length) || \"/\";\n if (await handler.handleUpgrade(socket, head, subPath)) return;\n }\n }\n\n // Normalize OpenAI-compatible paths (strip /openai/ prefix + rewrite arbitrary prefixes)\n // Skip Azure deployment paths — they have their own rewrite in the HTTP handler\n if (!pathname.match(AZURE_DEPLOYMENT_RE)) {\n pathname = normalizeCompatPath(pathname, logger);\n }\n\n if (\n pathname !== RESPONSES_PATH &&\n pathname !== REALTIME_PATH &&\n pathname !== GEMINI_LIVE_PATH &&\n pathname !== LIVE_PATH\n ) {\n socket.write(\"HTTP/1.1 404 Not Found\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n let liveId: symbol | undefined;\n if (pathname === LIVE_PATH) {\n if (req.method !== \"GET\" || parsedUrl.searchParams.has(\"model\")) {\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n\");\n return;\n }\n if (liveSessions.size >= liveLimits.maxSessions) {\n socket.end(\"HTTP/1.1 429 Too Many Requests\\r\\nConnection: close\\r\\n\\r\\n\");\n return;\n }\n liveId = Symbol(\"live-session\");\n const reservedId = liveId;\n liveSessions.set(reservedId, {\n testId: getTestId(req),\n dispose: () => {\n socket.destroy();\n liveSessions.delete(reservedId);\n },\n });\n }\n\n // Push any buffered data back before upgrading\n if (head.length > 0) {\n socket.unshift(head);\n }\n\n let ws: WebSocketConnection;\n try {\n ws = upgradeToWebSocket(req, socket, pathname === LIVE_PATH ? liveLimits : undefined);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"WebSocket upgrade failed\";\n if (liveId !== undefined) liveSessions.delete(liveId);\n logger.error(`WebSocket upgrade error: ${msg}`);\n if (!socket.destroyed) socket.destroy();\n return;\n }\n\n activeConnections.add(ws);\n\n ws.on(\"error\", (err: Error) => {\n logger.error(`WebSocket error: ${err.message}`);\n activeConnections.delete(ws);\n });\n\n ws.on(\"close\", () => {\n activeConnections.delete(ws);\n });\n\n // Route to handler\n const wsTestId = getTestId(req);\n if (pathname === LIVE_PATH && liveId !== undefined) {\n const sessionId = liveId;\n const dispose = handleLiveSession(ws, fixtures, journal, {\n defaults,\n limits: liveLimits,\n localApiKeys: resolvedAuth.publicConfig?.apiKeys,\n testId: wsTestId,\n headers: req.headers,\n onDispose: () => {\n liveSessions.delete(sessionId);\n activeConnections.delete(ws);\n },\n });\n liveSessions.set(sessionId, { testId: wsTestId, dispose });\n } else if (pathname === RESPONSES_PATH) {\n handleWebSocketResponses(ws, fixtures, journal, {\n ...defaults,\n model: \"gpt-4\",\n testId: wsTestId,\n upgradeHeaders: req.headers,\n });\n } else if (pathname === REALTIME_PATH) {\n const transcriptionIntent = parsedUrl.searchParams.get(\"intent\") === \"transcription\";\n const model = transcriptionIntent\n ? \"gpt-transcribe\"\n : (parsedUrl.searchParams.get(\"model\") ?? \"gpt-realtime-2\");\n handleWebSocketRealtime(ws, fixtures, journal, {\n ...defaults,\n model,\n transcriptionIntent,\n testId: wsTestId,\n upgradeHeaders: req.headers,\n });\n } else if (pathname === GEMINI_LIVE_PATH) {\n handleWebSocketGeminiLive(ws, fixtures, journal, {\n ...defaults,\n model: \"gemini-2.0-flash\",\n testId: wsTestId,\n upgradeHeaders: req.headers,\n });\n }\n }\n\n // Close active WS connections when server shuts down\n const originalClose = server.close.bind(server);\n server.close = function (this: http.Server, callback?: (err?: Error) => void) {\n closeLiveSessions();\n for (const ws of activeConnections) {\n ws.close(1001, \"Server shutting down\");\n }\n activeConnections.clear();\n videoStates.clear();\n openRouterVideoJobs.clear();\n veoVideoJobs.clear();\n grokVideoJobs.clear();\n bytePlusVideoJobs.clear();\n originalClose(callback);\n return this;\n } as typeof server.close;\n\n return new Promise<ServerInstance>((resolve, reject) => {\n server.on(\"error\", reject);\n server.listen(port, host, () => {\n const addr = server.address();\n if (!addr || typeof addr === \"string\") {\n reject(new Error(\"Unexpected address format\"));\n return;\n }\n const url = `http://${addr.address}:${addr.port}`;\n\n try {\n commitHandOff();\n } catch (err) {\n server.close(() => reject(err));\n return;\n }\n\n // Set base URL on mounted services that support it\n for (const { path: mountPath, handler } of mountList) {\n if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);\n }\n\n resolve({\n closeLiveSessions,\n server,\n journal,\n url,\n defaults,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\n });\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","names":["http"],"sources":["../src/server.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n Fixture,\n FixtureFileEntry,\n ChatCompletionRequest,\n ChaosConfig,\n ChaosDefaults,\n HandlerDefaults,\n MisbehaviorScope,\n MisbehaviorConfig,\n JournalEntry,\n MockServerOptions,\n Mountable,\n RecordProviderKey,\n ResponsesToolsMode,\n} from \"./types.js\";\nimport {\n getFixtureMisbehaviorPosition,\n setFixtureMisbehaviorPosition,\n MISBEHAVIOR_CATALOG,\n WIRE_SUPPORT,\n parseMisbehavior,\n parseMisbehaviorHeader,\n resolveMisbehaviorSeed,\n planMisbehavior,\n recordMisbehaviorOutcome,\n resolveMisbehaviorShortCircuit,\n} from \"./misbehavior.js\";\nimport { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport {\n validateFixtures,\n entryToFixture,\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n queueOneShotError,\n isOneShotError,\n claimOneShotError,\n clearFixtureQueue,\n releaseOneShotError,\n FixtureLoadError,\n MisbehaviorConfigError,\n enableHeldFixtureMisbehavior,\n markFixtureResponsesToolsExtended,\n responsesToolsExtendedView,\n responsesToolsViewSource,\n} from \"./fixture-loader.js\";\nimport { writeSSEStream, writeErrorResponse } from \"./sse-writer.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport {\n prepareOpenAIChatMisbehavior,\n resolveOpenAIChatMisbehaviorUsage,\n buildOpenAIRefusalChunks,\n buildOpenAIRefusalCompletion,\n buildOpenAIContentFilterChunks,\n buildOpenAIContentFilterCompletion,\n buildOpenAIReasoningChunks,\n buildOpenAIReasoningCompletion,\n buildTextChunks,\n buildToolCallChunks,\n buildTextCompletion,\n buildToolCallCompletion,\n buildContentWithToolCallsChunks,\n buildContentWithToolCallsCompletion,\n buildUsageChunk,\n resolveUsage,\n resolveFixtureBlockOutcome,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isCombinedFixtureResponse,\n isErrorResponse,\n serializeErrorResponse,\n isAudioResponse,\n isResponseFactory,\n isVideoResponse,\n isTranscriptionResponse,\n isImageResponse,\n isEmbeddingResponse,\n isJSONResponse,\n flattenHeaders,\n isJsonObject,\n validateToolsField,\n getTestId,\n resolveTestId,\n readBody,\n readBodyBufferBounded,\n RequestBodyTooLargeError,\n fixtureToolCallErrorCode,\n googleFixtureToolCallErrorDetails,\n isFixtureToolCallError,\n requireServedFunctionToolCalls,\n requireEmittedFunctionToolCalls,\n resolveRequestId,\n markMintedRequestId,\n resolveResponse,\n resolveStrictMode,\n wouldProxyMiss,\n resolveReasoningForModel,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n runWithToolArgumentsScope,\n createServerFixtureList,\n isExtendedResponsesToolsList,\n isServerOwnedFixtures,\n withoutResponsesToolKeys,\n getContext,\n describeMatch,\n} from \"./helpers.js\";\nimport { DEFAULT_TEST_ID } from \"./constants.js\";\nimport {\n isOpenRouterPath,\n buildOpenRouterCandidates,\n resolveOpenRouterShaping,\n shapeOpenRouterCompletion,\n shapeOpenRouterChunks,\n serializeOpenRouterError,\n handleOpenRouterModels,\n handleOpenRouterKey,\n handleOpenRouterCredits,\n} from \"./openrouter-chat.js\";\nimport type {\n FixtureResponse,\n ErrorResponse,\n ChatCompletion,\n SSEChunk,\n ResponseOverrides,\n} from \"./types.js\";\nimport { handleResponses } from \"./responses.js\";\nimport { handleMessages } from \"./messages.js\";\nimport { handleGemini } from \"./gemini.js\";\nimport { handleGeminiEmbedContent } from \"./gemini-embeddings.js\";\nimport { handleBedrock, handleBedrockStream } from \"./bedrock.js\";\nimport { handleConverse, handleConverseStream } from \"./bedrock-converse.js\";\nimport {\n handleGeminiInteractions,\n resetInteractionCounter,\n resetEventIdCounter,\n} from \"./gemini-interactions.js\";\nimport { handleEmbeddings } from \"./embeddings.js\";\nimport { handleImages, handleImageEdit, handleImageVariations } from \"./images.js\";\nimport { handleSpeech } from \"./speech.js\";\nimport { handleTranscription } from \"./transcription.js\";\nimport { handleVideoCreate, VideoStateMap } from \"./video.js\";\nimport {\n handleOpenRouterVideoCreate,\n handleOpenRouterVideoStatus,\n handleOpenRouterVideoContent,\n handleOpenRouterVideoModels,\n OpenRouterVideoJobMap,\n OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES,\n} from \"./openrouter-video.js\";\nimport { handleVeoVideoCreate, handleVeoVideoStatus, VeoVideoJobMap } from \"./veo-video.js\";\nimport { handleGrokVideoCreate, handleGrokVideoStatus, GrokVideoJobMap } from \"./grok-video.js\";\nimport {\n handleBytePlusVideoCreate,\n handleBytePlusVideoStatus,\n BytePlusVideoJobMap,\n} from \"./byteplus-video.js\";\nimport { handleElevenLabsAudio, handleElevenLabsTTS } from \"./elevenlabs-audio.js\";\nimport {\n handleElevenLabsVoiceDesign,\n handleElevenLabsVoiceCreate,\n handleElevenLabsVoiceGet,\n handleElevenLabsVoiceDelete,\n clearElevenLabsVoices,\n} from \"./elevenlabs-voice.js\";\nimport { handleFalQueue, falJobs } from \"./fal-audio.js\";\nimport { handleFal, falQueueStates, falWillHandle } from \"./fal.js\";\nimport { handleOllama, handleOllamaGenerate, handleOllamaEmbeddings } from \"./ollama.js\";\nimport { handleCohere, handleCohereEmbed } from \"./cohere.js\";\nimport { handleSearch, type SearchFixture } from \"./search.js\";\nimport { handleRerank, type RerankFixture } from \"./rerank.js\";\nimport { handleModeration, type ModerationFixture } from \"./moderation.js\";\nimport {\n handleBatchesCreate,\n handleBatchesList,\n handleBatchesRetrieve,\n handleBatchesCancel,\n clearBatchStore,\n} from \"./batches.js\";\nimport {\n handleFilesCreate,\n handleFilesList,\n handleFilesRetrieve,\n handleFilesContent,\n handleFilesDelete,\n clearFileStore,\n FILES_BODY_DRAIN_MAX_BYTES,\n FILES_BODY_MAX_BYTES,\n FILES_BODY_OVERSIZED,\n} from \"./files.js\";\nimport {\n handleFineTuningCreate,\n handleFineTuningList,\n handleFineTuningRetrieve,\n handleFineTuningCancel,\n handleFineTuningEvents,\n clearFineTuningStore,\n} from \"./fine-tuning.js\";\nimport {\n handleVectorStoresCreate,\n handleVectorStoresList,\n handleVectorStoresRetrieve,\n handleVectorStoresModify,\n handleVectorStoresDelete,\n handleVectorStoreFilesCreate,\n handleVectorStoreFilesList,\n handleVectorStoreFilesRetrieve,\n handleVectorStoreFilesDelete,\n handleVectorFileBatchesCreate,\n handleVectorFileBatchesRetrieve,\n handleVectorFileBatchesCancel,\n handleVectorFileBatchesFiles,\n handleVectorStoresSearch,\n clearVectorStoreStore,\n} from \"./vector-stores.js\";\nimport { upgradeToWebSocket, type WebSocketConnection } from \"./ws-framing.js\";\nimport { handleLiveSession } from \"./ws-live.js\";\nimport { normalizeLiveOptions } from \"./live-fixture.js\";\nimport { handleWebSocketResponses } from \"./ws-responses.js\";\nimport { handleWebSocketRealtime } from \"./ws-realtime.js\";\nimport { handleWebSocketGeminiLive } from \"./ws-gemini-live.js\";\nimport { Logger } from \"./logger.js\";\nimport {\n applyChaosAction,\n awaitChaosLatency,\n describeUnwritableReason,\n evaluateChaos,\n responseGoneReason,\n isChaosScope,\n resolveChaosConfig,\n resetChaosWarnings,\n parseChaosField,\n CHAOS_FIELDS,\n CHAOS_FIELD_NAMES,\n} from \"./chaos.js\";\nimport { buildOpenApiDocument, CATALOG_ROUTES } from \"./openapi.js\";\n// Route paths/patterns are the router's single source of truth — shared with\n// the machine-readable catalog (`route-registry.ts` → `openapi.ts`), so the\n// catalog cannot drift from the dispatcher. Every literal and pattern matched\n// below comes from this module: adding a surface means adding it there, and\n// `matchRouteDefinition` (used by the terminal-404 drift guard) resolves\n// against the same table the catalog is derived from.\nimport {\n BATCHES_PATH,\n BATCHES_ID_RE,\n BATCHES_CANCEL_RE,\n COMPLETIONS_PATH,\n RESPONSES_PATH,\n REALTIME_PATH,\n LIVE_PATH,\n GEMINI_LIVE_PATH,\n MESSAGES_PATH,\n EMBEDDINGS_PATH,\n COHERE_CHAT_PATH,\n COHERE_EMBED_PATH,\n SEARCH_PATH,\n RERANK_PATH,\n MODERATIONS_PATH,\n IMAGES_PATH,\n IMAGES_EDIT_PATH,\n IMAGES_VARIATIONS_PATH,\n SPEECH_PATH,\n TRANSCRIPTIONS_PATH,\n TRANSLATIONS_PATH,\n VIDEOS_PATH,\n GROK_VIDEO_SUBMIT_PATH,\n GROK_VIDEO_STATUS_RE,\n VEO_PREDICT_LRO_RE,\n VEO_OPERATION_RE,\n GEMINI_PREDICT_RE,\n ELEVENLABS_SOUND_GENERATION_PATH,\n ELEVENLABS_TTS_RE,\n ELEVENLABS_MUSIC_RE,\n ELEVENLABS_VOICE_DESIGN_PATH,\n ELEVENLABS_VOICE_CREATE_PATH,\n ELEVENLABS_VOICE_RE,\n FAL_QUEUE_SUBMIT_RE,\n FAL_QUEUE_REQUESTS_RE,\n FAL_RUN_RE,\n FAL_ROUTE_RE,\n GEMINI_INTERACTIONS_PATH,\n GEMINI_PATH_RE,\n GEMINI_EMBED_RE,\n AZURE_DEPLOYMENT_RE,\n BEDROCK_INVOKE_RE,\n BEDROCK_STREAM_RE,\n BEDROCK_CONVERSE_RE,\n BEDROCK_CONVERSE_STREAM_RE,\n VERTEX_AI_RE,\n OLLAMA_CHAT_PATH,\n OLLAMA_GENERATE_PATH,\n OLLAMA_EMBEDDINGS_PATH,\n OLLAMA_EMBED_PATH,\n OLLAMA_TAGS_PATH,\n OPENROUTER_VIDEOS_PATH,\n OPENROUTER_VIDEO_MODELS_PATH,\n OPENROUTER_MODELS_PATH,\n OPENROUTER_KEY_PATH,\n OPENROUTER_CREDITS_PATH,\n OPENROUTER_VIDEO_CONTENT_RE,\n OPENROUTER_VIDEO_STATUS_RE,\n HEALTH_PATH,\n READY_PATH,\n METRICS_PATH,\n MODELS_PATH,\n REQUESTS_PATH,\n FILES_PATH,\n FILES_ID_RE,\n FILES_CONTENT_RE,\n VECTOR_STORES_PATH,\n VECTOR_STORES_SEARCH_RE,\n VECTOR_STORES_BATCH_FILES_RE,\n VECTOR_STORES_BATCH_CANCEL_RE,\n VECTOR_STORES_BATCH_RE,\n VECTOR_STORES_FILE_RE,\n VECTOR_STORES_ID_RE,\n VECTOR_STORES_FILES_RE,\n VECTOR_STORES_FILE_BATCHES_RE,\n BYTEPLUS_VIDEO_SUBMIT_RE,\n BYTEPLUS_VIDEO_STATUS_RE,\n FINE_TUNING_JOBS_PATH,\n FINE_TUNING_ID_RE,\n FINE_TUNING_CANCEL_RE,\n FINE_TUNING_EVENTS_RE,\n CONTROL_PREFIX,\n matchRouteDefinition,\n} from \"./route-registry.js\";\nimport { createMetricsRegistry, normalizePathLabel, DESTROYED_STATUS_LABEL } from \"./metrics.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport {\n resolveInboundAuth,\n markAuthenticatedRequest,\n validateRequestApiKey,\n writeApiKeyHttpRejection,\n writeApiKeyUpgradeRejection,\n type ResolvedInboundAuth,\n} from \"./api-key-auth.js\";\nimport type { McpFakeSource } from \"./types.js\";\nimport {\n ensureFakeMount,\n findFakeMount,\n handOffMcpFakes,\n isFakeMount,\n mountConflictDetail,\n type MountList,\n} from \"./mcp-fakes-mount.js\";\nimport { handleFakesReportRoute } from \"./mcp-fakes-report.js\";\nimport { MCP_FAKES_DEFAULT_MOUNT, McpFakeStore, McpFakesAddError, blockIdOf } from \"./mcp-fakes.js\";\nimport { MCPMock } from \"./mcp-mock.js\";\nimport { build, msg, quote } from \"./message-text.js\";\n\nconst liveClosers = new WeakMap<HandlerDefaults, (testId?: string) => void>();\n\nexport interface ServerInstance {\n closeLiveSessions(testId?: string): void;\n server: http.Server;\n journal: Journal;\n url: string;\n defaults: HandlerDefaults;\n videoStates: VideoStateMap;\n openRouterVideoJobs: OpenRouterVideoJobMap;\n veoVideoJobs: VeoVideoJobMap;\n grokVideoJobs: GrokVideoJobMap;\n bytePlusVideoJobs: BytePlusVideoJobMap;\n}\n\nconst DEFAULT_CHUNK_SIZE = 20;\n\n// OpenAI-compatible endpoint suffixes for path prefix normalization.\n// Providers like BigModel (/v4/) use non-standard base URL prefixes.\n// Only includes endpoints that third-party OpenAI-compatible providers are\n// likely to serve — excludes provider-specific paths (/messages, /realtime)\n// and endpoints unlikely to appear behind non-standard prefixes\n// (/moderations, /videos, /models).\nconst COMPAT_SUFFIXES = [\n \"/chat/completions\",\n \"/embeddings\",\n \"/responses\",\n \"/audio/speech\",\n \"/audio/transcriptions\",\n \"/audio/translations\",\n \"/images/generations\",\n \"/images/edits\",\n \"/images/variations\",\n];\n\n/**\n * Normalize OpenAI-compatible paths with arbitrary prefixes.\n * Strips /openai/ prefix and rewrites paths ending in known suffixes to /v1/<suffix>.\n * Skips /v1/ (already standard) and /v2/ (Cohere convention).\n */\nfunction normalizeCompatPath(pathname: string, logger?: Logger): string {\n // Strip /openai/ prefix (Groq/OpenAI-compat alias)\n if (pathname.startsWith(\"/openai/\")) {\n pathname = pathname.slice(\"/openai\".length);\n }\n\n // Normalize arbitrary prefixes to /v1/\n if (!pathname.startsWith(\"/v1/\") && !pathname.startsWith(\"/v2/\")) {\n for (const suffix of COMPAT_SUFFIXES) {\n if (pathname.endsWith(suffix)) {\n if (logger) logger.debug(`Path normalized: ${pathname} → /v1${suffix}`);\n pathname = \"/v1\" + suffix;\n break;\n }\n }\n }\n\n return pathname;\n}\n\n// OpenRouter async video lifecycle (/api/v1/videos). Dispatch order matters:\n// content RE → models exact → status RE → submit exact. The status RE's\n// `[^/]+` segment would otherwise swallow the `models` listing path. The\n// content/status REs are shared with the route registry and metrics.ts\n// path-label normalization (imported above).\n\nconst DEFAULT_MODELS = [\n \"gpt-4\",\n \"gpt-4o\",\n \"claude-3-5-sonnet-20241022\",\n \"gemini-2.0-flash\",\n \"text-embedding-3-small\",\n];\n\nconst CORS_HEADERS: Record<string, string> = {\n \"Access-Control-Allow-Origin\": \"*\",\n // Every method the dispatcher serves: PUT is dispatched for\n // `/fal/queue/requests/{requestId}` (status/cancel/result), so a preflight\n // that omits it makes browsers refuse that call.\n \"Access-Control-Allow-Methods\": \"GET, POST, PUT, DELETE, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"*\",\n // Response headers are invisible to cross-origin JS unless exposed. The\n // journal's pagination total is a response header (the body stays a bare\n // array for back-compat), so a browser harness needs this to read it.\n \"Access-Control-Expose-Headers\": \"X-Total-Count, X-Request-Id\",\n};\n\nfunction setCorsHeaders(res: http.ServerResponse): void {\n for (const [key, value] of Object.entries(CORS_HEADERS)) {\n res.setHeader(key, value);\n }\n}\n\nfunction handleOptions(res: http.ServerResponse): void {\n setCorsHeaders(res);\n res.writeHead(204);\n res.end();\n}\n\nfunction handleNotFound(res: http.ServerResponse, message: string): void {\n setCorsHeaders(res);\n writeErrorResponse(res, 404, JSON.stringify({ error: { message, type: \"not_found\" } }));\n}\n\n// ---------------------------------------------------------------------------\n// /__aimock/* control API — used by aimock-pytest and other test harnesses\n// to manage fixtures, journal, and error injection without restarting the\n// server.\n// ---------------------------------------------------------------------------\n\n/** The complete `GET /__aimock/fixtures` query-param vocabulary; anything else 400s. */\nconst FIXTURES_PARAMS: ReadonlySet<string> = new Set([\"include\"]);\n\n/** The complete `GET /__aimock/journal` query-param vocabulary; anything else 400s. */\nconst JOURNAL_PARAMS: ReadonlySet<string> = new Set([\n \"limit\",\n \"offset\",\n \"path\",\n \"method\",\n \"status\",\n \"service\",\n \"testId\",\n \"requestId\",\n]);\n\n/**\n * The per-server state a full reset clears. `ServerInstance` structurally\n * satisfies this, so `LLMock.reset()` and the control-API full-reset route\n * share a single definition of \"everything\" instead of two lists that drift.\n */\nexport interface FullResetTargets {\n journal: Journal;\n videoStates: VideoStateMap;\n openRouterVideoJobs: OpenRouterVideoJobMap;\n veoVideoJobs: VeoVideoJobMap;\n grokVideoJobs: GrokVideoJobMap;\n bytePlusVideoJobs: BytePlusVideoJobMap;\n defaults: HandlerDefaults;\n /**\n * The server's mounts. A full reset unloads every MCP fake on them (R1, R2);\n * the entry-id counters and MCP sessions are kept.\n */\n mounts?: MountList;\n}\n\n/**\n * Perform a full reset: clear the fixtures array, the journal (entries *and*\n * per-test fixture match-counts, i.e. sequence position), the video and fal.ai\n * job/queue state, the fine-tuning store (jobs, their append-only event logs,\n * their poll counts, the create-time suffixes their model names are built from,\n * and the module's monotonic clock), the ElevenLabs Voice Design store, the\n * Gemini interaction/event-id counters, and any runtime chaos override\n * (reverting to the construction-time chaos config), then re-zero the\n * `aimock_fixtures_loaded` gauge.\n *\n * `targets` is `null` when no server is running (an in-process `reset()` before\n * `start()`). The process-global generation state is reset either way, since it\n * is not owned by any one server instance.\n *\n * Shared by `POST /__aimock/reset` (canonical), its deprecated\n * `POST /__aimock/reset/fixtures` alias, and `LLMock.reset()`.\n */\nexport function performFullReset(fixtures: Fixture[], targets: FullResetTargets | null): void {\n // Also invalidates one-shot claims parked in flight (see `clearFixtureQueue`).\n clearFixtureQueue(fixtures);\n falJobs.clear();\n falQueueStates.clear();\n clearBatchStore();\n clearElevenLabsVoices();\n clearFileStore();\n clearFineTuningStore();\n clearVectorStoreStore();\n resetInteractionCounter();\n resetEventIdCounter();\n if (!targets) return;\n liveClosers.get(targets.defaults)?.();\n targets.journal.clear();\n // Chaos warning latches are per-server state too: a suite that resets between\n // tests must see a bad static chaos value reported again, not inherit the\n // latch the previous test left armed. Scoped by the server's logger, so this\n // clears THIS server's latch and cannot re-arm a concurrent server's.\n resetChaosWarnings(targets.defaults.logger);\n // Drop any runtime chaos override installed via POST /__aimock/chaos, so the\n // server returns to the chaos configuration it was STARTED with. Reset is the\n // isolation barrier every parallel harness leans on; chaos leaking past it\n // poisons later tests with 500s that look like application bugs.\n targets.defaults.chaos = undefined;\n targets.defaults.misbehavior?.byTestId.clear();\n targets.videoStates.clear();\n targets.openRouterVideoJobs.clear();\n targets.veoVideoJobs.clear();\n targets.grokVideoJobs.clear();\n targets.bytePlusVideoJobs.clear();\n for (const { handler } of targets.mounts ?? []) handler.clearMcpFakes?.();\n if (targets.defaults.registry) {\n targets.defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n}\n\n/**\n * JSON-safe redaction for control-API inspection output. Functions (fixture\n * `predicate`s, response factories) and RegExps do not survive\n * JSON.stringify as anything useful, so they become marker strings.\n */\nfunction redactForInspection(value: unknown): unknown {\n if (typeof value === \"function\") return \"[function]\";\n if (value instanceof RegExp) return String(value);\n if (Array.isArray(value)) return value.map(redactForInspection);\n if (value !== null && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n out[key] = redactForInspection(entry);\n }\n return out;\n }\n return value;\n}\n\n/**\n * One-line kind label for a fixture response used by\n * `GET /__aimock/fixtures?include=fixtures` (e.g. \"text\", \"error\").\n * Response factories are reported as \"factory\".\n *\n * Discriminates with the same `is*Response` guards the request handlers use,\n * in the same order — NOT by inspecting keys. Every response shape extends\n * `ResponseOverrides` (`id`/`created`/`model`/`usage`), so a recorded fixture's\n * first key is usually an envelope override rather than the discriminant. The\n * audio-before-content/toolCalls order is the ORDERING CONTRACT documented on\n * `AudioResponse` in types.ts: those shapes structurally overlap.\n */\nfunction fixtureResponseKind(response: Fixture[\"response\"]): string {\n if (isResponseFactory(response)) return \"factory\";\n if (isErrorResponse(response)) return \"error\";\n if (isAudioResponse(response)) return \"audio\";\n if (isVideoResponse(response)) return \"video\";\n if (isTranscriptionResponse(response)) return \"transcription\";\n if (isImageResponse(response)) return \"image\";\n if (isEmbeddingResponse(response)) return \"embedding\";\n if (isJSONResponse(response)) return \"json\";\n if (isCombinedFixtureResponse(response)) return \"contentWithToolCalls\";\n if (isToolCallResponse(response)) return \"toolCalls\";\n if (isTextResponse(response)) return \"text\";\n return \"unknown\";\n}\n\n/**\n * The testId a journal entry was scoped under — `resolveTestId` applied to the\n * journaled headers and path, i.e. the SAME function that scoped the request\n * (fixture match-counts, chaos) when it arrived. Node folds a repeated\n * `X-Test-Id` into one string (\"a, a\") before either side sees it, and the\n * request is counted and chaos-evaluated under that folded string, so the\n * `?testId=` filter matches it verbatim too: no token-splitting here that the\n * scoping path does not also do. (Splitting on \",\" additionally broke every\n * legitimately comma-bearing id.) A raw `path.includes(\"testId=t1\")` both\n * prefix-collides with `t10` and matches unrelated params like `notTestId`.\n *\n * An MCP mount records the test id it resolved on the entry (I9, B3): a\n * decoded header or query value, or the one bound to the session at\n * `initialize`. That value wins; LLM entries carry none and are attributed as\n * before.\n */\nfunction journalEntryTestId(entry: JournalEntry): string {\n return entry.testId ?? resolveTestId(entry.headers, entry.path);\n}\n\n/**\n * The testId a chaos override is stored under, and read back with — resolved by\n * `getTestId`, i.e. `X-Test-Id` header then `?testId=`, exactly as\n * `resolveScopedDefaults` resolves the traffic being evaluated. A control call\n * and the requests it is meant to affect can then never land in different\n * scopes. `DEFAULT_TEST_ID` (neither header nor param) means the server-wide\n * baseline.\n *\n * Returns `null` when `X-Test-Id` is PRESENT but blank. `String(testId ?? \"\")`\n * in a harness produces that trivially, and silently treating it as \"untagged\"\n * would install a server-wide baseline that fails every other test — the exact\n * cross-test leak per-testId scoping exists to prevent. Callers must 400.\n */\nfunction chaosScopeId(req: http.IncomingMessage): string | null {\n const headerValue = req.headers[\"x-test-id\"];\n const raw = Array.isArray(headerValue) ? headerValue[0] : headerValue;\n if (typeof raw === \"string\" && raw.trim() === \"\") return null;\n return getTestId(req);\n}\n\n/** 400 for a control call whose `X-Test-Id` is present but blank. */\nfunction writeBlankTestId(res: http.ServerResponse): true {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'X-Test-Id': header is present but empty\" }));\n return true;\n}\n\n/**\n * The chaos config in effect for one testId: its override, else the baseline —\n * one or the other, never the two merged. Mirrors `resolveScopedDefaults` in\n * chaos.ts, so what `GET /__aimock/chaos` reports for a scope is exactly what\n * that scope's traffic is evaluated against.\n */\nfunction effectiveChaos(defaults: HandlerDefaults, scopeId: string): ChaosConfig {\n // `has`, not truthiness — an installed-but-empty override is a selection (see\n // `resolveScopedDefaults`), so it must shadow the baseline here too or `GET`\n // would report a config the traffic is not evaluated against.\n if (defaults.chaosByTestId?.has(scopeId)) return defaults.chaosByTestId.get(scopeId) ?? {};\n const current = defaults.chaos;\n if (!current) return {};\n return isChaosScope(current) ? (current.base ?? {}) : current;\n}\n\n/** The `GET /__aimock/mcp/fakes` query-param vocabulary; anything else 400s. */\nconst MCP_FAKES_PARAMS = new Set([\"testId\", \"context\", \"mount\"]);\n\n/** A block's `mount` path, read without running getters; the add validates it. */\nfunction controlFakeMountOf(raw: unknown): string {\n if (typeof raw !== \"object\" || raw === null) return MCP_FAKES_DEFAULT_MOUNT;\n const value: unknown = Object.getOwnPropertyDescriptor(raw, \"mount\")?.value;\n return typeof value === \"string\" ? value : MCP_FAKES_DEFAULT_MOUNT;\n}\n\n/** The blocks of one control-API `mcpFakes` value that go to one mount path. */\ninterface ControlFakeGroup {\n path: string;\n /** Position of each block in the request's `mcpFakes` value. */\n positions: number[];\n sources: McpFakeSource[];\n}\n\n/** What the after-start auto-mount of a control-API add is wired with (W6, as W4). */\ninterface ControlFakeWiring {\n journal: Journal;\n defaults: HandlerDefaults;\n}\n\n/**\n * Check one `POST /__aimock/fixtures` `mcpFakes` value against the live\n * mounts (F10, W6) without changing anything. Returns every error in input\n * order (an empty list when the value can be added), and `apply`, which adds\n * the blocks (auto-mounting an MCPMock where no mount serves a block's path)\n * and returns the number of blocks added.\n *\n * The whole value is checked before any mount is touched, and the check\n * never adds to a real mount: each group is added to a throwaway store,\n * whose errors are the ones reported (it numbers the add `control-api#1`, as\n * a new mount would; for an existing MCPMock the rejected group is re-run on\n * its atomic add, so the errors name that mount's next `<n>`, I7). A group\n * whose path no request to it can reach (a mount that is not an MCPMock\n * serves it, an MCPMock answers it as its root, or it is under the control\n * prefix) is a mount conflict (one error per block).\n */\nfunction planControlApiFakes(\n raw: unknown,\n mounts: MountList,\n): { errors: FixtureLoadError[]; apply(wiring: ControlFakeWiring): number } {\n const items: Array<{ position: number; source: McpFakeSource }> = Array.isArray(raw)\n ? raw.map((block: unknown, position) => ({\n position,\n source: { source: \"control-api\", blockIndex: position, raw: block },\n }))\n : [{ position: 0, source: { source: \"control-api\", blockIndex: null, raw } }];\n\n const groups = new Map<string, ControlFakeGroup>();\n // An empty `mcpFakes` array is one (bad) add to the default mount.\n if (items.length === 0) {\n groups.set(MCP_FAKES_DEFAULT_MOUNT, {\n path: MCP_FAKES_DEFAULT_MOUNT,\n positions: [],\n sources: [],\n });\n }\n for (const { position, source } of items) {\n const path = controlFakeMountOf(source.raw);\n const group = groups.get(path) ?? { path, positions: [], sources: [] };\n group.positions.push(position);\n group.sources.push(source);\n groups.set(path, group);\n }\n\n const found: Array<{ position: number; error: FixtureLoadError }> = [];\n /** The paths `apply` auto-mounts, in order. */\n const pending: string[] = [];\n for (const group of groups.values()) {\n const target = findFakeMount(mounts, group.path, pending);\n if (target.kind === \"conflict\") {\n group.positions.forEach((position) => {\n const where = Array.isArray(raw) ? msg`mcpFakes[${position}]` : msg`mcpFakes`;\n found.push({\n position,\n error: new FixtureLoadError({\n rule: \"mcp-fakes/mount-conflict\",\n file: null,\n blockId: null,\n entryId: null,\n detail: msg`${where}: ${mountConflictDetail(group.path, target)}`,\n }),\n });\n });\n continue;\n }\n let failure = addFailure(() => new McpFakeStore().add(group.sources, { kind: \"control-api\" }));\n if (target.kind === \"none\") pending.push(group.path);\n if (!failure) continue;\n // The throwaway numbers the add `control-api#1`; an existing MCPMock's\n // errors must name its own next `<n>` (I7). Its add is atomic (a throw\n // adds nothing and consumes no `<n>`), so the same rejected input is\n // re-run on it for the numbered errors. A mount with any other add is\n // never called here (A2).\n if (target.kind === \"mcp\" && target.handler.addMcpFakes === MCPMock.prototype.addMcpFakes) {\n const handler = target.handler;\n failure =\n addFailure(() => handler.addMcpFakes?.(group.sources, { kind: \"control-api\" })) ?? failure;\n }\n for (const error of failure.errors) {\n found.push({ position: positionOf(error, group), error });\n }\n }\n found.sort((a, b) => a.position - b.position);\n\n return {\n errors: found.map((f) => f.error),\n apply(wiring: ControlFakeWiring): number {\n let added = 0;\n for (const group of groups.values()) {\n const target = ensureFakeMount(\n mounts,\n group.path,\n {\n journal: wiring.journal,\n registry: wiring.defaults.registry,\n logger: wiring.defaults.logger,\n replaySpeed: wiring.defaults.replaySpeed,\n },\n wiring.defaults.logger,\n );\n // The plan found no conflict, and nothing else runs in between.\n if (\"conflict\" in target) continue;\n const result = target.handler.addMcpFakes?.(group.sources, { kind: \"control-api\" });\n for (const warning of result?.warnings ?? []) wiring.defaults.logger.warn(warning.message);\n added += group.sources.length;\n }\n return added;\n },\n };\n}\n\n/** The `McpFakesAddError` that `add` throws, or `null` when it adds. */\nfunction addFailure(add: () => unknown): McpFakesAddError | null {\n try {\n add();\n return null;\n } catch (err) {\n if (err instanceof McpFakesAddError) return err;\n throw err;\n }\n}\n\n/**\n * The request position of the block an add error names. The add numbers a\n * run-time group's blocks by their place in the group (`[<j>]`), or gives no\n * index to a single-object value; an error tied to no block sorts with the\n * group's first block.\n */\nfunction positionOf(error: FixtureLoadError, group: ControlFakeGroup): number {\n const first = group.positions[0] ?? 0;\n if (error.blockId == null || error.file === null) return first;\n const at = group.positions.findIndex(\n (_, j) => error.blockId === blockIdOf(error.file ?? \"\", \"\", j),\n );\n return at === -1 ? first : group.positions[at];\n}\n\n/** The listing half of an MCP mount, as `MCPMock` has it. */\ninterface FakesSnapshotSource {\n fakesSnapshot: MCPMock[\"fakesSnapshot\"];\n}\n\nfunction hasFakesSnapshot(handler: Mountable): handler is Mountable & FakesSnapshotSource {\n return \"fakesSnapshot\" in handler && typeof handler.fakesSnapshot === \"function\";\n}\n\n/**\n * `GET /__aimock/mcp/fakes` (spec 6.5, I9): for each MCP mount (or the one\n * named by `mount`), the blocks that apply to the requested test id and\n * context, with every entry id and its consumed state for that test id.\n * A mount is listed when it takes fakes (it implements `addMcpFakes`, the\n * check every other fakes path uses); one with no `fakesSnapshot` lists no\n * blocks.\n */\nfunction listControlApiFakes(\n mounts: MountList,\n testId: string | null,\n context: string | null,\n mount: string | null,\n): Array<{ mount: string; blocks: ReturnType<MCPMock[\"fakesSnapshot\"]> }> | null {\n const listed = mounts.flatMap(({ path, handler }) =>\n isFakeMount(handler) && (mount === null || path === mount)\n ? [\n {\n mount: path,\n blocks: hasFakesSnapshot(handler) ? handler.fakesSnapshot(testId, context) : [],\n },\n ]\n : [],\n );\n return mount !== null && listed.length === 0 ? null : listed;\n}\n\n// Per-server addition identities survive fixture deletion and full resets.\nconst controlFixtureAdditions = new WeakMap<HandlerDefaults, number>();\n\n/**\n * Handle requests under `/__aimock/`. Returns `true` if the request was\n * handled, `false` if the path doesn't match the control prefix.\n */\nasync function handleControlAPI(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n searchParams: URLSearchParams,\n fixtures: Fixture[],\n journal: Journal,\n videoStates: VideoStateMap,\n openRouterVideoJobs: OpenRouterVideoJobMap,\n veoVideoJobs: VeoVideoJobMap,\n grokVideoJobs: GrokVideoJobMap,\n bytePlusVideoJobs: BytePlusVideoJobMap,\n defaults: HandlerDefaults,\n mounts: MountList,\n): Promise<boolean> {\n if (!pathname.startsWith(CONTROL_PREFIX)) return false;\n\n const subPath = pathname.slice(CONTROL_PREFIX.length);\n setCorsHeaders(res);\n\n // GET /__aimock/health\n if (subPath === \"/health\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n return true;\n }\n\n // GET /__aimock/openapi.json — machine-readable route catalog.\n if (subPath === \"/openapi.json\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(buildOpenApiDocument()));\n return true;\n }\n\n // GET /__aimock/routes — flat method+path list for shells.\n if (subPath === \"/routes\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ count: CATALOG_ROUTES.length, routes: CATALOG_ROUTES }));\n return true;\n }\n\n // GET /__aimock/journal — optionally filtered/paginated.\n // No query params → full array (historical behaviour, unchanged).\n // Supported params: limit (int >= 0), offset (int >= 0, default 0),\n // path (SUBSTRING), method (exact, case-insensitive), status (int),\n // service (EXACT), testId (resolved exactly as the server resolves it).\n // Anything else is a 400: silently ignoring an unknown param would let\n // `?statusCode=404` return the whole journal and pass a caller's assertion\n // against traffic it never meant to select.\n if (subPath === \"/journal\" && req.method === \"GET\") {\n const bad = (message: string): true => {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: message }));\n return true;\n };\n for (const key of searchParams.keys()) {\n if (!JOURNAL_PARAMS.has(key)) {\n return bad(\n `Unknown query parameter: '${key}'. Supported: ${[...JOURNAL_PARAMS].join(\", \")}`,\n );\n }\n }\n const parseNonNegativeInt = (name: string, fallback: number): number | null => {\n const raw = searchParams.get(name);\n if (raw === null) return fallback;\n if (!/^\\d+$/.test(raw.trim())) return null;\n return Number(raw);\n };\n const limit = parseNonNegativeInt(\"limit\", -1);\n const offset = parseNonNegativeInt(\"offset\", 0);\n if (limit === null) return bad(\"Invalid 'limit': must be an integer >= 0\");\n if (offset === null) return bad(\"Invalid 'offset': must be an integer >= 0\");\n let statusFilter: number | undefined;\n const statusRaw = searchParams.get(\"status\");\n if (statusRaw !== null) {\n if (!/^\\d+$/.test(statusRaw.trim())) return bad(\"Invalid 'status': must be an integer\");\n statusFilter = Number(statusRaw);\n }\n const pathFilter = searchParams.get(\"path\");\n const methodFilter = searchParams.get(\"method\");\n const serviceFilter = searchParams.get(\"service\");\n const testIdFilter = searchParams.get(\"testId\");\n const requestIdFilter = searchParams.get(\"requestId\");\n\n let entries: JournalEntry[] = journal.getAll();\n if (methodFilter !== null) {\n const want = methodFilter.toUpperCase();\n entries = entries.filter((e) => e.method.toUpperCase() === want);\n }\n if (pathFilter !== null) {\n entries = entries.filter((e) => e.path.includes(pathFilter));\n }\n if (statusFilter !== undefined) {\n entries = entries.filter((e) => e.response.status === statusFilter);\n }\n if (serviceFilter !== null) {\n entries = entries.filter((e) => e.service === serviceFilter);\n }\n if (testIdFilter !== null) {\n entries = entries.filter((e) => journalEntryTestId(e) === testIdFilter);\n }\n if (requestIdFilter !== null) {\n entries = entries.filter((e) => e.headers[\"x-request-id\"] === requestIdFilter);\n }\n // Count AFTER filtering but BEFORE pagination, so a paging caller can tell\n // when it is done. It ships as a header because the body is a bare array\n // for back-compat and can never grow an envelope.\n const total = entries.length;\n if (offset > 0) entries = entries.slice(offset);\n if (limit >= 0) entries = entries.slice(0, limit);\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"X-Total-Count\": String(total),\n });\n res.end(journalJson(entries, journal));\n return true;\n }\n\n // GET /__aimock/fixtures — inspect current fixture count. With\n // ?include=fixtures, also dump each fixture's (redacted) match criteria\n // and response kind so harnesses can assert what would match.\n if (subPath === \"/fixtures\" && req.method === \"GET\") {\n // Unknown params 400 for the same reason `/journal` does: a typo like\n // `?incluide=fixtures` must never quietly return the count-only body and\n // pass an assertion against a dump the caller never received.\n for (const key of searchParams.keys()) {\n if (!FIXTURES_PARAMS.has(key)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Unknown query parameter: '${key}'. Supported: ${[...FIXTURES_PARAMS].join(\", \")}`,\n }),\n );\n return true;\n }\n }\n const include = searchParams.get(\"include\");\n if (include === null) {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ count: fixtures.length }));\n return true;\n }\n if (include !== \"fixtures\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'include': expected 'fixtures'\" }));\n return true;\n }\n // Only a server with responsesTools \"extended\" reads `match.toolNamespace`,\n // `customToolCalls` and `responsesBlocks`; elsewhere they do not change\n // the kind, as in 1.44.0.\n const extendedTools = isExtendedResponsesToolsList(fixtures);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n count: fixtures.length,\n fixtures: fixtures.map((fixture, index) => ({\n index,\n match: redactForInspection(fixture.match),\n // NOT `response` — that name already means the response ITSELF on\n // `Fixture`, and this is only a one-word kind label. A queued\n // one-shot error carries a FACTORY response (the factory performs\n // the idempotent claim), so the shape test alone reports \"factory\"\n // and this surface loses the one signal it exists to give: that an\n // injection is armed. Take the kind from the one-shot MARKER.\n responseKind: isOneShotError(fixture)\n ? \"error\"\n : fixtureResponseKind(\n extendedTools || typeof fixture.response === \"function\"\n ? fixture.response\n : withoutResponsesToolKeys(fixture.response),\n ),\n ...(fixture.latency !== undefined ? { latency: fixture.latency } : {}),\n ...(fixture.chaos !== undefined ? { chaos: fixture.chaos } : {}),\n })),\n }),\n );\n return true;\n }\n\n if (subPath === \"/misbehavior/catalog\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ catalog: MISBEHAVIOR_CATALOG, WIRE_SUPPORT }));\n return true;\n }\n\n if (\n subPath === \"/misbehavior\" &&\n (req.method === \"GET\" || req.method === \"POST\" || req.method === \"DELETE\")\n ) {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n const reply = (status: number, body: unknown): true => {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return true;\n };\n const scope = defaults.misbehavior;\n if (!scope && req.method !== \"GET\") {\n return reply(409, {\n error:\n \"misbehavior is not enabled: start aimock with enableMisbehavior: true (CLI: --misbehavior)\",\n });\n }\n if (req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/misbehavior: failed to read body: ${msg}`);\n return reply(400, { error: `Failed to read request body: ${msg}` });\n }\n let input: unknown;\n try {\n input = JSON.parse(raw);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/misbehavior: invalid JSON: ${msg}`);\n return reply(400, { error: `Invalid JSON: ${msg}` });\n }\n // Only this route treats an empty object as an explicit opt-out.\n if (isJsonObject(input) && Object.keys(input).length === 0) input = { faults: [] };\n const parsed = parseMisbehavior(input);\n if (!parsed.ok) {\n return reply(400, {\n error: \"Validation failed\",\n rule: parsed.issue.rule,\n message: parsed.issue.message,\n });\n }\n const config =\n parsed.config.seed === \"random\"\n ? { ...parsed.config, seed: resolveMisbehaviorSeed(parsed.config.seed, defaults.logger) }\n : parsed.config;\n scope?.byTestId.set(scopeId, config);\n } else if (req.method === \"DELETE\") {\n scope?.byTestId.delete(scopeId);\n }\n return reply(200, {\n misbehavior: scope?.byTestId.get(scopeId) ?? scope?.baseline ?? { faults: [] },\n });\n }\n\n // GET /__aimock/chaos — read the chaos config in effect for THIS caller's\n // testId: its own override if one is installed, else the server-wide\n // baseline (the construction config, or an untagged override).\n if (subPath === \"/chaos\" && req.method === \"GET\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // DELETE /__aimock/chaos — drop the override for this caller's testId (or the\n // server-wide baseline when untagged), falling back to what it shadowed.\n // `POST {}` means \"explicitly no chaos\"; this means \"forget I said anything\".\n //\n // SYMMETRIC with POST: an untagged DELETE drops the untagged baseline ONLY.\n // Dropping every per-testId override too would let one test's cleanup revoke\n // a concurrently-running test's opt-out. `POST /__aimock/reset` is the one\n // route that clears everything.\n if (subPath === \"/chaos\" && req.method === \"DELETE\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n defaults.chaosByTestId?.delete(scopeId);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // POST /__aimock/chaos — replace the server chaos config at runtime (no\n // restart). Accepts any subset of dropRate/malformedRate/disconnectRate as\n // numbers in [0, 1]; `{}` means explicitly no chaos. Unknown fields and\n // out-of-range values are rejected with 400.\n //\n // SCOPED to the caller's testId (`X-Test-Id`, else `?testId=`), like every\n // other mutable axis in the server (fixture match-counts, video job maps): an\n // override installed by test `t1` applies only to traffic resolving to `t1`.\n // An untagged call sets the server-wide baseline. `POST /__aimock/reset`\n // drops all of it, restoring the chaos config the server was STARTED with.\n //\n // REPLACES WHOLESALE — the body is not merged over the config it shadows. A\n // server started with `--chaos-latency 500` that is sent `{ \"dropRate\": 1 }`\n // for `t1` gives `t1` drops and NO latency: restate `latencyMs` to keep it.\n // That is what makes `POST {}` (\"explicitly no chaos\") different from\n // `DELETE` (\"fall back to what I was shadowing\"); under a merge, `POST {}`\n // would be a no-op. The 200 body echoes the config actually in effect for the\n // scope, and any field that WAS in effect and is not restated is named in a\n // warning, so a dropped baseline rate is never silent.\n if (subPath === \"/chaos\" && req.method === \"POST\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/chaos: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/chaos: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid body: expected a JSON object\" }));\n return true;\n }\n // The set of fields and their bounds come from `CHAOS_FIELDS`, and each\n // value is validated by the same `parseChaosField` every other chaos source\n // uses. Re-typing the limits here is how this endpoint used to accept\n // `{ latencyMs: 250.5 }` with a 200 and echo it back from `GET`, while the\n // resolver silently discarded it at request time as a non-integer: the\n // control API reported a config the traffic never saw.\n for (const key of Object.keys(parsed)) {\n if (!(CHAOS_FIELD_NAMES as readonly string[]).includes(key)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Unknown chaos field: '${key}'` }));\n return true;\n }\n }\n const next: ChaosConfig = {};\n for (const key of CHAOS_FIELD_NAMES) {\n const value = parsed[key];\n if (value === undefined) continue;\n // JSON body: the field must be a number. A numeric STRING is a\n // client-side type error here, not a wire spelling to be parsed — the\n // header API is the surface that takes text.\n const accepted = typeof value === \"number\" ? parseChaosField(key, value) : undefined;\n if (accepted === undefined) {\n const shape = CHAOS_FIELDS[key].integer ? \"a whole number of ms\" : \"a number\";\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Invalid '${key}': must be ${shape} between 0 and ${CHAOS_FIELDS[key].max}`,\n }),\n );\n return true;\n }\n next[key] = accepted;\n }\n // The install REPLACES what was in effect for this scope; it does not merge\n // over it. Name every field that was in effect and is not restated, so a\n // baseline rate a test silently loses (the classic case: a server-wide\n // `--chaos-latency` vanishing under a scoped `{ dropRate: 1 }`) shows up in\n // the log instead of as a mystery in the timings.\n const shadowed = effectiveChaos(defaults, scopeId);\n const droppedFields = (Object.keys(shadowed) as (keyof ChaosConfig)[]).filter(\n (key) => shadowed[key] !== undefined && next[key] === undefined,\n );\n if (droppedFields.length > 0) {\n const lost = droppedFields.map((key) => `${key}=${shadowed[key]}`).join(\", \");\n defaults.logger.warn(\n `[chaos] POST /__aimock/chaos (testId '${scopeId}') replaces the chaos config for this ` +\n `scope wholesale, it is not merged: ${lost} no longer applies here. ` +\n `Restate the field in the body to keep it.`,\n );\n }\n defaults.chaosByTestId?.set(scopeId, next);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // GET /__aimock/mcp/fakes — the MCP fakes that apply to a test id/context,\n // per mount, with each entry's consumed state (spec 6.5, I9).\n if (subPath === \"/mcp/fakes\" && req.method === \"GET\") {\n const reply = (status: number, body: unknown): true => {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return true;\n };\n for (const key of searchParams.keys()) {\n if (!MCP_FAKES_PARAMS.has(key)) {\n return reply(400, {\n error: `Unknown query parameter: '${key}'. Supported: ${[...MCP_FAKES_PARAMS].join(\", \")}`,\n });\n }\n }\n // Empty values are not supplied (I1, I2).\n const testId = searchParams.get(\"testId\") || null;\n const context = searchParams.get(\"context\") || null;\n const mount = searchParams.get(\"mount\") || null;\n const listed = listControlApiFakes(mounts, testId, context, mount);\n if (listed === null) {\n return reply(404, { error: build(msg`No MCP mount at ${quote(mount ?? \"\")}`) });\n }\n return reply(200, { testId, context, mounts: listed });\n }\n\n // GET /__aimock/mcp/fakes/report — the per-test fake report (RP6).\n if (subPath === \"/mcp/fakes/report\" && req.method === \"GET\") {\n return handleFakesReportRoute(res, searchParams, mounts);\n }\n\n // POST /__aimock/fixtures — add fixtures dynamically\n if (subPath === \"/fixtures\" && req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/fixtures: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: { fixtures?: FixtureFileEntry[]; mcpFakes?: unknown } | null;\n try {\n parsed = JSON.parse(raw) as { fixtures?: FixtureFileEntry[]; mcpFakes?: unknown } | null;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/fixtures: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n\n // F10, B6: `fixtures` is optional when the body carries `mcpFakes`.\n const withFakes =\n typeof parsed === \"object\" && parsed !== null && Object.hasOwn(parsed, \"mcpFakes\");\n if (\n parsed === null ||\n (!Array.isArray(parsed.fixtures) && !(withFakes && parsed.fixtures === undefined))\n ) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: 'Missing or invalid \"fixtures\" array' }));\n return true;\n }\n const entries: FixtureFileEntry[] = Array.isArray(parsed.fixtures) ? parsed.fixtures : [];\n\n const missingMatchIndex = entries.findIndex(\n (entry) =>\n entry !== null && typeof entry === \"object\" && !Array.isArray(entry) && entry.match == null,\n );\n if (missingMatchIndex !== -1) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Fixture at index ${missingMatchIndex} is missing match` }));\n return true;\n }\n\n const invalidMatchIndex = entries.findIndex(\n (entry) =>\n entry !== null &&\n typeof entry === \"object\" &&\n !Array.isArray(entry) &&\n entry.match != null &&\n (typeof entry.match !== \"object\" || Array.isArray(entry.match)),\n );\n if (invalidMatchIndex !== -1) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({ error: `Fixture at index ${invalidMatchIndex}: match must be an object` }),\n );\n return true;\n }\n\n // An extended server changes the fixtures it makes in place only in an\n // array no other server reads (LLMock's). In a caller's array, which a\n // legacy server may share, they stay as 1.44.0 made them and this server\n // reads them through its view, as it reads the caller's own fixtures.\n const extendedResponsesTools = defaults.responsesTools === \"extended\";\n const markInPlace = extendedResponsesTools && isServerOwnedFixtures(fixtures);\n const addition = controlFixtureAdditions.get(defaults) ?? 0;\n controlFixtureAdditions.set(defaults, addition + 1);\n const converted: Fixture[] = [];\n const loadErrors: (FixtureLoadError | MisbehaviorConfigError)[] = [];\n for (const [index, entry] of entries.entries()) {\n try {\n const fixture = entryToFixture(entry, undefined, undefined, {\n file: `control-api#${addition}`,\n index,\n });\n if (defaults.misbehavior) enableHeldFixtureMisbehavior(fixture);\n if (markInPlace) markFixtureResponsesToolsExtended(fixture);\n converted.push(fixture);\n } catch (error) {\n if (!(error instanceof FixtureLoadError || error instanceof MisbehaviorConfigError)) {\n throw error;\n }\n loadErrors.push(error);\n }\n }\n // Only a fully converted batch preserves the original validation indices.\n const issues =\n loadErrors.length === 0\n ? validateFixtures(\n extendedResponsesTools ? converted.map(responsesToolsExtendedView) : converted,\n )\n : [];\n const errors = issues.filter((i) => i.severity === \"error\");\n // The whole body is checked before anything is added (W6): the LLM\n // fixtures, then every `mcpFakes` block against the live mounts.\n const fakes = withFakes ? planControlApiFakes(parsed.mcpFakes, mounts) : null;\n const fakeErrors = fakes?.errors ?? [];\n const validationFailed = (details: unknown[]): true => {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Validation failed\", details }));\n return true;\n };\n if (loadErrors.length > 0 || errors.length > 0 || fakeErrors.length > 0) {\n return validationFailed([\n ...loadErrors.map((e) => e.toJSON()),\n ...errors,\n ...fakeErrors.map((e) => e.toJSON()),\n ]);\n }\n\n let mcpFakesAdded = 0;\n if (fakes) {\n try {\n mcpFakesAdded = fakes.apply({ journal, defaults });\n } catch (err) {\n if (!(err instanceof McpFakesAddError)) throw err;\n return validationFailed(err.errors.map((e) => e.toJSON()));\n }\n }\n fixtures.push(...converted);\n if (defaults.registry) {\n defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify(\n withFakes ? { added: converted.length, mcpFakesAdded } : { added: converted.length },\n ),\n );\n return true;\n }\n\n // DELETE /__aimock/fixtures — clear all fixtures, and every MCP fake (R3)\n if (subPath === \"/fixtures\" && req.method === \"DELETE\") {\n clearFixtureQueue(fixtures);\n journal.clearMisbehaviorCounters();\n for (const { handler } of mounts) handler.clearMcpFakes?.();\n if (defaults.registry) {\n defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ cleared: true }));\n return true;\n }\n\n const resetTargets = (): FullResetTargets => ({\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\n defaults,\n mounts,\n });\n\n // POST /__aimock/reset — full reset (fixtures, journal entries + fixture\n // match-counts, video/fal job state, Gemini counters)\n if (subPath === \"/reset\" && req.method === \"POST\") {\n performFullReset(fixtures, resetTargets());\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ reset: true }));\n return true;\n }\n\n // POST /__aimock/reset/journal — clear only the request journal entries,\n // preserving fixture match-counts (sequencing state stays intact)\n if (subPath === \"/reset/journal\" && req.method === \"POST\") {\n journal.clearEntries();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ reset: true }));\n return true;\n }\n\n // POST /__aimock/reset/fixtures — DEPRECATED alias for /reset. The name\n // promises a fixtures-only reset but it always performed the full reset;\n // /reset is the honest route. Behaviour is unchanged for existing callers.\n if (subPath === \"/reset/fixtures\" && req.method === \"POST\") {\n performFullReset(fixtures, resetTargets());\n const deprecation =\n \"POST /__aimock/reset/fixtures is deprecated; use POST /__aimock/reset (full reset) or POST /__aimock/reset/journal (journal only)\";\n defaults.logger.warn(\n \"POST /__aimock/reset/fixtures is deprecated; use /__aimock/reset or /__aimock/reset/journal\",\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\", Deprecation: \"true\" });\n res.end(JSON.stringify({ reset: true, deprecated: true, deprecation }));\n return true;\n }\n\n // POST /__aimock/error — queue a one-shot error\n if (subPath === \"/error\" && req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/error: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: { status?: number; body?: { message?: string; type?: string; code?: string } };\n try {\n parsed = JSON.parse(raw) as typeof parsed;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/error: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n\n // Validate the payload — an unchecked `status` reaches\n // `res.writeHead(status)` on the next matched request and throws\n // ERR_HTTP_INVALID_STATUS_CODE for 99, 0, 1000 or 99.5, losing the\n // injected error and degrading to a generic 500.\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid body: expected a JSON object\" }));\n return true;\n }\n // Omitted — or an explicit null, which is how a serializer spells an absent\n // optional — keeps the historic default of 500.\n const status = parsed.status ?? 500;\n if (!isInjectableStatus(status)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid 'status': must be ${INJECTED_STATUS_RANGE}` }));\n return true;\n }\n const errorBody = parsed.body;\n // `body: null` is an absent body, not a malformed one — same rule as the\n // fields below and as `status`. Rejecting it broke a call that worked\n // (main defaulted every field) for a shape any serializer emits for an\n // unset optional.\n if (errorBody !== undefined && errorBody !== null) {\n if (typeof errorBody !== \"object\" || Array.isArray(errorBody)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'body': must be an object\" }));\n return true;\n }\n for (const field of [\"message\", \"type\", \"code\"] as const) {\n const value = errorBody[field];\n // null means absent, not invalid: aimock's own error envelope\n // (`serializeErrorResponse`) emits `code: null`, and so does a real\n // OpenAI error, so a captured body can be pasted back verbatim.\n if (value !== undefined && value !== null && typeof value !== \"string\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid 'body.${field}': must be a string` }));\n return true;\n }\n }\n }\n // Shared with `LLMock.nextRequestError`: same endpoint gate, consumed when\n // served rather than when its predicate is evaluated.\n queueOneShotError(fixtures, status, errorBody ?? undefined);\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ queued: true }));\n return true;\n }\n\n // Unknown control path\n handleNotFound(res, `Unknown control endpoint: ${pathname}`);\n return true;\n}\n\n/**\n * The client tore the connection down before its request body had fully\n * arrived. Node rejects the pending body read with `aborted` (ECONNRESET) and\n * destroys the response, so the rejection surfaces in the handler's read arm\n * looking like any other thrown error. It is caller behaviour, not a server\n * fault: no status can reach the client, so none must be journaled as\n * delivered. A body that blew its size cap also leaves the request destroyed\n * and incomplete, but that one is aimock's own decision, not a peer abort.\n */\nfunction clientAbortedMidBody(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n err: unknown,\n): boolean {\n if (err instanceof RequestBodyTooLargeError) return false;\n return res.destroyed && !req.complete;\n}\n\nasync function handleCompletions(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n getRequestEntry: () => JournalEntry | null,\n modelFallback?: string,\n providerKey?: RecordProviderKey,\n openRouter = false,\n beforeFixtureSelection?: () => void,\n bytePlusPath = false,\n): Promise<void> {\n setCorsHeaders(res);\n // Named in fixture tool-call rejections, so the message says which door the\n // request came through. The BytePlus door is the `/api/v3/` path itself\n // (`bytePlusPath`), not the record-gated `providerKey`, so a replay-only\n // request is named the same as a recording one.\n const wire =\n providerKey === \"azure\"\n ? \"Azure OpenAI Chat Completions\"\n : providerKey === \"openrouter\"\n ? \"OpenRouter Chat Completions\"\n : providerKey === \"byteplus\" || bytePlusPath\n ? \"BytePlus ModelArk Chat Completions\"\n : \"OpenAI Chat Completions\";\n\n // Read request body\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"Failed to read request body\";\n // Same classification every `routeError` route applies to this failure: a\n // body that blew its size cap is the CALLER's fault, logged at warn.\n // If the reader destroyed the socket, no status was delivered.\n // This arm catches the read itself\n // rather than letting it reach `routeError`, so it has to say so on its\n // own — and it logs either way, because a read failure answered in\n // silence is a request that vanishes from the logs.\n const clientFault = err instanceof RequestBodyTooLargeError;\n const route = `${req.method ?? \"POST\"} ${req.url ?? COMPLETIONS_PATH}`;\n const clientAbort = clientAbortedMidBody(req, res, err);\n const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);\n if (clientAbort || bodyLimitDisconnect) {\n // The body reader or caller destroyed the socket: nothing can be\n // delivered and nothing crashed. Journal the torn socket the way the proxy arm\n // and chaos `disconnect` do, never a status the client did not get.\n const interruptReason = bodyLimitDisconnect\n ? \"request body exceeded size limit\"\n : \"client aborted\";\n defaults.logger.warn(\n bodyLimitDisconnect ? `${route}: ${msg}` : `${route}: client aborted mid-body (${msg})`,\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status: 0,\n fixture: null,\n interrupted: true,\n interruptReason,\n },\n });\n return;\n }\n const status = clientFault ? 400 : 500;\n if (clientFault) defaults.logger.warn(`${route}: ${msg}`);\n else defaults.logger.error(`${route}: ${msg}`);\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status, fixture: null },\n });\n writeErrorResponse(\n res,\n status,\n openRouter\n ? serializeOpenRouterError(status, `Request body read failed: ${msg}`)\n : JSON.stringify({\n error: {\n message: `Request body read failed: ${msg}`,\n type: clientFault ? \"invalid_request_error\" : \"server_error\",\n },\n }),\n );\n return;\n }\n\n // Parse JSON body\n let body: ChatCompletionRequest;\n try {\n body = JSON.parse(raw) as ChatCompletionRequest;\n } catch (parseErr: unknown) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown parse error\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, `Malformed JSON: ${detail}`)\n : JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n param: null,\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `body.messages` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(body)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, \"Request body must be a JSON object\")\n : JSON.stringify({\n error: {\n message: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Azure deployments may omit model from body — use deployment ID as fallback\n if (modelFallback && !body.model) {\n body.model = modelFallback;\n }\n\n // Validate messages array\n if (!Array.isArray(body.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, \"Missing required parameter: 'messages'\")\n : JSON.stringify({\n error: {\n message: \"Missing required parameter: 'messages'\",\n type: \"invalid_request_error\",\n param: null,\n code: null,\n },\n }),\n );\n return;\n }\n\n const nullMessageIndex = body.messages.findIndex((message) => message === null);\n if (nullMessageIndex !== -1) {\n const message = `Invalid request: messages[${nullMessageIndex}] must be an object`;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, message)\n : JSON.stringify({\n error: {\n message,\n type: \"invalid_request_error\",\n param: null,\n code: null,\n },\n }),\n );\n return;\n }\n\n // Only native OpenAI ingress applies this shape rule; compatible routes\n // retain their own tool conventions. Missing-function shorthand stays valid.\n if (new URL(req.url ?? COMPLETIONS_PATH, \"http://localhost\").pathname === COMPLETIONS_PATH) {\n let toolsError = validateToolsField(body.tools);\n if (!toolsError && Array.isArray(body.tools)) {\n const nullFunctionIndex = body.tools.findIndex((tool) => tool?.function === null);\n if (nullFunctionIndex !== -1) {\n toolsError = `tools[${nullFunctionIndex}].function must not be null`;\n }\n }\n if (toolsError) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({ error: { message: toolsError, type: \"invalid_request_error\" } }),\n );\n return;\n }\n }\n\n const method = req.method ?? \"POST\";\n const path = req.url ?? COMPLETIONS_PATH;\n const flatHeaders = flattenHeaders(req.headers);\n\n // Set endpoint type once early so router/recorder and journal see it\n body._endpointType = \"chat\";\n body._context = getContext(req);\n\n // Match fixture first — chaos resolution depends on fixture-level overrides\n // (headers > fixture.chaos > server defaults), so the fixture has to be\n // known before we can roll with the right config.\n const testId = getTestId(req);\n const matchOptions = recordMatchOptions(\n // In record mode a miss proxies upstream to capture a fresh turn, so an\n // earlier-turn capture must not shadow a longer request via the relaxed\n // turnIndex disambiguator — keep turnIndex a strict gate while recording.\n // This handler's record gate (below) is `defaults.record && providerKey`.\n !!(defaults.record && providerKey),\n defaults.logger,\n );\n\n // OpenRouter `models[]` fallback simulation. When the request arrived on the\n // OpenRouter base AND carries a fallback array, attempt the candidate list\n // `[model, ...models]` in order and serve the FIRST non-error fixture match\n // — an ERROR-fixture candidate simulates a RUNTIME provider failure (429/503)\n // and falls through, exactly as real OpenRouter fails over on a runtime\n // error. The winning slug is echoed back as the response `model` (the only\n // fallback signal a real client sees). `preResolvedResponse` is the winner's\n // already-resolved response so the shared branch below does not re-resolve\n // (and thus does not re-invoke a response factory). Requests without a\n // fallback array take the ordinary single-model match path unchanged.\n //\n // Deliberate non-goal (mock vs real): real OpenRouter rejects an\n // unknown/invalid model in `models[]` up front with a 400 \"not a valid model\n // ID\" and does NOT fail over from it (failover is runtime-error only). aimock\n // is fixture-driven — an unknown model simply matches no fixture (a strict\n // miss / 404), so we do not replicate that up-front 400.\n let fixture: Fixture | null = null;\n let skippedBySequenceOrTurn = 0;\n let preResolvedResponse: FixtureResponse | null = null;\n // The model echoed back in the RESPONSE — the winner of the fallback chain,\n // or the requested model when there is no chain. The client's originally\n // requested `body.model` is left UNTOUCHED so the journaled request records\n // what was actually sent: it is the RESPONSE, not the request, that carries\n // the fallback outcome (`response.model` = winner).\n let responseModel = body.model;\n // Whether the fallback loop already advanced the served fixture's match count\n // (so the shared increment below does not double-count it).\n let fixtureCountIncremented = false;\n const openRouterFallback = openRouter && Array.isArray(body.models) && body.models.length > 0;\n // Select the fixture to serve for `probe`, CLAIMING a one-shot injected error\n // the instant it is selected — synchronously, before any chaos-latency await\n // and before its factory runs — so exactly one request consumes it. A\n // one-shot another in-flight request already claimed is no longer in\n // `fixtures`, so re-running the match falls through to the next candidate.\n const selectFixture = (\n probe: ChatCompletionRequest,\n counts: ReturnType<typeof journal.getFixtureMatchCountsForTest>,\n ): ReturnType<typeof matchFixtureDiagnostic> => {\n for (;;) {\n beforeFixtureSelection?.();\n const attempt = matchFixtureDiagnostic(\n fixtures,\n probe,\n counts,\n defaults.requestTransform,\n matchOptions,\n );\n if (\n attempt.fixture &&\n isOneShotError(attempt.fixture) &&\n !claimOneShotError(fixtures, attempt.fixture)\n ) {\n continue;\n }\n return attempt;\n }\n };\n\n if (openRouterFallback) {\n const candidates = buildOpenRouterCandidates(body);\n // Re-read after each in-loop increment (below). `getFixtureMatchCountsForTest`\n // returns the LIVE cached map only once a map exists for `testId`; on the\n // FIRST request for a testId it returns a fresh TRANSIENT empty map that\n // `incrementFixtureMatchCount` (which lazily creates the cached map) never\n // touches. Without the refresh, a single fixture matched by MULTIPLE\n // candidates in one request would evaluate later candidates against a stale\n // count-0 snapshot — re-matching the same sequenced/turn-gated fixture and\n // over-advancing its count. Refreshing binds `matchCounts` to the live map.\n let matchCounts = journal.getFixtureMatchCountsForTest(testId);\n // Fail-CLOSED gate: `provider.allow_fallbacks: false` suppresses fall-through\n // — only the primary is tried and a primary error fixture is served as\n // terminal. Absent / `true` keeps the default runtime-error fall-through.\n const allowFallbacks = body.provider?.allow_fallbacks !== false;\n let lastErrorFixture: Fixture | null = null;\n let lastErrorResponse: FixtureResponse | null = null;\n // Separable resolver step: a candidate's success/error decision goes through\n // this small lookup (fixture match today) kept OUT of the loop's control\n // flow, so the loop could later resolve a candidate against a live upstream\n // without re-welding the iteration to `matchFixtureDiagnostic`.\n const resolveCandidate = async (\n candidate: string,\n ): Promise<{ fixture: Fixture; response: FixtureResponse; isError: boolean } | null> => {\n const probe: ChatCompletionRequest = { ...body, model: candidate };\n const attempt = selectFixture(probe, matchCounts);\n skippedBySequenceOrTurn = Math.max(skippedBySequenceOrTurn, attempt.skippedBySequenceOrTurn);\n if (!attempt.fixture) return null;\n const response = await resolveResponse(attempt.fixture, probe);\n return { fixture: attempt.fixture, response, isError: isErrorResponse(response) };\n };\n for (const candidate of candidates) {\n const outcome = await resolveCandidate(candidate);\n if (!outcome) {\n // Primary produced no fixture and fall-through is suppressed — stop.\n if (!allowFallbacks) break;\n continue;\n }\n // A candidate whose fixture matched-and-resolved is \"consumed\": advance\n // its match count (INCLUDING error candidates used as failovers) so a\n // sequenced/turn-gated fixture progresses across requests exactly as a\n // single match would — otherwise a sequenced error primary replays the\n // same failover on every request.\n journal.incrementFixtureMatchCount(outcome.fixture, fixtures, testId);\n fixtureCountIncremented = true;\n // Rebind to the now-live cached map so subsequent candidates in THIS\n // request see the increment (see the `let matchCounts` note above).\n matchCounts = journal.getFixtureMatchCountsForTest(testId);\n responseModel = candidate;\n if (outcome.isError) {\n // Per-error-fixture failover gate. An ERROR fixture may set\n // `fallthrough: false` to mark its error CLASS as non-failover-eligible\n // — reproducing OpenRouter serving a 403/generic provider error as\n // terminal instead of advancing to the next `models[]` candidate\n // (openclaw #60191). Absent / `true` keeps the default fall-through.\n // Composes with the request-level `allowFallbacks` gate: fail over only\n // when BOTH allow it (if EITHER says don't, this candidate is terminal).\n const errorFallsThrough = (outcome.response as ErrorResponse).fallthrough !== false;\n if (allowFallbacks && errorFallsThrough) {\n // Runtime provider failure — remember it and fail over to the next.\n lastErrorFixture = outcome.fixture;\n lastErrorResponse = outcome.response;\n continue;\n }\n }\n // Success, or a terminal error (allow_fallbacks:false or fallthrough:false).\n fixture = outcome.fixture;\n preResolvedResponse = outcome.response;\n break;\n }\n if (!fixture && lastErrorFixture) {\n // Every candidate failed — serve the last provider's error (faithful to\n // \"primary and every fallback failed\"). It was already counted above.\n fixture = lastErrorFixture;\n preResolvedResponse = lastErrorResponse;\n }\n } else {\n const single = selectFixture(body, journal.getFixtureMatchCountsForTest(testId));\n fixture = single.fixture;\n skippedBySequenceOrTurn = single.skippedBySequenceOrTurn;\n }\n\n if (fixture) {\n // The fallback loop already advanced the served fixture's count; only the\n // single-match path still needs to increment here (never double-count).\n if (!fixtureCountIncremented) journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n // `JSON.stringify` drops functions/RegExps, so a predicate fixture logged\n // as `{}`; `describeMatch` names every present matcher by kind.\n defaults.logger.debug(\n `Fixture matched: ${describeMatch(fixture.match, fixtures.indexOf(fixture))}`,\n );\n } else {\n const lastUserMsg = body.messages.filter((m) => m.role === \"user\").pop();\n const snippet =\n typeof lastUserMsg?.content === \"string\" ? lastUserMsg.content.slice(0, 80) : \"\";\n defaults.logger.debug(\n `No fixture matched for request (model=${body.model ?? \"?\"}, msg=\"${snippet}\")`,\n );\n }\n\n // Roll chaos once per request. Dispatch by action + path:\n // drop / disconnect → apply immediately; upstream is never called and no\n // response body is produced.\n // malformed, fixture path → write invalid JSON instead of the fixture.\n // malformed, proxy path → proxy to upstream, then swap body via the\n // beforeWriteResponse hook (passed only when the\n // action is malformed, so the hook doesn't need\n // to re-check the action).\n // Deterministic latency is injected BEFORE the terminal actions are rolled,\n // so a configured delay applies to every outcome (served fixture, proxied\n // response, streamed response, and each chaos failure alike) — and, being\n // resolved from the same per-testId scope as the rates, never leaks into a\n // concurrently-running test that did not configure it.\n // Resolved ONCE and threaded into both the latency await and the action roll:\n // re-resolving would re-parse the chaos headers and emit every invalid/out-of-range\n // warning twice per request.\n const chaosConfig = resolveChaosConfig(\n fixture,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n await awaitChaosLatency(\n fixture,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n res,\n chaosConfig,\n );\n // C13: the latency await resolves EARLY when the client hangs up mid-delay\n // (the timer is cancelled off `res`'s `close`). `applyChaosAsync` re-checks\n // writability at exactly this point; a SPLIT gate has to do it itself.\n // Without this the handler carries on and builds, \"serves\" and JOURNALS a\n // full response into a dead socket — a phantom entry for bytes no client\n // ever received.\n const goneAfterLatency = responseGoneReason(res);\n if (goneAfterLatency !== null) {\n // Claimed at selection, but no error body ever reached a client — re-arm\n // so the injection is not burned by a client that walked away.\n releaseOneShotError(fixtures, fixture);\n defaults.logger.debug(\n `[chaos] ${method} ${path}: ${describeUnwritableReason(goneAfterLatency)} after the ` +\n `latency delay — not served, not journalled`,\n );\n return;\n }\n const chaosAction = evaluateChaos(\n fixture,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n chaosConfig,\n );\n const chaosContext = { method, path, headers: flatHeaders, body };\n // With no fixture, the response is aimock's own unless this request was\n // going to be proxied — so the journal source is \"internal\", not \"proxy\",\n // on the non-proxied path. A miss is only proxied when record mode has an\n // upstream for THIS provider and strict is not refusing it first; the\n // shared rule lives in `wouldProxyMiss` (also used by elevenlabs-voice.ts).\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const missWouldProxy = wouldProxyMiss(effectiveStrict, defaults.record, providerKey);\n const noFixtureSource = missWouldProxy ? \"proxy\" : \"internal\";\n // Chaos writes its own entry. Resolve by request identity, including after\n // awaited proxy hooks, so concurrent requests cannot receive each other's marker.\n const recordBypass = (reason: \"proxied\" | \"chaos-fired\"): void => {\n const entry = getRequestEntry();\n if (!entry) return; // A skipped chaos action did not write a response.\n recordMisbehaviorOutcome({\n entry,\n summary: resolveMisbehaviorShortCircuit({\n wire: \"openai-chat\",\n fixture: fixture ?? undefined,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n reason,\n }),\n defaults,\n testId,\n });\n };\n\n if (chaosAction === \"drop\" || chaosAction === \"disconnect\" || chaosAction === \"rateLimit\") {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n fixture ? \"fixture\" : noFixtureSource,\n defaults.registry,\n defaults.logger,\n );\n recordBypass(\"chaos-fired\");\n // The chaos action, not the fixture, answered this request — a claimed\n // one-shot's error body was never written, so put it back in the queue.\n releaseOneShotError(fixtures, fixture);\n return;\n }\n\n // `malformed` is applied here whenever there is no upstream response to\n // mutate: a matched fixture, or a miss that would not be proxied (the 404\n // and strict-503 paths). Only the proxied no-fixture case defers, to the\n // `beforeWriteResponse` hook below — the same `wouldProxyMiss` rule as the\n // source label above, so a strict-mode miss with an upstream configured is\n // answered here rather than skipped for a 503 that never rolled. Before\n // this, a rolled `malformed` on the no-fixture non-proxied path fell through\n // to a plain 404 — never applied, journalled or counted. With no fixture,\n // nothing here was ever proxied, so the source is aimock itself:\n // `\"internal\"`, never `\"proxy\"`.\n if (chaosAction === \"malformed\" && (fixture || !missWouldProxy)) {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n fixture ? \"fixture\" : \"internal\",\n defaults.registry,\n defaults.logger,\n );\n recordBypass(\"chaos-fired\");\n // Same as the terminal actions above: malformed replaces the body, so a\n // claimed one-shot's error was never served.\n releaseOneShotError(fixtures, fixture);\n return;\n }\n\n if (!fixture) {\n if (effectiveStrict) {\n const strictStatus = 503;\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(\n strictNoMatchLogLine(\n req.method ?? \"POST\",\n req.url ?? COMPLETIONS_PATH,\n skippedBySequenceOrTurn,\n ),\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n openRouter\n ? serializeOpenRouterError(strictStatus, strictMessage)\n : JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n param: null,\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n // Try record-and-replay proxy if configured\n if (defaults.record && providerKey) {\n // Hook is only passed when chaos wants to mutate the response. When\n // it's passed, it unconditionally applies malformed + journals + tells\n // proxyAndRecord to skip its default relay. The hook has no branching\n // logic — that decision is made here, at the call site.\n const hookOptions =\n chaosAction === \"malformed\"\n ? {\n // Malformed is emitted as a hardcoded invalid-JSON body, so the\n // captured upstream response isn't used here (the parameter is\n // intentionally omitted rather than declared-and-ignored).\n // Future dispatch (phase 3: non-JSON / streaming) will accept\n // the response and branch on contentType.\n beforeWriteResponse: () => {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n chaosContext,\n \"proxy\",\n defaults.registry,\n defaults.logger,\n );\n recordBypass(\"chaos-fired\");\n return true;\n },\n // Streaming responses can't be mutated post-facto (bytes already\n // on the wire). Record the bypass so the rolled action isn't\n // invisible in logs / Prometheus.\n onHookBypassed: (reason: \"sse_streamed\" | \"ndjson_streamed\" | \"binary_streamed\") => {\n defaults.logger.warn(\n `[chaos] malformed bypassed on proxy: upstream returned streaming response (${reason})`,\n );\n defaults.registry?.incrementCounter(\"aimock_chaos_bypassed_total\", {\n action: \"malformed\",\n source: \"proxy\",\n reason,\n });\n },\n }\n : undefined;\n\n // WHO killed a mid-flight stream decides what the journal says, and\n // after the fact the two look identical: `req.aborted`, `req.destroyed`\n // and `res.destroyed` all read the same whether the peer hung up or the\n // recorder tore the response down. The one signal that separates them is\n // the peer's FIN/RST, which arrives on the request socket as `end` (or\n // `error`) and only ever when the CLIENT went away. Removed afterwards:\n // a keep-alive socket outlives this request.\n let clientHungUp = false;\n const noteClientHangUp = (): void => {\n if (!res.writableEnded) clientHungUp = true;\n };\n req.socket?.on(\"end\", noteClientHangUp);\n req.socket?.on(\"error\", noteClientHangUp);\n let outcome: Awaited<ReturnType<typeof proxyAndRecord>>;\n try {\n outcome = await proxyAndRecord(\n req,\n res,\n body,\n providerKey,\n req.url ?? COMPLETIONS_PATH,\n fixtures,\n defaults,\n raw,\n hookOptions,\n );\n } finally {\n req.socket?.off(\"end\", noteClientHangUp);\n req.socket?.off(\"error\", noteClientHangUp);\n }\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n // A stream that died mid-flight still carries the 200 it opened with;\n // mark it interrupted so the journal shows what the client actually\n // got rather than a clean success, and name the side that killed it —\n // a client hang-up is normal caller behaviour, an upstream/recorder\n // tear-down is a fault worth chasing.\n const destroyedMidStream = res.destroyed && !res.writableEnded;\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: {\n status: res.statusCode ?? 200,\n fixture: null,\n source: \"proxy\",\n ...(destroyedMidStream\n ? {\n interrupted: true,\n interruptReason: clientHungUp ? \"client aborted\" : \"proxy stream destroyed\",\n }\n : {}),\n },\n });\n recordBypass(\"proxied\");\n return;\n }\n // outcome === \"not_configured\" — nothing was written; fall through to\n // 404, unless a rolled `malformed` is still owed to the client. Nothing\n // was proxied, so the source is `\"internal\"`.\n if (chaosAction === \"malformed\") {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n chaosContext,\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n recordBypass(\"chaos-fired\");\n return;\n }\n }\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n openRouter\n ? serializeOpenRouterError(404, \"No fixture matched\")\n : JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n param: null,\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n // Reuse the response already resolved by the OpenRouter fallback loop (so a\n // response factory is not invoked twice); otherwise resolve it now.\n const resolvedResponse = preResolvedResponse ?? (await resolveResponse(fixture, body));\n const evaluation = planMisbehavior({\n wire: \"openai-chat\",\n fixture,\n response: resolvedResponse,\n request: body,\n stream: body.stream === true,\n defaults,\n rawHeaders: req.headers,\n url: req.url,\n });\n if (evaluation.kind === \"error\") {\n const entry = journal.add({\n method,\n path,\n headers: flatHeaders,\n body,\n response: { status: evaluation.status, fixture },\n });\n recordMisbehaviorOutcome({ entry, summary: evaluation.summary, defaults, testId });\n if (!evaluation.summary?.evaluations.some((row) => row.outcome === \"error\")) {\n defaults.logger.error(`${evaluation.code}: ${evaluation.message}`);\n }\n\n writeErrorResponse(\n res,\n evaluation.status,\n openRouter\n ? serializeOpenRouterError(evaluation.status, `${evaluation.code}: ${evaluation.message}`)\n : JSON.stringify({\n error: {\n message: evaluation.message,\n type: \"invalid_request_error\",\n param: null,\n code: evaluation.code,\n },\n }),\n );\n return;\n }\n const appliedPlan =\n evaluation.kind === \"applied\" ? prepareOpenAIChatMisbehavior(evaluation) : undefined;\n const response = appliedPlan?.response ?? resolvedResponse;\n const summary = appliedPlan?.summary ?? evaluation.summary;\n const recordOutcome = (entry: JournalEntry): void => {\n recordMisbehaviorOutcome({ entry, summary, defaults, testId });\n };\n // Resolve ordinary applied reasoning once, before usage and delivery, using\n // the same strict/model gate as the selected response builder.\n const appliedReasoning =\n appliedPlan &&\n appliedPlan.reasoning === undefined &&\n (isTextResponse(response) ||\n isToolCallResponse(response) ||\n isCombinedFixtureResponse(response))\n ? resolveReasoningForModel(\n response.reasoning,\n responseModel,\n resolveStrictMode(defaults.strict, req.headers),\n defaults.logger,\n )\n : undefined;\n // Only the existing OpenRouter route exposes K9 reasoning. Use that same\n // decision for full-output estimation, before any transport interruption.\n const appliedUsage = appliedPlan\n ? resolveOpenAIChatMisbehaviorUsage(\n appliedPlan,\n body,\n appliedPlan.reasoning === undefined ? appliedReasoning !== undefined : openRouter,\n )\n : undefined;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n // OpenRouter always accounts usage (cost) in the response, including as the\n // final streaming chunk — the OpenAI `stream_options.include_usage` gate is a\n // deprecated no-op there.\n const includeUsage = body.stream === true && body.stream_options?.include_usage === true;\n const emitStreamingUsage = includeUsage || openRouter;\n\n // Prompt text for streaming usage-chunk token estimation, concatenated from\n // the request messages exactly as the non-streaming completion builders do\n // (see buildTextCompletion et al. in helpers.ts) so both paths estimate the\n // same prompt token count. The streaming usage chunk is then resolved through\n // the SAME helpers.ts `resolveUsage` as the non-streaming path — a single\n // source of truth for \"explicit token override wins, cost-only override still\n // estimates\" (replaces three formerly-duplicated inline `?? 0` copies).\n const streamingPromptText = body.messages\n .map((m) =>\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content.map((p) => p.text ?? \"\").join(\"\")\n : \"\",\n )\n .join(\"\");\n const resolveStreamingUsageTokens = (\n overrides: ResponseOverrides | undefined,\n completionText: string,\n ): { prompt_tokens: number; completion_tokens: number; total_tokens: number } =>\n appliedUsage ?? resolveUsage(overrides, streamingPromptText, completionText);\n\n const resolveRecordedTimings = (chunks: SSEChunk[]) => {\n const timings = fixture.recordedTimings;\n if (!appliedPlan?.duplicateId || !timings) return timings;\n const gaps = timings.interChunkDelaysMs;\n return {\n ...timings,\n interChunkDelaysMs: Array.from(\n { length: Math.max(gaps.length, chunks.length - 1) },\n (_, index) => gaps[index] ?? gaps.at(-1) ?? 0,\n ),\n };\n };\n\n // OpenRouter response shaping (no-op for OpenAI callers). Applied as a\n // post-pass over the objects the shared OpenAI builders produce so the\n // OpenAI code path is untouched. All OpenRouter-specific field shapes live in\n // openrouter-chat.ts. The fixture's `id` override still wins verbatim (the\n // `gen-` prefix rewrite only applies to auto-generated ids).\n const shapeORCompletion = (\n completion: ChatCompletion,\n overrides: ResponseOverrides | undefined,\n ): ChatCompletion => {\n if (appliedUsage) completion.usage = appliedUsage;\n if (!openRouter) return completion;\n return shapeOpenRouterCompletion(\n completion,\n resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel),\n overrides?.id !== undefined,\n );\n };\n const shapeORChunks = (\n chunks: SSEChunk[],\n usageChunk: SSEChunk | undefined,\n overrides: ResponseOverrides | undefined,\n ): void => {\n if (!openRouter) return;\n const shaping = resolveOpenRouterShaping(overrides, overrides?.model ?? responseModel);\n shapeOpenRouterChunks(chunks, shaping, overrides?.id !== undefined);\n // The final usage chunk shares the stream id and provider; shaping it also\n // augments its usage with cost/cost_details.\n if (usageChunk) shapeOpenRouterChunks([usageChunk], shaping, overrides?.id !== undefined);\n };\n // Opt-in `: OPENROUTER PROCESSING` keepalive comment lines (default off).\n const openRouterProcessing = !!(openRouter && fixture.openRouterProcessing);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status, fixture },\n });\n recordOutcome(entry);\n writeErrorResponse(\n res,\n status,\n openRouter\n ? serializeOpenRouterError(status, response.error.message, response.error.metadata)\n : serializeErrorResponse(response),\n {\n retryAfter: response.retryAfter,\n },\n );\n return;\n }\n\n // Audio responses are not supported on the chat completions endpoint\n if (isAudioResponse(response)) {\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 422, fixture },\n });\n recordOutcome(entry);\n writeErrorResponse(\n res,\n 422,\n openRouter\n ? serializeOpenRouterError(\n 422,\n \"Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.\",\n )\n : JSON.stringify({\n error: {\n message:\n \"Audio responses are not supported on the chat completions endpoint. Use Gemini generateContent or a dedicated audio endpoint.\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Fault-specific terminals have distinct native message/delta shapes. Keep\n // ordinary builders and their historical finishReason mapping unchanged.\n if (\n appliedPlan &&\n isTextResponse(response) &&\n (appliedPlan.stop === \"refusal\" ||\n appliedPlan.stop === \"content_filter\" ||\n appliedPlan.reasoning !== undefined)\n ) {\n const overrides = extractOverrides(response);\n const entry = journal.add({\n method,\n path,\n headers: flatHeaders,\n body,\n response: { status: 200, fixture },\n });\n recordOutcome(entry);\n if (body.stream !== true) {\n const completion =\n appliedPlan.stop === \"refusal\"\n ? buildOpenAIRefusalCompletion(\n appliedPlan.refusal ?? \"\",\n responseModel,\n overrides,\n body.messages,\n )\n : appliedPlan.stop === \"content_filter\"\n ? buildOpenAIContentFilterCompletion(responseModel, overrides, body.messages)\n : buildOpenAIReasoningCompletion(\n appliedPlan.reasoning ?? \"\",\n responseModel,\n openRouter,\n overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks =\n appliedPlan.stop === \"refusal\"\n ? buildOpenAIRefusalChunks(appliedPlan.refusal ?? \"\", responseModel, chunkSize, overrides)\n : appliedPlan.stop === \"content_filter\"\n ? buildOpenAIContentFilterChunks(responseModel, overrides)\n : buildOpenAIReasoningChunks(\n appliedPlan.reasoning ?? \"\",\n responseModel,\n chunkSize,\n openRouter,\n overrides,\n );\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0].id,\n overrides?.model ?? responseModel,\n chunks[0].created,\n resolveStreamingUsageTokens(overrides, \"\"),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: resolveRecordedTimings(chunks),\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n entry.response.interrupted = true;\n entry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Content + tool calls response\n if (isCombinedFixtureResponse(response)) {\n if (response.webSearches?.length) {\n defaults.logger.warn(\n \"webSearches in fixture response are not supported for Chat Completions API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = appliedPlan\n ? appliedReasoning\n : resolveReasoningForModel(\n response.reasoning,\n responseModel,\n effectiveStrict,\n defaults.logger,\n );\n // Validate authoritative blocks before recording success in either mode.\n // Reuse their normalized payload for nonstream responses and usage estimates.\n const streaming = body.stream === true;\n const blockOutcome =\n response.blocks && response.blocks.length > 0\n ? resolveFixtureBlockOutcome(response.blocks)\n : undefined;\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 200, fixture },\n });\n recordOutcome(journalEntry);\n // A Responses-only custom tool call (customToolCalls / responsesBlocks) is\n // rejected before any byte is written. It runs after journaling so the 500\n // entry keeps the request body and the matched fixture (routeError amends\n // it).\n const toolCalls = requireEmittedFunctionToolCalls(response, wire);\n if (!streaming) {\n const completion = buildContentWithToolCallsCompletion(\n blockOutcome?.content ?? response.content ?? \"\",\n blockOutcome?.toolCalls ?? toolCalls,\n responseModel,\n effReasoning,\n blockOutcome\n ? {\n ...overrides,\n finishReason:\n overrides?.finishReason ?? (blockOutcome.hasToolCalls ? \"tool_calls\" : \"stop\"),\n }\n : overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks = buildContentWithToolCallsChunks(\n blockOutcome?.content ?? response.content ?? \"\",\n blockOutcome?.toolCalls ?? toolCalls,\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n blockOutcome?.ordered,\n );\n // Estimate usage from the same authoritative payload sent to the client.\n const completionText = blockOutcome\n ? blockOutcome.content + blockOutcome.toolCalls.map((tc) => tc.name + tc.arguments).join(\"\")\n : (response.content ?? \"\") + toolCalls.map((tc) => tc.name + tc.arguments).join(\"\");\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0]?.id ?? \"chatcmpl-unknown\",\n overrides?.model ?? responseModel,\n chunks[0]?.created ?? Math.floor(Date.now() / 1000),\n resolveStreamingUsageTokens(overrides, completionText),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: resolveRecordedTimings(chunks),\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\n if (response.webSearches?.length) {\n defaults.logger.warn(\n \"webSearches in fixture response are not supported for Chat Completions API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = appliedPlan\n ? appliedReasoning\n : resolveReasoningForModel(\n response.reasoning,\n responseModel,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 200, fixture },\n });\n recordOutcome(journalEntry);\n if (body.stream !== true) {\n const completion = buildTextCompletion(\n response.content,\n responseModel,\n effReasoning,\n overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks = buildTextChunks(\n response.content,\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n );\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0]?.id ?? \"chatcmpl-unknown\",\n overrides?.model ?? responseModel,\n chunks[0]?.created ?? Math.floor(Date.now() / 1000),\n resolveStreamingUsageTokens(overrides, response.content),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: resolveRecordedTimings(chunks),\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n if (response.webSearches?.length) {\n defaults.logger.warn(\n \"webSearches in fixture response are not supported for Chat Completions API — ignoring\",\n );\n }\n const overrides = extractOverrides(response);\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const effReasoning = appliedPlan\n ? appliedReasoning\n : resolveReasoningForModel(\n response.reasoning,\n responseModel,\n effectiveStrict,\n defaults.logger,\n );\n const journalEntry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 200, fixture },\n });\n recordOutcome(journalEntry);\n const toolCalls = requireServedFunctionToolCalls(response, wire);\n if (body.stream !== true) {\n const completion = buildToolCallCompletion(\n toolCalls,\n responseModel,\n effReasoning,\n overrides,\n body.messages,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(shapeORCompletion(completion, overrides)));\n } else {\n const chunks = buildToolCallChunks(\n toolCalls,\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n );\n const completionText = toolCalls.map((tc) => tc.name + tc.arguments).join(\"\");\n const usageChunk = emitStreamingUsage\n ? buildUsageChunk(\n chunks[0]?.id ?? \"chatcmpl-unknown\",\n overrides?.model ?? responseModel,\n chunks[0]?.created ?? Math.floor(Date.now() / 1000),\n resolveStreamingUsageTokens(overrides, completionText),\n overrides?.systemFingerprint,\n )\n : undefined;\n shapeORChunks(chunks, usageChunk, overrides);\n const interruption = createInterruptionSignal(fixture);\n const completed = await writeSSEStream(res, chunks, {\n latency,\n streamingProfile: fixture.streamingProfile,\n signal: interruption?.signal,\n onChunkSent: interruption?.tick,\n usageChunk,\n recordedTimings: resolveRecordedTimings(chunks),\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n openRouterProcessing,\n });\n if (!completed) {\n if (!res.writableEnded) res.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n }\n interruption?.cleanup();\n }\n return;\n }\n\n // Fixture response matched no known type — guard against silent hang\n const entry = journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: 500, fixture },\n });\n recordOutcome(entry);\n writeErrorResponse(\n res,\n 500,\n openRouter\n ? serializeOpenRouterError(500, \"Fixture response did not match any known type\")\n : JSON.stringify({\n error: {\n message: \"Fixture response did not match any known type\",\n type: \"server_error\",\n },\n }),\n );\n}\n\nexport interface ServiceFixtures {\n search: SearchFixture[];\n rerank: RerankFixture[];\n moderation: ModerationFixture[];\n /** MCP fake blocks, handed off at start to the MCPMock serving each block's `mount` (F2). */\n mcpFakes?: McpFakeSource[];\n}\n\n// NOTE: The fixtures array is read by reference on each request. Callers\n// (e.g. LLMock) may mutate it after the server starts and changes will\n// be visible immediately. This is intentional — do not copy the array.\nexport async function createServer(\n fixtures: Fixture[],\n options?: MockServerOptions,\n mounts?: Array<{ path: string; handler: Mountable }>,\n serviceFixtures?: ServiceFixtures,\n): Promise<ServerInstance> {\n const resolvedAuth = resolveInboundAuth({ value: options?.auth, label: \"options.auth\" });\n return createServerWithResolvedAuth(fixtures, options, resolvedAuth, mounts, serviceFixtures);\n}\n\n/** @internal Config startup uses this to avoid parsing a selected auth source twice. */\nexport async function createServerWithResolvedAuth(\n fixtures: Fixture[],\n options: MockServerOptions | undefined,\n resolvedAuth: ResolvedInboundAuth,\n mounts?: Array<{ path: string; handler: Mountable }>,\n serviceFixtures?: ServiceFixtures,\n): Promise<ServerInstance> {\n const logger = new Logger(options?.logLevel ?? \"silent\");\n // Mounts-array rule (spec 5.2): one server-owned array for every use below.\n // A caller's array is that array, so a later `LLMock.mount()` push is seen.\n const mountList = mounts ?? [];\n // F2: hand MCP fakes off before the mount loop; a bad input rejects start().\n // A start that fails later takes the hand-off back, so a retry loads each\n // block once.\n const handOff =\n serviceFixtures?.mcpFakes && serviceFixtures.mcpFakes.length > 0\n ? handOffMcpFakes(mountList, serviceFixtures.mcpFakes, logger)\n : null;\n try {\n return await startServer(\n fixtures,\n options,\n resolvedAuth,\n mountList,\n logger,\n serviceFixtures,\n () => handOff?.commit(),\n );\n } catch (err) {\n handOff?.undo();\n throw err;\n }\n}\n\n/**\n * The journal as JSON. An entry names the caller's fixture; the JSON shows\n * the fixture the request was served from (`Journal.servedFixture`): an\n * extended server's view, with the held keys applied, or LLMock's\n * per-addition copy with misbehavior enabled. The journal therefore reads as\n * it did when the entries held those objects.\n */\nfunction journalJson(entries: JournalEntry[], journal: Journal): string {\n if (!entries.some((entry) => journal.servedFixture(entry) !== entry.response.fixture)) {\n return JSON.stringify(entries);\n }\n return JSON.stringify(\n entries.map((entry) => {\n const fixture = entry.response.fixture;\n let served = journal.servedFixture(entry);\n if (served === fixture || !served) return entry;\n // A view is rebuilt from its fixture, as the extended server reads it now.\n const viewSource = responsesToolsViewSource(served);\n if (viewSource !== served) served = responsesToolsExtendedView(viewSource);\n return { ...entry, response: { ...entry.response, fixture: served } };\n }),\n );\n}\n\n/**\n * The server of `createServerWithResolvedAuth`, after the MCP fakes hand-off.\n * `commitHandOff` runs once the server listens; if it throws, the server is\n * closed and start rejects.\n */\nasync function startServer(\n fixtures: Fixture[],\n options: MockServerOptions | undefined,\n resolvedAuth: ResolvedInboundAuth,\n mountList: MountList,\n logger: Logger,\n serviceFixtures: ServiceFixtures | undefined,\n commitHandOff: () => void,\n): Promise<ServerInstance> {\n const callerFixtures = fixtures;\n // Keep raw entries in the caller's live array, assigning only absent identities.\n let rawFixtureAddition = 0;\n function ensureRawFixturePositions(): void {\n const existingPositions = new Set(\n callerFixtures\n .map(getFixtureMisbehaviorPosition)\n .filter((position) => position !== undefined),\n );\n for (const fixture of callerFixtures) {\n if (getFixtureMisbehaviorPosition(fixture) !== undefined) continue;\n let position: string;\n do {\n position = `createServer#${rawFixtureAddition++}`;\n } while (existingPositions.has(position));\n setFixtureMisbehaviorPosition(fixture, position);\n existingPositions.add(position);\n }\n }\n ensureRawFixturePositions();\n\n const host = options?.host ?? \"127.0.0.1\";\n const port = options?.port ?? 0;\n const registry = options?.metrics ? createMetricsRegistry() : undefined;\n const serverOptions = options ?? {};\n // 1.44.0 ignored an unknown `responsesTools` option, so an invalid value is\n // ignored with a warning (at any logLevel, as aimock --config warns) and the\n // server runs in \"legacy\" mode.\n const validResponsesTools = (mode: unknown): mode is ResponsesToolsMode =>\n mode === \"legacy\" || mode === \"extended\";\n if (\n serverOptions.responsesTools !== undefined &&\n !validResponsesTools(serverOptions.responsesTools)\n ) {\n new Logger(\"warn\").warn(\n `Ignoring responsesTools because it must be \"legacy\" or \"extended\", got ${JSON.stringify(serverOptions.responsesTools)}. Using \"legacy\".`,\n );\n }\n // From here on the server reads and writes the caller's array through its\n // own list, which carries this server's responsesTools mode (and, when\n // \"extended\", each fixture's extended view). Nothing is written to the\n // caller's fixtures for the mode, so servers that share them stay apart.\n fixtures = createServerFixtureList(\n callerFixtures,\n () => serverOptions.responsesTools,\n responsesToolsExtendedView,\n );\n // Runtime-mutable server chaos config. Reads fall through to the construction\n // options until POST /__aimock/chaos installs an override, which is scoped to\n // the caller's testId. The untagged baseline lives in the SAME map under\n // DEFAULT_TEST_ID, so \"drop the baseline\" and \"drop one test's override\" are\n // one operation and neither can accidentally take the other's overrides with\n // it; only assigning `undefined` (a full reset) clears the map.\n const chaosByTestId = new Map<string, ChaosConfig>();\n let misbehaviorBaseline: MisbehaviorConfig | undefined;\n const misbehavior: MisbehaviorScope = {\n byTestId: new Map(),\n // The default-ID override is the runtime baseline for every unnamed scope.\n // Keep its construction/setter fallback separate so DELETE reveals it.\n get baseline() {\n return this.byTestId.get(DEFAULT_TEST_ID) ?? misbehaviorBaseline;\n },\n set baseline(config: MisbehaviorConfig | undefined) {\n misbehaviorBaseline = config;\n if (config === undefined) this.byTestId.delete(DEFAULT_TEST_ID);\n else if (this.byTestId.has(DEFAULT_TEST_ID)) this.byTestId.set(DEFAULT_TEST_ID, config);\n },\n };\n // Misbehavior is opt-in (enableMisbehavior). Without it there is no scope,\n // so no fault is planned, and the `misbehavior` option, fixture keys and the\n // X-AIMock-Misbehavior header are ignored, as in 1.44.0.\n const misbehaviorEnabled = serverOptions.enableMisbehavior === true;\n if (misbehaviorEnabled) callerFixtures.forEach(enableHeldFixtureMisbehavior);\n if (misbehaviorEnabled && serverOptions.misbehavior !== undefined) {\n const parsed = parseMisbehavior(serverOptions.misbehavior);\n if (!parsed.ok) throw new TypeError(`${parsed.issue.rule}: ${parsed.issue.message}`);\n misbehavior.baseline =\n parsed.config.seed === \"random\"\n ? { ...parsed.config, seed: resolveMisbehaviorSeed(parsed.config.seed, logger) }\n : parsed.config;\n }\n\n const defaults = {\n latency: serverOptions.latency ?? 0,\n chunkSize: Math.max(1, serverOptions.chunkSize ?? DEFAULT_CHUNK_SIZE),\n replaySpeed: serverOptions.replaySpeed ?? 1.0,\n logger,\n chaosByTestId,\n misbehavior: misbehaviorEnabled ? misbehavior : undefined,\n get misbehaviorCounters(): Journal {\n return journal;\n },\n // Handlers get a SCOPE, not a flat config: chaos.ts picks the override for\n // the request's X-Test-Id and falls back to the baseline.\n get chaos(): ChaosDefaults {\n return {\n base: chaosByTestId.get(DEFAULT_TEST_ID) ?? serverOptions.chaos,\n byTestId: chaosByTestId,\n };\n },\n // Assigning `undefined` drops EVERY runtime override instead of latching an\n // empty one, so the construction-time chaos config is always recoverable\n // (that is what `POST /__aimock/reset` does). `POST {}` still installs a\n // real, empty override: \"explicitly no chaos\".\n set chaos(value: ChaosDefaults | undefined) {\n if (value === undefined) {\n chaosByTestId.clear();\n return;\n }\n const base = isChaosScope(value) ? value.base : value;\n if (base === undefined) chaosByTestId.delete(DEFAULT_TEST_ID);\n else chaosByTestId.set(DEFAULT_TEST_ID, base);\n },\n registry,\n get record() {\n return serverOptions.record;\n },\n get strict() {\n return serverOptions.strict;\n },\n get strictToolArguments() {\n return serverOptions.strictToolArguments;\n },\n get responsesTools() {\n const mode = serverOptions.responsesTools;\n return validResponsesTools(mode) ? mode : undefined;\n },\n get requestTransform() {\n return serverOptions.requestTransform;\n },\n get falQueue() {\n return serverOptions.falQueue;\n },\n get openRouterVideo() {\n return serverOptions.openRouterVideo;\n },\n get veoVideo() {\n return serverOptions.veoVideo;\n },\n get grokVideo() {\n return serverOptions.grokVideo;\n },\n get bytePlusVideo() {\n return serverOptions.bytePlusVideo;\n },\n };\n\n // Validate chaos defaults through the ONE chaos table, so what startup warns\n // about is exactly what the runtime rejects (same fields, same bounds, same\n // words). The hand-rolled range check this replaces said nothing for\n // `latencyMs: 250.5`, which the runtime then rejected on every request.\n if (options?.chaos) {\n const chaosDefaults = options.chaos as Record<string, unknown>;\n for (const field of CHAOS_FIELD_NAMES) {\n const value = chaosDefaults[field];\n if (value === undefined) continue;\n // Typed config, like the control API's JSON body: a numeric string is a\n // type error, not a wire spelling to be parsed.\n if (typeof value === \"number\" && parseChaosField(field, value) !== undefined) continue;\n const shape = CHAOS_FIELDS[field].integer ? \"a whole number of ms\" : \"a number\";\n logger.warn(\n `Chaos default ${field} value ${JSON.stringify(value)} — must be ${shape} in [0,${CHAOS_FIELDS[field].max}]; rejected at runtime, never clamped: this default is ignored`,\n );\n }\n }\n\n // Validate poll-progression thresholds (resolveProgression treats\n // non-finite values as unset and floors/clamps the rest to >= 0 integers)\n for (const { name, config } of [\n { name: \"falQueue\", config: options?.falQueue },\n { name: \"openRouterVideo\", config: options?.openRouterVideo },\n { name: \"veoVideo\", config: options?.veoVideo },\n { name: \"grokVideo\", config: options?.grokVideo },\n { name: \"bytePlusVideo\", config: options?.bytePlusVideo },\n ]) {\n if (!config) continue;\n for (const field of [\"pollsBeforeInProgress\", \"pollsBeforeCompleted\"] as const) {\n const value = config[field];\n if (value === undefined) continue;\n if (!Number.isFinite(value)) {\n logger.warn(`${name}.${field} (${value}) is not a finite number — treating as unset`);\n } else if (!Number.isInteger(value) || value < 0) {\n logger.warn(\n `${name}.${field} (${value}) is not a non-negative integer — flooring/clamping to a non-negative integer`,\n );\n }\n }\n }\n\n // Validate the recorded-b64 cap: the capture path treats a negative or\n // non-integer record.openRouterVideo.maxContentBytes as the default rather\n // than letting `cap > 0` checks misbehave on negatives or NaN.\n {\n const cap = options?.record?.openRouterVideo?.maxContentBytes;\n if (cap !== undefined && (!Number.isInteger(cap) || cap < 0)) {\n logger.warn(\n `record.openRouterVideo.maxContentBytes (${cap}) is not a non-negative integer — using the default cap (${OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES})`,\n );\n }\n }\n\n // Reject a BytePlus upstream base that already carries Ark's `/api/v3`\n // prefix. `record.providers.byteplus` is an ORIGIN: the video handlers pass\n // the full `/api/v3/contents/generations/tasks[...]` constant to\n // resolveUpstreamUrl, and the chat/images proxies relay the client's raw\n // `req.url` (which is itself `/api/v3/...`). `@tanstack/ai-byteplus@0.3.4`\n // ships `https://ark.ap-southeast.bytepluses.com/api/v3` as its default Ark\n // `base_url` (`BYTEPLUS_ARK_BASE_URL`, which its own author labels\n // \"Docs-derived\" — this repo has not read BytePlus's docs), so pasting that\n // into --provider-byteplus is the expected mistake, and it composes\n // `/api/v3/api/v3/...` on every BytePlus path. The origin+prefix itself IS\n // observed to serve: a keyless GET under it answers 401, not 404.\n //\n // This THROWS rather than silently stripping the suffix, for two reasons.\n // (1) Nothing is being taken away: the doubled form cannot serve any\n // BytePlus request, so there is no working configuration to preserve —\n // whereas a silent strip would make aimock rewrite an operator-supplied URL\n // and would be flatly wrong for the one case where a path-suffixed base is\n // deliberate (a reverse proxy mounted under a path: stripping sends the\n // request to the origin, bypassing the mount). (2) A warn is easy to miss in\n // a mock server's log stream, and the symptom it leaves behind — a relayed\n // upstream 404 — does not name its cause. Fail at startup, where the message\n // can.\n {\n const bytePlusBase = options?.record?.providers?.byteplus;\n if (bytePlusBase !== undefined) {\n let basePath: string | undefined;\n try {\n basePath = new URL(bytePlusBase).pathname;\n } catch {\n // Not parseable as an absolute URL — leave it to the request path to\n // report; this guard only speaks to the prefix-doubling mistake.\n }\n if (basePath !== undefined && /(^|\\/)api\\/v3\\/?$/.test(basePath)) {\n throw new Error(\n `record.providers.byteplus (${bytePlusBase}) ends in /api/v3, but aimock ` +\n `appends the /api/v3 prefix itself — every BytePlus request would go to ` +\n `/api/v3/api/v3/... and fail upstream. Configure the ORIGIN only ` +\n `(e.g. https://ark.ap-southeast.bytepluses.com).`,\n );\n }\n }\n }\n\n /**\n * The in-flight request, scoped to the async execution that serves it.\n * Entered once in the `http.createServer` callback, so every handler —\n * including the ones in other modules that only ever see the shared\n * `journal` — runs inside it.\n */\n const requestScope = new AsyncLocalStorage<http.IncomingMessage>();\n /** The journal entry each request produced, keyed by the request object. */\n const ownJournalEntry = new WeakMap<http.IncomingMessage, JournalEntry>();\n\n // Programmatic default: finite caps so long-running embedders don't inherit\n // an unbounded journal / fixture-count map. Callers that need unbounded\n // retention (e.g. short-lived test harnesses) can opt in by passing 0.\n const journal = new Journal({\n maxEntries: options?.journalMaxEntries ?? 1000,\n fixtureCountsMaxTestIds: options?.fixtureCountsMaxTestIds ?? 500,\n onAdd: (entry) => {\n const req = requestScope.getStore();\n if (req) ownJournalEntry.set(req, entry);\n },\n });\n // An extended server matches each fixture through its view; the journal\n // counts and records the caller's fixture behind it, as before the views.\n if (serverOptions.responsesTools === \"extended\") {\n journal.configureFixtureViewSource(responsesToolsViewSource);\n }\n const videoStates = new VideoStateMap();\n const openRouterVideoJobs = new OpenRouterVideoJobMap();\n const veoVideoJobs = new VeoVideoJobMap();\n const grokVideoJobs = new GrokVideoJobMap();\n const bytePlusVideoJobs = new BytePlusVideoJobMap();\n\n /**\n * The OpenAI error `type` that goes with a status: 4xx is the caller's\n * fault, everything else is ours. Shared by `routeError` and the envelopes\n * it calls so the body can never disagree with the status line.\n */\n function errorTypeForStatus(status: number): string {\n return status >= 400 && status < 500 ? \"invalid_request_error\" : \"server_error\";\n }\n\n /**\n * Envelope for a fixture tool-call error (see isFixtureToolCallError: invalid\n * JSON arguments on an object wire, a custom tool call on a non-Responses\n * wire, or a malformed fixture tool call). It is the provider envelope aimock\n * emits for that route, with the aimock `code` in it: Google's\n * `google.rpc.ErrorInfo` detail on Gemini and Vertex AI, a string\n * `error.code` on Gemini Interactions and Anthropic Messages, a `reason`\n * member on Bedrock (a `code` member would replace `__type` as the AWS SDK's\n * error name), and a sibling `code` on Ollama's bare string error. Every\n * other route, Cohere included, gets the OpenAI-style\n * `{error: {message, type, code}}`. OpenRouter routes pass their own\n * `toolCallEnvelope` instead of using this one.\n */\n function invalidToolArgumentsEnvelope(pathname: string, message: string, code: string): string {\n if (pathname === OLLAMA_CHAT_PATH) return JSON.stringify({ error: message, code });\n if (pathname === GEMINI_INTERACTIONS_PATH) {\n return JSON.stringify({ error: { code, message } });\n }\n if (GEMINI_PATH_RE.test(pathname) || VERTEX_AI_RE.test(pathname)) {\n return JSON.stringify({\n error: {\n code: 500,\n message,\n status: \"INTERNAL\",\n details: googleFixtureToolCallErrorDetails(code),\n },\n });\n }\n if (pathname === MESSAGES_PATH) {\n return JSON.stringify({ type: \"error\", error: { type: \"api_error\", code, message } });\n }\n if (\n BEDROCK_INVOKE_RE.test(pathname) ||\n BEDROCK_STREAM_RE.test(pathname) ||\n BEDROCK_CONVERSE_RE.test(pathname) ||\n BEDROCK_CONVERSE_STREAM_RE.test(pathname)\n ) {\n return JSON.stringify({ __type: \"InternalServerException\", message, reason: code });\n }\n return JSON.stringify({ error: { message, type: \"server_error\", code } });\n }\n\n function invalidMisbehaviorHeaderEnvelope(pathname: string, detail: string): string {\n const code = \"aimock_misbehavior_invalid\";\n const message = `${code}: ${detail}`;\n if (pathname === OLLAMA_CHAT_PATH || pathname === OLLAMA_GENERATE_PATH) {\n return JSON.stringify({ error: message });\n }\n if (pathname === COHERE_CHAT_PATH) return JSON.stringify({ message });\n if (pathname === GEMINI_INTERACTIONS_PATH) {\n return JSON.stringify({ error: { code, message } });\n }\n if (GEMINI_PATH_RE.test(pathname) || VERTEX_AI_RE.test(pathname)) {\n return JSON.stringify({ error: { code: 400, message, status: \"INVALID_ARGUMENT\" } });\n }\n if (pathname === MESSAGES_PATH) {\n return JSON.stringify({\n type: \"error\",\n error: { type: \"invalid_request_error\", code, message },\n });\n }\n if (\n BEDROCK_INVOKE_RE.test(pathname) ||\n BEDROCK_STREAM_RE.test(pathname) ||\n BEDROCK_CONVERSE_RE.test(pathname) ||\n BEDROCK_CONVERSE_STREAM_RE.test(pathname)\n ) {\n return JSON.stringify({ __type: \"ValidationException\", message });\n }\n return JSON.stringify({ error: { message, type: \"invalid_request_error\", code } });\n }\n\n /**\n * The newest journal entry this request already produced, or null.\n *\n * Attribution is by the identity of the `IncomingMessage` the entry was\n * written under — never by `x-request-id`. That header is CALLER-supplied\n * (`resolveRequestId` echoes a well-formed one) and nothing makes it\n * unique: a retry, a harness that pins one id, or a load generator sends\n * the same id on many requests, and keying off it made a crash rewrite an\n * EARLIER request's entry while leaving the crashing request untraced. The\n * request object cannot be collided by a caller, so one entry belongs to\n * exactly one request. A handler writes at most one entry; if it writes\n * more, the newest wins, which is the entry the old scan would have found.\n */\n function lastJournalEntryFor(req: http.IncomingMessage): JournalEntry | null {\n return ownJournalEntry.get(req) ?? null;\n }\n\n /**\n * Uniform terminal arm for a route handler that threw. Every route error\n * path logs the route, journals the failure, sets CORS and answers the error\n * envelope — so a handler crash is never invisible in the logs or in\n * `/__aimock/journal`.\n *\n * ONE request produces ONE entry. `res.headersSent` is not the test for that:\n * a handler that journaled its 200 and then threw before `writeHead` has\n * sent no headers, and journaling again would leave two contradicting\n * entries for one request. So the existing entry is looked up by request\n * identity ({@link lastJournalEntryFor}) and AMENDED — status to what the\n * client actually got when the response is still changeable, or interrupted\n * when it isn't — and a fresh entry is\n * added only when the handler journaled nothing. That holds after the\n * response too: a handler that answered and then crashed before its own\n * journal write gets an entry carrying the status already sent, so a\n * post-response crash is never invisible.\n *\n * Once headers are on the wire the status can't change, so the socket is\n * destroyed: a clean `end()` reads as EOF and the client treats a truncated\n * stream as a complete response. The chat-style SSE routes whose clients\n * surface an error frame pass `streamEvent`; that frame is written first,\n * but the tear-down still follows it.\n *\n * A body that blew its size cap is the CALLER's fault, not a server fault:\n * it logs at warn, but if the reader destroyed the socket it journals an\n * interruption with status 0 because no 4xx reached the client. A client\n * that hung up before its body arrived\n * ({@link clientAbortedMidBody}) is not a fault at all: it logs at warn and\n * journals a torn socket (`interrupted`, status 0), never a 500 the client\n * could not have received.\n */\n function routeError(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n err: unknown,\n pathname: string,\n opts?: {\n service?: string;\n /**\n * Provider-shaped error body. Takes the STATUS routeError settled on —\n * a client-fault body cap answers 400, and an envelope that hardcoded\n * 500 would contradict the status line it is sent with.\n */\n envelope?: (msg: string, status: number) => string;\n /**\n * Provider-shaped body for a fixture tool-call error (always a 500),\n * carrying the aimock `code`. Defaults to the envelope the pathname\n * implies ({@link invalidToolArgumentsEnvelope}).\n */\n toolCallEnvelope?: (msg: string, code: string) => string;\n streamEvent?: (msg: string, status: number) => string;\n },\n ): void {\n const route = `${req.method ?? \"?\"} ${pathname}`;\n const msg = err instanceof Error ? err.message : \"Internal error\";\n const invalidToolArguments = isFixtureToolCallError(err);\n const clientFault = err instanceof RequestBodyTooLargeError;\n const clientAbort = clientAbortedMidBody(req, res, err);\n const status = clientFault ? 400 : 500;\n if (clientAbort) logger.warn(`${route}: client aborted mid-body (${msg})`);\n else if (clientFault) logger.warn(`${route}: ${msg}`);\n else logger.error(`${route}: ${msg}`);\n if (err instanceof Error && err.stack) logger.debug(err.stack);\n const existing = lastJournalEntryFor(req);\n const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);\n if ((clientAbort || bodyLimitDisconnect) && !res.headersSent) {\n const interruptReason = bodyLimitDisconnect\n ? \"request body exceeded size limit\"\n : \"client aborted\";\n // Nothing reached the client and nothing crashed: the entry records a\n // torn socket (status 0, same as chaos `disconnect` before headers), and\n // there is no socket left to answer on.\n if (existing) {\n if (!existing.response.interrupted) {\n existing.response.status = 0;\n existing.response.interrupted = true;\n existing.response.interruptReason = interruptReason;\n }\n return;\n }\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n ...(opts?.service ? { service: opts.service } : {}),\n response: {\n status: 0,\n fixture: null,\n source: \"internal\",\n interrupted: true,\n interruptReason,\n },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after body-read interruption: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n return;\n }\n if (!res.headersSent) {\n if (existing) {\n // The handler's own entry, corrected to the status the client gets.\n // `source`/`fixture` are left alone: they record what was going to\n // serve this request, which the crash didn't change.\n existing.response.status = status;\n if (invalidToolArguments) existing.response.error = msg;\n } else {\n // Wrapped so journaling can never mask the error write below.\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n ...(opts?.service ? { service: opts.service } : {}),\n response: {\n status,\n fixture: null,\n source: \"internal\",\n ...(invalidToolArguments ? { error: msg } : {}),\n },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n }\n setCorsHeaders(res);\n writeErrorResponse(\n res,\n status,\n invalidToolArguments\n ? (opts?.toolCallEnvelope ?? ((m, c) => invalidToolArgumentsEnvelope(pathname, m, c)))(\n msg,\n fixtureToolCallErrorCode(err),\n )\n : opts?.envelope\n ? opts.envelope(msg, status)\n : JSON.stringify({\n error: {\n message: msg,\n type: errorTypeForStatus(status),\n },\n }),\n );\n } else {\n // Headers are on the wire, so the status the client got is fixed. If the\n // handler already journaled, mark its entry so the journal and the\n // metrics finish hook agree with the torn socket instead of reporting a\n // clean success. If it journaled nothing (it crashed on the way to\n // journaling, after the response went out), ADD the entry now — a\n // post-response crash must never leave a request without a trace.\n //\n // `interrupted` means the client did not get a complete body. Once\n // `end()` has run it did, so a crash after that point is recorded in\n // `error` with the status that was delivered, never as an interruption.\n const midStreamReason = clientAbort ? \"client aborted\" : \"handler crashed mid-stream\";\n if (existing) {\n if (res.writableEnded) {\n if (existing.response.error === undefined) existing.response.error = msg;\n } else if (!existing.response.interrupted) {\n existing.response.interrupted = true;\n existing.response.interruptReason = midStreamReason;\n }\n } else {\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n ...(opts?.service ? { service: opts.service } : {}),\n response: {\n status: res.statusCode,\n fixture: null,\n source: \"internal\",\n ...(res.writableEnded\n ? { error: msg }\n : { interrupted: true, interruptReason: midStreamReason }),\n },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n }\n // A response that already completed has nothing left to tear down.\n if (res.writableEnded) return;\n if (opts?.streamEvent) {\n try {\n // Destroy once the frame is flushed — written, then torn down, never\n // ended cleanly.\n res.write(opts.streamEvent(msg, status), () => {\n if (!res.destroyed) res.destroy();\n });\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n res.destroy();\n }\n } else {\n res.destroy();\n }\n }\n }\n\n // Share journal and metrics registry with mounted services\n for (const { handler } of mountList) {\n if (handler.setJournal) handler.setJournal(journal);\n if (registry && handler.setRegistry) handler.setRegistry(registry);\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) handler.setReplaySpeed(defaults.replaySpeed);\n }\n\n // Set initial fixtures-loaded gauge\n if (registry) {\n registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => {\n // Delegate to async handler — catch unhandled rejections to prevent Node.js crashes.\n // Run inside the request scope so every journal write made while serving\n // this request (in any handler module) is attributed back to it.\n requestScope.run(req, () => {\n runWithToolArgumentsScope({ strict: defaults.strictToolArguments === true, logger }, () =>\n handleHttpRequest(req, res).catch((err: unknown) => {\n routeError(req, res, err, req.url ?? \"?\");\n }),\n );\n });\n });\n\n async function handleHttpRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n // Record start time for metrics\n const startTime = registry ? process.hrtime.bigint() : 0n;\n\n // Request-id propagation: echo a well-formed caller id, else mint one.\n // Normalized back onto `req.headers` so every downstream\n // `flattenHeaders` journal snapshot carries it with zero per-handler\n // edits, and echoed on the response for trace correlation. A MINTED id is\n // aimock's own invention and must never reach a real provider, so the\n // provenance is marked for `buildForwardHeaders` to strip on egress; a\n // caller-supplied id is the caller's header and forwards untouched.\n const { id: requestId, generated: requestIdMinted } = resolveRequestId(req.headers);\n req.headers[\"x-request-id\"] = requestId;\n markMintedRequestId(req, requestIdMinted);\n res.setHeader(\"X-Request-Id\", requestId);\n\n let pathname = \"\";\n\n // Instrument response completion for metrics. The callbacks read pathname\n // via closure after normalizeCompatPath has rewritten it, so metrics\n // record the canonical /v1/... path. Registered BEFORE the URL is parsed:\n // a request whose target or `Host` header will not parse is answered 400,\n // and hooking after the parse would leave that response\n // uncounted. It reaches `normalizePathLabel` with the empty pre-parse\n // pathname and lands in `{unknown}`, like every other pre-routing reject.\n //\n // Two terminal events, one count. `finish` fires only when the body was\n // ended; a response torn down by `res.destroy()` — the `disconnect` chaos\n // action, a body-cap reset, a catch-arm teardown — never finishes and only\n // ever emits `close`. Those were invisible to `/metrics`, so the request\n // total under-counted by exactly the failures worth watching. `close`\n // also follows every `finish`, hence the guard: a normal response counts\n // once, under its status; a destroyed one counts once, as `destroyed`.\n if (registry) {\n let recorded = false;\n const recordOutcome = (status: string): void => {\n if (recorded) return;\n recorded = true;\n try {\n // Read the mount table at record time, not at start: `LLMock.mount()`\n // after `start()` pushes onto this same array, and a snapshot taken\n // here at startup labelled that (correctly routed) traffic `{unknown}`.\n const normalizedPath = normalizePathLabel(\n pathname,\n mountList.map((m) => m.path),\n );\n const method = req.method ?? \"UNKNOWN\";\n registry.incrementCounter(\"aimock_requests_total\", {\n method,\n path: normalizedPath,\n status,\n });\n const elapsed = Number(process.hrtime.bigint() - startTime) / 1e9;\n registry.observeHistogram(\n \"aimock_request_duration_seconds\",\n { method, path: normalizedPath },\n elapsed,\n );\n } catch (err) {\n defaults.logger.warn(\"metrics instrumentation error\", err);\n }\n };\n res.on(\"finish\", () => recordOutcome(String(res.statusCode)));\n res.on(\"close\", () => {\n if (!res.writableFinished) recordOutcome(DESTROYED_STATUS_LABEL);\n });\n }\n\n // Parse the URL pathname (strip query string)\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n } catch (err: unknown) {\n const route = `${req.method ?? \"?\"} ${req.url ?? \"?\"}`;\n const msg = err instanceof Error ? err.message : \"Internal error\";\n logger.error(`${route}: ${msg}`);\n if (err instanceof Error && err.stack) logger.debug(err.stack);\n try {\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? \"?\",\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null, source: \"internal\" },\n });\n } catch (jErr) {\n logger.warn(\n `${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n setCorsHeaders(res);\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Invalid request target\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n pathname = parsedUrl.pathname;\n // Capture the ORIGINAL path before normalizeCompatPath rewrites it — the\n // OpenRouter `/api/v1/` base is the detection signal and would otherwise be\n // erased (`/api/v1/chat/completions` → `/v1/chat/completions`).\n const originalPathname = pathname;\n const isOpenRouter = isOpenRouterPath(originalPathname);\n // BytePlus Ark attribution, GATED ON CONFIGURATION. A path prefix is not\n // evidence of a vendor — the COMPAT_SUFFIXES comment above exists precisely\n // because arbitrary vendors ride arbitrary prefixes (BigModel uses /v4/).\n // Ungated, anyone serving an OpenAI-compatible vendor under /api/v3 with\n // `record.providers.openai` configured would suddenly look up a byteplus\n // upstream, find none, and lose record mode entirely. Requiring a\n // configured byteplus upstream makes the new behavior reachable only for\n // the user who asked for it.\n const isBytePlusArk =\n defaults.record?.providers.byteplus !== undefined && originalPathname.startsWith(\"/api/v3/\");\n\n // Browser CORS preflights do not carry application credentials. A bare\n // OPTIONS is still a route request and must pass the normal auth boundary.\n if (\n req.method === \"OPTIONS\" &&\n (!resolvedAuth.policy.enabled ||\n (req.headers.origin !== undefined &&\n req.headers[\"access-control-request-method\"] !== undefined))\n ) {\n handleOptions(res);\n return;\n }\n\n const isPublicProbe =\n req.method === \"GET\" &&\n (pathname === HEALTH_PATH || pathname === READY_PATH || pathname === METRICS_PATH);\n if (!isPublicProbe) {\n if (!validateRequestApiKey(req, resolvedAuth.policy).ok) {\n writeApiKeyHttpRejection(res, setCorsHeaders);\n return;\n }\n markAuthenticatedRequest(req, resolvedAuth.policy);\n }\n\n // Control API — must be checked before mounts and path rewrites\n if (pathname.startsWith(CONTROL_PREFIX)) {\n ensureRawFixturePositions();\n await handleControlAPI(\n req,\n res,\n pathname,\n parsedUrl.searchParams,\n fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\n defaults,\n mountList,\n );\n return;\n }\n\n // Validate the entire Node-normalized value before any provider can serve\n // or skip unsupported faults. Repeated fields must parse as one grammar;\n // never select only the first value. Keep valid headers intact for planning.\n const misbehaviorHeader = defaults.misbehavior\n ? parseMisbehaviorHeader(req.headers[\"x-aimock-misbehavior\"])\n : undefined;\n if (misbehaviorHeader && !misbehaviorHeader.ok) {\n const detail = misbehaviorHeader.issue.message;\n const message = `aimock_misbehavior_invalid: ${detail}`;\n logger.error(`${req.method ?? \"?\"} ${pathname}: ${message}`);\n journal.add({\n method: req.method ?? \"?\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null, source: \"internal\", error: message },\n });\n setCorsHeaders(res);\n writeErrorResponse(\n res,\n 400,\n invalidMisbehaviorHeaderEnvelope(normalizeCompatPath(pathname), detail),\n );\n return;\n }\n\n // Dispatch to mounted services before any path rewrites\n for (const { path: mountPath, handler } of mountList) {\n if (pathname === mountPath || pathname.startsWith(mountPath + \"/\")) {\n const subPath = pathname.slice(mountPath.length) || \"/\";\n const handled = await handler.handleRequest(req, res, subPath);\n if (handled) return;\n }\n }\n\n // Ollama /api/* routes must be dispatched BEFORE normalizeCompatPath, which\n // rewrites any path ending in /embeddings to /v1/embeddings. The /api/chat,\n // /api/generate, and /api/embed paths are unaffected (their suffixes aren't\n // in COMPAT_SUFFIXES), but /api/embeddings would collide with the OpenAI\n // handler. /api/embed is the current Ollama endpoint\n // (https://github.com/ollama/ollama/blob/main/docs/api.md); /api/embeddings\n // is the legacy path kept for backwards-compatibility. Both route to the\n // same handler.\n if (pathname === OLLAMA_CHAT_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleOllama(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (pathname === OLLAMA_GENERATE_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleOllamaGenerate(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (\n (pathname === OLLAMA_EMBEDDINGS_PATH || pathname === OLLAMA_EMBED_PATH) &&\n req.method === \"POST\"\n ) {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleOllamaEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (pathname === OLLAMA_TAGS_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n const modelIds = new Set<string>();\n for (const f of fixtures) {\n if (f.match.model && typeof f.match.model === \"string\") {\n modelIds.add(f.match.model);\n }\n }\n const ids = modelIds.size > 0 ? [...modelIds] : DEFAULT_MODELS;\n const models = ids.map((name) => ({\n name,\n model: name,\n modified_at: new Date().toISOString(),\n size: 0,\n digest: \"\",\n details: {},\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ models }));\n return;\n }\n\n // OpenRouter async video lifecycle (/api/v1/videos). Like the Ollama\n // /api/* routes above, dispatched before normalizeCompatPath. Order:\n // content RE → models exact → status RE → submit exact (the status RE's\n // `[^/]+` segment would otherwise swallow the `models` listing path; the\n // content path's extra `/content` segment can never match it).\n\n // GET /api/v1/videos/{jobId}/content — download the generated bytes\n const openRouterVideoContentMatch = pathname.match(OPENROUTER_VIDEO_CONTENT_RE);\n if (openRouterVideoContentMatch && req.method === \"GET\") {\n try {\n await handleOpenRouterVideoContent(\n req,\n res,\n openRouterVideoContentMatch[1],\n journal,\n defaults,\n setCorsHeaders,\n openRouterVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /api/v1/videos/models — video model listing (must precede the\n // status RE, whose [^/]+ segment would otherwise capture \"models\")\n if (pathname === OPENROUTER_VIDEO_MODELS_PATH && req.method === \"GET\") {\n try {\n ensureRawFixturePositions();\n await handleOpenRouterVideoModels(req, res, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /api/v1/videos/{jobId} — poll job status\n const openRouterVideoStatusMatch = pathname.match(OPENROUTER_VIDEO_STATUS_RE);\n if (openRouterVideoStatusMatch && req.method === \"GET\") {\n try {\n ensureRawFixturePositions();\n await handleOpenRouterVideoStatus(\n req,\n res,\n openRouterVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n openRouterVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /api/v1/videos — submit a video generation job (202 Accepted)\n if (pathname === OPENROUTER_VIDEOS_PATH && req.method === \"POST\") {\n // CORS headers before the body is read: a readBody throw (e.g. the\n // body-size cap) lands in the catch below, which must not write a 500\n // that is opaque to browser clients. The handler re-applies the same\n // headers (setHeader is idempotent).\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleOpenRouterVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n openRouterVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // ── BytePlus Ark (Seedance) async video task lifecycle ──────────────────\n // Registered in the PRE-REWRITE band, alongside the OpenRouter video routes\n // above: normalizeCompatPath does not currently claim these paths, but the\n // Ollama block documents that hazard and the mount dispatch also runs\n // pre-rewrite, so keeping every raw-path route in one band keeps one rule.\n //\n // The REs anchor an ENUMERATED optional `/api/v3` prefix (see metrics.ts).\n // That matters here specifically because this band runs ~1,100 lines ahead\n // of every fal branch, so a wildcard prefix would take\n // `/fal/contents/generations/tasks` away from the fal proxy.\n //\n // Status is tested BEFORE submit and each is method-guarded, so a future\n // DELETE .../tasks/{id} falls through to 404 rather than being mis-served.\n const bytePlusVideoStatusMatch = pathname.match(BYTEPLUS_VIDEO_STATUS_RE);\n if (bytePlusVideoStatusMatch && req.method === \"GET\") {\n try {\n ensureRawFixturePositions();\n await handleBytePlusVideoStatus(\n req,\n res,\n bytePlusVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n if (BYTEPLUS_VIDEO_SUBMIT_RE.test(pathname) && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleBytePlusVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // OpenRouter discovery endpoints. Dispatched BEFORE normalizeCompatPath\n // (which does not rewrite these — /models etc. are excluded from\n // COMPAT_SUFFIXES — so they would otherwise 404), mirroring the\n // /api/v1/videos ordering above. Read-only metadata; no body.\n if (pathname === OPENROUTER_MODELS_PATH && req.method === \"GET\") {\n ensureRawFixturePositions();\n handleOpenRouterModels(req, res, fixtures, journal, defaults, setCorsHeaders);\n return;\n }\n if (pathname === OPENROUTER_KEY_PATH && req.method === \"GET\") {\n handleOpenRouterKey(req, res, journal, setCorsHeaders);\n return;\n }\n if (pathname === OPENROUTER_CREDITS_PATH && req.method === \"GET\") {\n handleOpenRouterCredits(req, res, journal, setCorsHeaders);\n return;\n }\n\n // Azure OpenAI: /openai/deployments/{id}/{operation} → /v1/{operation} (chat/completions, embeddings)\n // Must be checked BEFORE the generic /openai/ prefix strip\n let azureDeploymentId: string | undefined;\n const azureMatch = pathname.match(AZURE_DEPLOYMENT_RE);\n if (azureMatch && req.method === \"POST\") {\n azureDeploymentId = azureMatch[1];\n const operation = azureMatch[2];\n pathname = `/v1/${operation}`;\n }\n\n // Normalize OpenAI-compatible paths (strip /openai/ prefix + rewrite arbitrary prefixes)\n if (!azureDeploymentId) {\n pathname = normalizeCompatPath(pathname, logger);\n }\n\n // Health / readiness probes\n if (pathname === HEALTH_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n if (mountList.length > 0) {\n const services: Record<string, unknown> = {\n llm: { status: \"ok\", fixtures: fixtures.length },\n };\n for (const { path: mountPath, handler } of mountList) {\n if (handler.health) {\n const name = mountPath.replace(/^\\//, \"\");\n services[name] = handler.health();\n }\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", services }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n }\n return;\n }\n\n if (pathname === READY_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ready\" }));\n return;\n }\n\n // Prometheus metrics\n if (pathname === METRICS_PATH && req.method === \"GET\") {\n if (!registry) {\n handleNotFound(res, \"Not found\");\n return;\n }\n setCorsHeaders(res);\n res.writeHead(200, { \"Content-Type\": \"text/plain; version=0.0.4; charset=utf-8\" });\n res.end(registry.serialize());\n return;\n }\n\n // Models listing\n if (pathname === MODELS_PATH && req.method === \"GET\") {\n setCorsHeaders(res);\n const modelIds = new Set<string>();\n for (const f of fixtures) {\n if (f.match.model && typeof f.match.model === \"string\") {\n modelIds.add(f.match.model);\n }\n }\n const ids = modelIds.size > 0 ? [...modelIds] : DEFAULT_MODELS;\n const data = ids.map((id) => ({\n id,\n object: \"model\" as const,\n created: 1686935002,\n owned_by: \"aimock\",\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ object: \"list\", data }));\n return;\n }\n\n // Batches API — cancel RE before id RE (the id RE would swallow /cancel).\n // Cancel takes no payload — the `openai` SDK posts an empty body — but the\n // body is still read, and discarded, before the handler runs. Reading it is\n // what applies `readBody`'s 10 MB ceiling: a POST route that never touches\n // the stream lets node quietly dump whatever the client sends, so this one\n // route would accept an unbounded upload while the create route beside it\n // (the sibling pattern followed here, down to the error arm) rejects the\n // same bytes.\n const batchesCancelMatch = pathname.match(BATCHES_CANCEL_RE);\n if (batchesCancelMatch && req.method === \"POST\") {\n try {\n await readBody(req);\n await handleBatchesCancel(\n req,\n res,\n batchesCancelMatch[1],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"batches\" });\n }\n return;\n }\n const batchesIdMatch = pathname.match(BATCHES_ID_RE);\n if (batchesIdMatch && req.method === \"GET\") {\n try {\n await handleBatchesRetrieve(req, res, batchesIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"batches\" });\n }\n return;\n }\n if (pathname === BATCHES_PATH && req.method === \"GET\") {\n try {\n await handleBatchesList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"batches\" });\n }\n return;\n }\n if (pathname === BATCHES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleBatchesCreate(req, res, raw, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"batches\",\n });\n }\n return;\n }\n\n // Files API mock — dispatch order matters: content RE → id RE → collection.\n // The id RE's `[^/]+` would otherwise swallow `/content`, and the\n // collection exact match must not claim an id path.\n //\n // Every branch is method-guarded, so an unhandled method on a files path\n // (`PATCH /v1/files/{id}`, and also `HEAD`, which nothing here implements)\n // falls through to the shared 404. That is this server's convention, not a\n // files-specific gap: there is no `405` anywhere in this file, the BytePlus\n // block above documents the same fallthrough by name, and measured against\n // a live server `HEAD /health` and `PATCH /v1/models` answer 404 exactly\n // like their files equivalents. Answering 405 + `Allow` here — or serving\n // HEAD — would make files the only surface in the mock that behaves that\n // way, which is a bigger inconsistency than the one it fixes. Changing it\n // is a server-wide change and belongs in its own pass.\n const filesContentMatch = pathname.match(FILES_CONTENT_RE);\n if (filesContentMatch && req.method === \"GET\") {\n try {\n await handleFilesContent(req, res, filesContentMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n const filesIdMatch = pathname.match(FILES_ID_RE);\n if (filesIdMatch && req.method === \"GET\") {\n try {\n await handleFilesRetrieve(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n if (filesIdMatch && req.method === \"DELETE\") {\n try {\n await handleFilesDelete(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n if (pathname === FILES_PATH && req.method === \"GET\") {\n // `purpose` is NOT read here. It used to be, with `searchParams.get`,\n // which silently first-wins a repeat and hands `\"\"` through for\n // `?purpose=`; the files module reads all four list parameters itself so\n // one rule covers them all.\n try {\n await handleFilesList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"files\" });\n }\n return;\n }\n if (pathname === FILES_PATH && req.method === \"POST\") {\n try {\n // A Buffer, not readBody's string: a multipart upload can carry\n // arbitrary binary and a utf8 decode here would corrupt it before\n // files.ts ever sees the bytes. Every other route keeps using readBody\n // unchanged.\n //\n // Bounded, not readBodyBuffer: this route must answer a\n // 400 for a body that is *over* its content cap, and readBodyBuffer's\n // only answer to over-size is destroying the socket — which the caller\n // reads as ECONNRESET, with no status and no CORS. Here the bound is\n // on memory, not on the socket. See the constants' doc comments.\n const body = await readBodyBufferBounded(\n req,\n FILES_BODY_MAX_BYTES,\n FILES_BODY_DRAIN_MAX_BYTES,\n );\n await handleFilesCreate(\n req,\n res,\n body.buffer ?? FILES_BODY_OVERSIZED,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"files\",\n });\n }\n return;\n }\n\n // Fine-tuning jobs — cancel/events REs before id RE.\n // Cancel takes no payload — the `openai` SDK posts an empty body — but the\n // body is still read, and discarded, before the handler runs. Reading it is\n // what applies `readBody`'s 10 MB ceiling: a POST route that never touches\n // the stream lets node quietly dump whatever the client sends, so this one\n // route would accept an unbounded upload while the create route beside it\n // (the sibling pattern followed here, down to the error arm) rejects the\n // same bytes.\n const ftCancelMatch = pathname.match(FINE_TUNING_CANCEL_RE);\n if (ftCancelMatch && req.method === \"POST\") {\n try {\n await readBody(req);\n await handleFineTuningCancel(req, res, ftCancelMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"fine-tuning\",\n });\n }\n return;\n }\n const ftEventsMatch = pathname.match(FINE_TUNING_EVENTS_RE);\n if (ftEventsMatch && req.method === \"GET\") {\n try {\n await handleFineTuningEvents(req, res, ftEventsMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"fine-tuning\" });\n }\n return;\n }\n const ftIdMatch = pathname.match(FINE_TUNING_ID_RE);\n if (ftIdMatch && req.method === \"GET\") {\n try {\n await handleFineTuningRetrieve(req, res, ftIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"fine-tuning\" });\n }\n return;\n }\n if (pathname === FINE_TUNING_JOBS_PATH && req.method === \"GET\") {\n try {\n await handleFineTuningList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"fine-tuning\" });\n }\n return;\n }\n if (pathname === FINE_TUNING_JOBS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleFineTuningCreate(req, res, raw, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"fine-tuning\",\n });\n }\n return;\n }\n\n // Vector Stores — most-specific REs before the id RE, collection last.\n // The id RE's `[^/]+` would otherwise swallow `/files`, `/search` and\n // the file-batch suffixes, and the collection exact match must not claim\n // an id path. Every branch is method-guarded so unhandled methods fall\n // through to the shared 404, the server-wide convention (see the files\n // block above).\n const vsSearchMatch = pathname.match(VECTOR_STORES_SEARCH_RE);\n if (vsSearchMatch && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVectorStoresSearch(\n req,\n res,\n vsSearchMatch[1],\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsBatchFilesMatch = pathname.match(VECTOR_STORES_BATCH_FILES_RE);\n if (vsBatchFilesMatch && req.method === \"GET\") {\n try {\n await handleVectorFileBatchesFiles(\n req,\n res,\n vsBatchFilesMatch[1],\n vsBatchFilesMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsBatchCancelMatch = pathname.match(VECTOR_STORES_BATCH_CANCEL_RE);\n if (vsBatchCancelMatch && req.method === \"POST\") {\n try {\n await readBody(req);\n await handleVectorFileBatchesCancel(\n req,\n res,\n vsBatchCancelMatch[1],\n vsBatchCancelMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsBatchMatch = pathname.match(VECTOR_STORES_BATCH_RE);\n if (vsBatchMatch && req.method === \"GET\") {\n try {\n await handleVectorFileBatchesRetrieve(\n req,\n res,\n vsBatchMatch[1],\n vsBatchMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n const vsFileMatch = pathname.match(VECTOR_STORES_FILE_RE);\n if (vsFileMatch && req.method === \"GET\") {\n try {\n await handleVectorStoreFilesRetrieve(\n req,\n res,\n vsFileMatch[1],\n vsFileMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (vsFileMatch && req.method === \"DELETE\") {\n try {\n await handleVectorStoreFilesDelete(\n req,\n res,\n vsFileMatch[1],\n vsFileMatch[2],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n // Note: VECTOR_STORES_ID_RE only matches the exact 3-segment id path,\n // so it can never swallow the /files, /search or /file_batches suffixes\n // handled above — no extra depth guards needed.\n const vsIdMatch = pathname.match(VECTOR_STORES_ID_RE);\n if (vsIdMatch && req.method === \"GET\") {\n try {\n await handleVectorStoresRetrieve(req, res, vsIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (vsIdMatch && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVectorStoresModify(\n req,\n res,\n vsIdMatch[1],\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (vsIdMatch && req.method === \"DELETE\") {\n try {\n await handleVectorStoresDelete(req, res, vsIdMatch[1], journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (VECTOR_STORES_FILES_RE.test(pathname) && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n const storeId = pathname.split(\"/\")[3];\n await handleVectorStoreFilesCreate(\n req,\n res,\n storeId,\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (VECTOR_STORES_FILES_RE.test(pathname) && req.method === \"GET\") {\n try {\n const storeId = pathname.split(\"/\")[3];\n await handleVectorStoreFilesList(req, res, storeId, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (VECTOR_STORES_FILE_BATCHES_RE.test(pathname) && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n const storeId = pathname.split(\"/\")[3];\n await handleVectorFileBatchesCreate(\n req,\n res,\n storeId,\n raw,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (pathname === VECTOR_STORES_PATH && req.method === \"GET\") {\n try {\n await handleVectorStoresList(req, res, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n if (pathname === VECTOR_STORES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleVectorStoresCreate(req, res, raw, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"vector-stores\" });\n }\n return;\n }\n\n // Journal inspection endpoints\n if (pathname === REQUESTS_PATH) {\n setCorsHeaders(res);\n if (req.method === \"GET\") {\n const limitParam = parsedUrl.searchParams.get(\"limit\");\n let opts: { limit: number } | undefined;\n if (limitParam) {\n const limit = Number(limitParam);\n if (!/^\\+?\\d+$/.test(limitParam.trim()) || !Number.isSafeInteger(limit) || limit <= 0) {\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Invalid limit parameter: \"${limitParam}\"`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n opts = { limit };\n }\n const entries = journal.getAll(opts);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(journalJson(entries, journal));\n return;\n }\n if (req.method === \"DELETE\") {\n // Clear only the request journal entries, preserving fixture\n // match-counts (sequencing state). Clearing the request log must not\n // silently rewind sequenced fixtures. For a full reset (entries +\n // match-counts), use POST /__aimock/reset.\n journal.clearEntries();\n res.writeHead(204);\n res.end();\n return;\n }\n handleNotFound(res, \"Not found\");\n return;\n }\n\n // POST /v1/responses — OpenAI Responses API\n if (pathname === RESPONSES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleResponses(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) =>\n `event: error\\ndata: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v1/messages — Anthropic Claude Messages API\n if (pathname === MESSAGES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleMessages(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) =>\n `event: error\\ndata: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v2/chat — Cohere v2 Chat API\n if (pathname === COHERE_CHAT_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleCohere(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) =>\n `event: error\\ndata: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v2/embed — Cohere v2 Embed API\n if (pathname === COHERE_EMBED_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleCohereEmbed(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/embeddings — OpenAI Embeddings API\n if (pathname === EMBEDDINGS_PATH && req.method === \"POST\") {\n try {\n const deploymentId = azureDeploymentId;\n const embeddingsProvider: RecordProviderKey = azureDeploymentId ? \"azure\" : \"openai\";\n let raw = await readBody(req);\n // Azure deployments may omit model from body — use deployment ID as fallback\n if (deploymentId) {\n try {\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (!parsed.model) {\n parsed.model = deploymentId;\n raw = JSON.stringify(parsed);\n }\n } catch (err) {\n if (!(err instanceof SyntaxError)) {\n defaults.logger.error(\n `Unexpected error in Azure model injection: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n // Fall through for parse errors — let handleEmbeddings report them\n }\n }\n ensureRawFixturePositions();\n await handleEmbeddings(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n embeddingsProvider,\n originalPathname === EMBEDDINGS_PATH,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/images/generations — OpenAI Image Generation API\n if (pathname === IMAGES_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleImages(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"openai\",\n undefined,\n isBytePlusArk ? \"byteplus\" : undefined,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/images/edits — OpenAI Image Edit API (multipart/form-data)\n if (pathname === IMAGES_EDIT_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleImageEdit(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/images/variations — OpenAI Image Variations API (multipart/form-data)\n if (pathname === IMAGES_VARIATIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleImageVariations(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/audio/speech — OpenAI TTS API\n if (pathname === SPEECH_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleSpeech(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/audio/transcriptions — OpenAI Transcription API\n if (pathname === TRANSCRIPTIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleTranscription(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/audio/translations — OpenAI Translation API\n if (pathname === TRANSLATIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleTranscription(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"translation\",\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/videos/generations — xAI Grok Imagine video submit. A distinct\n // exact path from Sora's POST /v1/videos (no collision). Must precede the\n // Sora GET status RE which would otherwise parse `generations` as an id on\n // a GET — but this is a POST, so the guard is method-level here and\n // `id !== \"generations\"` in the GET block below. (T0: stub filled in T2.)\n if (pathname === GROK_VIDEO_SUBMIT_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleGrokVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n grokVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/videos — Video Generation API\n if (pathname === VIDEOS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n videoStates,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /v1/videos/{id} — Grok-first video status check. Grok Imagine and\n // Sora share this path: handleGrokVideoStatus does a job-map-first lookup\n // and falls through to the UNCHANGED Sora handleVideoStatus on a Grok miss\n // (disjoint id namespaces → unambiguous). The `id !== \"generations\"` guard\n // keeps the Grok submit literal out of the status RE. (T0: the Grok job map\n // is always empty, so every GET delegates to Sora — behavior-preserving.)\n const grokVideoStatusMatch = pathname.match(GROK_VIDEO_STATUS_RE);\n if (grokVideoStatusMatch && grokVideoStatusMatch[1] !== \"generations\" && req.method === \"GET\") {\n try {\n ensureRawFixturePositions();\n await handleGrokVideoStatus(\n req,\n res,\n grokVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n grokVideoJobs,\n videoStates,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/models/{model}:predictLongRunning — Google Veo video submit.\n // Anchored on `:predictLongRunning`, so it never collides with the Gemini\n // `:predict` Imagen route below. (T0: handler is a stub filled in T1.)\n const veoPredictMatch = pathname.match(VEO_PREDICT_LRO_RE);\n if (veoPredictMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleVeoVideoCreate(\n req,\n res,\n raw,\n veoPredictMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n veoVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /v1beta/operations/{name} — Google Veo video status poll.\n // (T0: handler is a stub filled in T1.)\n const veoOperationMatch = pathname.match(VEO_OPERATION_RE);\n if (veoOperationMatch && req.method === \"GET\") {\n try {\n ensureRawFixturePositions();\n await handleVeoVideoStatus(\n req,\n res,\n veoOperationMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n veoVideoJobs,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/models/{model}:predict — Gemini Imagen API\n const geminiPredictMatch = pathname.match(GEMINI_PREDICT_RE);\n if (geminiPredictMatch && req.method === \"POST\") {\n const predictModel = geminiPredictMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleImages(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"gemini\",\n predictModel,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/interactions — Google Gemini Interactions API\n if (pathname === GEMINI_INTERACTIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleGeminiInteractions(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v1beta/models/{model}:embedContent — Google Gemini Embedding\n const geminiEmbedMatch = pathname.match(GEMINI_EMBED_RE);\n if (geminiEmbedMatch && req.method === \"POST\") {\n const embedModel = geminiEmbedMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleGeminiEmbedContent(\n req,\n res,\n raw,\n embedModel,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1beta/models/{model}:(generateContent|streamGenerateContent) — Google Gemini\n const geminiMatch = pathname.match(GEMINI_PATH_RE);\n if (geminiMatch && req.method === \"POST\") {\n const geminiModel = geminiMatch[1];\n const streaming = geminiMatch[2] === \"streamGenerateContent\";\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleGemini(\n req,\n res,\n raw,\n geminiModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /v1/projects/{project}/locations/{location}/publishers/google/models/{model}:(generateContent|streamGenerateContent) — Vertex AI\n const vertexMatch = pathname.match(VERTEX_AI_RE);\n if (vertexMatch && req.method === \"POST\") {\n const vertexModel = vertexMatch[1];\n const streaming = vertexMatch[2] === \"streamGenerateContent\";\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleGemini(\n req,\n res,\n raw,\n vertexModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"vertexai\",\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\\n\\n`,\n });\n }\n return;\n }\n\n // POST /model/{modelId}/invoke — AWS Bedrock Claude API\n const bedrockMatch = pathname.match(BEDROCK_INVOKE_RE);\n if (bedrockMatch && req.method === \"POST\") {\n const bedrockModelId = bedrockMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleBedrock(\n req,\n res,\n raw,\n bedrockModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /model/{modelId}/invoke-with-response-stream — AWS Bedrock Claude streaming\n const bedrockStreamMatch = pathname.match(BEDROCK_STREAM_RE);\n if (bedrockStreamMatch && req.method === \"POST\") {\n const bedrockModelId = bedrockStreamMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleBedrockStream(\n req,\n res,\n raw,\n bedrockModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /model/{modelId}/converse — AWS Bedrock Converse API\n const converseMatch = pathname.match(BEDROCK_CONVERSE_RE);\n if (converseMatch && req.method === \"POST\") {\n const converseModelId = converseMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleConverse(\n req,\n res,\n raw,\n converseModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /model/{modelId}/converse-stream — AWS Bedrock Converse streaming API\n const converseStreamMatch = pathname.match(BEDROCK_CONVERSE_STREAM_RE);\n if (converseStreamMatch && req.method === \"POST\") {\n const converseStreamModelId = converseStreamMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleConverseStream(\n req,\n res,\n raw,\n converseStreamModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /search — Web Search API (Tavily-compatible)\n if (pathname === SEARCH_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleSearch(\n req,\n res,\n raw,\n serviceFixtures?.search ?? [],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"search\",\n });\n }\n return;\n }\n\n // POST /v2/rerank — Reranking API (Cohere rerank-compatible)\n if (pathname === RERANK_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleRerank(\n req,\n res,\n raw,\n serviceFixtures?.rerank ?? [],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"rerank\",\n });\n }\n return;\n }\n\n // POST /v1/moderations — Moderation API (OpenAI-compatible)\n if (pathname === MODERATIONS_PATH && req.method === \"POST\") {\n try {\n const raw = await readBody(req);\n await handleModeration(\n req,\n res,\n raw,\n serviceFixtures?.moderation ?? [],\n journal,\n defaults,\n setCorsHeaders,\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n service: \"moderation\",\n });\n }\n return;\n }\n\n // POST /v1/sound-generation — ElevenLabs Sound Generation API\n if (pathname === ELEVENLABS_SOUND_GENERATION_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleElevenLabsAudio(req, res, raw, fixtures, defaults, journal, \"sound-generation\");\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/text-to-voice/design — ElevenLabs Voice Design (must precede create)\n if (pathname === ELEVENLABS_VOICE_DESIGN_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleElevenLabsVoiceDesign(req, res, raw, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"elevenlabs-voice\" });\n }\n return;\n }\n\n // POST /v1/text-to-voice — save a designed preview as a permanent voice\n if (pathname === ELEVENLABS_VOICE_CREATE_PATH && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleElevenLabsVoiceCreate(req, res, raw, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"elevenlabs-voice\" });\n }\n return;\n }\n\n // GET|DELETE /v1/voices/{voice_id} — slot management after Voice Design save\n const elevenLabsVoiceMatch = pathname.match(ELEVENLABS_VOICE_RE);\n if (elevenLabsVoiceMatch && (req.method === \"GET\" || req.method === \"DELETE\")) {\n setCorsHeaders(res);\n // The id arrives percent-encoded on the wire while the voice store is\n // keyed by the id exactly as it appears in JSON, so the raw path segment\n // made any id carrying a space or a slash permanently unreachable.\n // `decodeURIComponent` throws `URIError` on a malformed escape — that is\n // a bad request, not a server fault, so it is answered 400 rather than\n // falling into the 500 handler below.\n let voiceId: string;\n try {\n voiceId = decodeURIComponent(elevenLabsVoiceMatch[1]);\n } catch {\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Invalid voice id '${elevenLabsVoiceMatch[1]}': malformed percent-encoding`,\n type: \"invalid_request_error\",\n },\n }),\n );\n // Journaled AFTER the write, like every other terminal arm in this\n // batch: the caller's answer never waits on bookkeeping. Tagged with\n // the service so this rejection is selectable under\n // `?service=elevenlabs-voice` with the rest of the route's branches —\n // it was the one voice branch that left no journal entry at all.\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n service: \"elevenlabs-voice\",\n body: null,\n response: { status: 400, fixture: null },\n });\n return;\n }\n try {\n if (req.method === \"GET\") {\n ensureRawFixturePositions();\n await handleElevenLabsVoiceGet(req, res, voiceId, fixtures, defaults, journal);\n } else {\n ensureRawFixturePositions();\n await handleElevenLabsVoiceDelete(req, res, voiceId, fixtures, defaults, journal);\n }\n } catch (err: unknown) {\n routeError(req, res, err, pathname, { service: \"elevenlabs-voice\" });\n }\n return;\n }\n\n // POST /v1/text-to-speech/{voice_id} — ElevenLabs TTS API\n const elevenLabsTTSMatch = pathname.match(ELEVENLABS_TTS_RE);\n if (elevenLabsTTSMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n const voiceId = elevenLabsTTSMatch[1];\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleElevenLabsTTS(req, res, raw, fixtures, defaults, journal, voiceId);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/music/(generation|variation|remix|extend) — ElevenLabs Music API\n const musicMatch = pathname.match(ELEVENLABS_MUSIC_RE);\n if (musicMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n const musicSubType = musicMatch[1] ?? \"music\";\n try {\n const raw = await readBody(req);\n ensureRawFixturePositions();\n await handleElevenLabsAudio(req, res, raw, fixtures, defaults, journal, musicSubType);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // Body read by the general fal handler; preserved so legacy fal-audio\n // routes below don't double-consume the stream on passthrough.\n let falBody: string | undefined;\n\n // /fal/* with `x-fal-target-host` header — general fal.ai routing\n // (queue.fal.run, fal.run, rest.fal.ai, rest.alpha.fal.ai).\n // Matches the requestMiddleware path-mirror convention used by\n // @fal-ai/client when proxyUrl can't be honoured server-side.\n if (FAL_ROUTE_RE.test(pathname) && req.headers[\"x-fal-target-host\"]) {\n setCorsHeaders(res);\n try {\n falBody = req.method === \"POST\" || req.method === \"PUT\" ? await readBody(req) : \"\";\n const raw = falBody;\n // Chaos is rolled EXACTLY ONCE per fal request. This gate owns the roll\n // only when the general handler is actually going to own the request;\n // if `handleFal` would return \"passthrough\" the request continues to\n // the legacy `/fal/queue/...` / `/fal/run/...` routes below, and THEIR\n // `applyChaosAsync` (or the queue-requests gate) is the single roll.\n // Rolling here unconditionally would double-roll every passthrough\n // (observed: 0.72 effective drop rate for a configured 0.5).\n //\n // The deterministic latency is awaited BEFORE the roll, so a configured\n // delay applies to every outcome on this path — served state, proxied\n // response and each chaos failure alike — exactly as the completions\n // path does, and resolved from the same per-testId scope as the rates.\n //\n // `source` is \"internal\": the roll happens before any fixture match or\n // upstream call, so nothing was going to serve this but aimock's own\n // fal logic. Mirrors the veo/grok/openrouter lifecycle gates.\n if (falWillHandle(req, pathname)) {\n // Resolved ONCE and threaded into both the latency await and the\n // action roll — re-resolving would re-parse the chaos headers and\n // warn twice per request. `res` is passed so a client that hangs up\n // mid-delay CANCELS the pending timer instead of leaving the handler\n // waiting out the full latency. Both mirror the completions path.\n const chaosConfig = resolveChaosConfig(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n await awaitChaosLatency(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n res,\n chaosConfig,\n );\n // C13: the latency await resolves EARLY when the client hangs up\n // mid-delay (the timer is cancelled off `res`'s `close`).\n // `applyChaosAsync` re-checks writability at exactly this point; a\n // SPLIT gate has to do it itself. Without this the handler carries\n // on and builds, \"serves\" and JOURNALS a full response into a dead\n // socket — a phantom entry for bytes no client ever received.\n const goneAfterLatency = responseGoneReason(res);\n if (goneAfterLatency !== null) {\n defaults.logger.debug(\n `[chaos] ${req.method ?? \"GET\"} ${pathname}: ` +\n `${describeUnwritableReason(goneAfterLatency)} after the latency delay — ` +\n `not served, not journalled`,\n );\n return;\n }\n const chaosAction = evaluateChaos(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n chaosConfig,\n );\n if (chaosAction) {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n {\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n },\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n return;\n }\n }\n ensureRawFixturePositions();\n const outcome = await handleFal(req, res, raw, pathname, fixtures, defaults, journal);\n if (outcome === \"handled\") return;\n // passthrough: fall through to legacy fal-audio routes below\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n return;\n }\n }\n\n // POST /fal/queue/submit/{model} — fal.ai Queue Submit\n const falQueueSubmitMatch = pathname.match(FAL_QUEUE_SUBMIT_RE);\n if (falQueueSubmitMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = falBody ?? (await readBody(req));\n ensureRawFixturePositions();\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // GET /fal/queue/requests/{requestId} — fal.ai Queue Status/Result\n const falQueueRequestsMatch = pathname.match(FAL_QUEUE_REQUESTS_RE);\n if (\n falQueueRequestsMatch &&\n (req.method === \"GET\" || req.method === \"POST\" || req.method === \"PUT\")\n ) {\n setCorsHeaders(res);\n try {\n const raw =\n req.method === \"POST\" || req.method === \"PUT\" ? (falBody ?? (await readBody(req))) : \"{}\";\n // Status / cancel / result are pure state lookups: `handleFalQueue`\n // rolls no chaos for them, so this gate is their single roll. Latency\n // first, then the roll — same order as every other handler path.\n // `source` is \"internal\" (no fixture, no upstream: aimock's own queue\n // state was going to serve this), matching the veo status gate.\n // Resolved ONCE and threaded into both the latency await and the action\n // roll; `res` makes the delay cancellable on client disconnect. Same\n // shape as the completions path and the `x-fal-target-host` gate above.\n const chaosConfig = resolveChaosConfig(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n await awaitChaosLatency(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n res,\n chaosConfig,\n );\n // C13: the latency await resolves EARLY when the client hangs up\n // mid-delay (the timer is cancelled off `res`'s `close`).\n // `applyChaosAsync` re-checks writability at exactly this point; a\n // SPLIT gate has to do it itself. Without this the handler carries on\n // and builds, \"serves\" and JOURNALS a full response into a dead\n // socket — a phantom entry for bytes no client ever received.\n const goneAfterLatency = responseGoneReason(res);\n if (goneAfterLatency !== null) {\n defaults.logger.debug(\n `[chaos] ${req.method ?? \"GET\"} ${pathname}: ` +\n `${describeUnwritableReason(goneAfterLatency)} after the latency delay — ` +\n `not served, not journalled`,\n );\n return;\n }\n const chaosAction = evaluateChaos(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n chaosConfig,\n );\n if (chaosAction) {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n {\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n },\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n return;\n }\n ensureRawFixturePositions();\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /fal/run/{model} — fal.ai Synchronous Run\n const falRunMatch = pathname.match(FAL_RUN_RE);\n if (falRunMatch && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = falBody ?? (await readBody(req));\n ensureRawFixturePositions();\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n routeError(req, res, err, pathname);\n }\n return;\n }\n\n // POST /v1/chat/completions — Chat Completions API\n if (pathname !== COMPLETIONS_PATH) {\n // Registry drift guard: the catalog claims every ROUTE_DEFINITIONS\n // entry is mounted. If the registry matches a request the dispatcher\n // just fell through, the two have drifted — warn loudly (the 404\n // stands; this never changes serving behavior). Exempt: /metrics 404s\n // by design when the server runs with `metrics: false`.\n const catalogMatch = matchRouteDefinition(req.method ?? \"\", pathname);\n if (catalogMatch && !(pathname === METRICS_PATH && !registry)) {\n defaults.logger.warn(\n `Route drift: ${req.method ?? \"?\"} ${pathname} matches the route catalog ` +\n `(${catalogMatch.method} ${catalogMatch.path} — ${catalogMatch.description}) ` +\n `but no dispatcher branch served it. The catalog entry or the dispatcher ` +\n `is stale — see route-registry.ts.`,\n );\n }\n handleNotFound(res, \"Not found\");\n return;\n }\n if (req.method !== \"POST\") {\n handleNotFound(res, \"Not found\");\n return;\n }\n\n // OpenRouter callers (original path under /api/v1/) get the OpenRouter\n // provider key + response shaping; OpenAI (/v1/...) callers are unchanged.\n const completionsProvider: RecordProviderKey = azureDeploymentId\n ? \"azure\"\n : isOpenRouter\n ? \"openrouter\"\n : isBytePlusArk\n ? \"byteplus\"\n : \"openai\";\n try {\n await handleCompletions(\n req,\n res,\n fixtures,\n journal,\n defaults,\n () => lastJournalEntryFor(req),\n azureDeploymentId,\n completionsProvider,\n isOpenRouter,\n ensureRawFixturePositions,\n originalPathname.startsWith(\"/api/v3/\"),\n );\n } catch (err: unknown) {\n routeError(req, res, err, pathname, {\n envelope: (m, status) =>\n isOpenRouter\n ? serializeOpenRouterError(status, m)\n : JSON.stringify({\n error: { message: m, type: errorTypeForStatus(status) },\n }),\n // OpenRouter's numeric `error.code` is the HTTP status, so the aimock\n // code rides in its free-form `metadata`.\n ...(isOpenRouter\n ? { toolCallEnvelope: (m, code) => serializeOpenRouterError(500, m, { reason: code }) }\n : {}),\n streamEvent: (m, status) =>\n `data: ${\n isOpenRouter\n ? serializeOpenRouterError(status, m)\n : JSON.stringify({ error: { message: m, type: errorTypeForStatus(status) } })\n }\\n\\n`,\n });\n }\n }\n\n // ─── WebSocket upgrade handling ──────────────────────────────────────────\n\n const activeConnections = new Set<WebSocketConnection>();\n const liveLimits = normalizeLiveOptions(options?.live);\n const liveSessions = new Map<symbol, { testId: string; dispose: () => void }>();\n const closeLiveSessions = (testId?: string) => {\n for (const session of [...liveSessions.values()]) {\n if (testId === undefined || session.testId === testId) session.dispose();\n }\n };\n liveClosers.set(defaults, closeLiveSessions);\n\n server.on(\n \"upgrade\",\n (req: http.IncomingMessage, socket: import(\"node:net\").Socket, head: Buffer) => {\n handleUpgradeRequest(req, socket, head).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.warn(`Unhandled upgrade error: ${msg}`);\n if (!socket.destroyed) socket.destroy();\n });\n },\n );\n\n /**\n * Body bytes the platform already parsed onto `req` for an upgrade request.\n *\n * Node >= 26 delivers an upgrade request's body here and leaves `head`\n * empty; Node <= 24 leaves the body in `head` and ends `req` with nothing.\n * The stream has already ended in both cases, so this resolves on the next\n * tick either way — it never waits on the network.\n */\n function drainParsedRequestBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n let settled = false;\n const done = (): void => {\n if (settled) return;\n settled = true;\n resolve(Buffer.concat(chunks));\n };\n req.on(\"data\", (c: Buffer) => chunks.push(c));\n req.on(\"end\", done);\n req.on(\"error\", done);\n req.on(\"close\", done);\n req.resume();\n });\n }\n\n async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n // `Upgrade: h2c` + `Connection: Upgrade` on plain requests — including\n // ones with a body — to probe for HTTP/2 cleartext support. Only actual\n // WebSocket upgrades belong on this path.\n //\n // Node fires \"upgrade\" instead of \"request\" for any `Connection: Upgrade`,\n // whatever protocol is named, and the request never reaches the normal\n // pipeline. Rather than reimplementing body parsing, rebuild the request\n // line and headers with `Upgrade`/`Connection` dropped — the only thing\n // that made this look like an upgrade — replay them onto the socket, and\n // let Node re-parse the connection from scratch as an ordinary request.\n //\n // WHERE THE BODY LIVES DEPENDS ON THE NODE VERSION, and both cases must be\n // replayed or the re-parsed request stalls forever waiting on a\n // `Content-Length` worth of bytes that will never arrive:\n //\n // - Node <= 24 detaches the parser at \"upgrade\", so `req` yields nothing\n // and any body bytes already read land in `head` (or, if the client\n // sent them later, still arrive on the socket afterwards).\n // - Node >= 26 parses the body onto `req` and leaves `head` EMPTY. The\n // bytes are not on the socket either — draining `req` is the only way\n // to get them back.\n //\n // Draining `req` is safe on both: on the older behaviour it ends\n // immediately with zero bytes, so the concat below is a no-op there and\n // `head` carries the body as before.\n if ((req.headers.upgrade ?? \"\").toLowerCase() !== \"websocket\") {\n const parsedBody = await drainParsedRequestBody(req);\n const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\\r\\n`;\n const headerLines: string[] = [];\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n if (/^(?:upgrade|connection)$/i.test(req.rawHeaders[i])) continue;\n headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);\n }\n const rebuilt = Buffer.from(requestLine + headerLines.join(\"\\r\\n\") + \"\\r\\n\\r\\n\");\n socket.unshift(Buffer.concat([rebuilt, parsedBody, head]));\n server.emit(\"connection\", socket);\n return;\n }\n\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.warn(`Unhandled upgrade error: ${msg}`);\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n\");\n return;\n }\n let pathname = parsedUrl.pathname;\n\n if (!validateRequestApiKey(req, resolvedAuth.policy).ok) {\n writeApiKeyUpgradeRejection(socket);\n return;\n }\n\n // Dispatch to mounted services before any path rewrites\n for (const { path: mountPath, handler } of mountList) {\n if (\n (pathname === mountPath || pathname.startsWith(mountPath + \"/\")) &&\n handler.handleUpgrade\n ) {\n const subPath = pathname.slice(mountPath.length) || \"/\";\n if (await handler.handleUpgrade(socket, head, subPath)) return;\n }\n }\n\n // Normalize OpenAI-compatible paths (strip /openai/ prefix + rewrite arbitrary prefixes)\n // Skip Azure deployment paths — they have their own rewrite in the HTTP handler\n if (!pathname.match(AZURE_DEPLOYMENT_RE)) {\n pathname = normalizeCompatPath(pathname, logger);\n }\n\n if (\n pathname !== RESPONSES_PATH &&\n pathname !== REALTIME_PATH &&\n pathname !== GEMINI_LIVE_PATH &&\n pathname !== LIVE_PATH\n ) {\n socket.write(\"HTTP/1.1 404 Not Found\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n if (\n defaults.misbehavior &&\n pathname !== LIVE_PATH &&\n req.headers[\"x-aimock-misbehavior\"] !== undefined\n ) {\n const code = \"aimock_misbehavior_invalid\";\n const message = \"use the runtime scope: POST /__aimock/misbehavior with X-Test-Id\";\n const body = JSON.stringify({\n error:\n pathname === GEMINI_LIVE_PATH\n ? { code: 400, status: \"INVALID_ARGUMENT\", message: `${code}: ${message}` }\n : { type: \"invalid_request_error\", code, message },\n });\n socket.end(\n \"HTTP/1.1 400 Bad Request\\r\\n\" +\n \"Content-Type: application/json\\r\\n\" +\n `Content-Length: ${Buffer.byteLength(body)}\\r\\n` +\n \"Connection: close\\r\\n\\r\\n\" +\n body,\n );\n return;\n }\n\n let liveId: symbol | undefined;\n if (pathname === LIVE_PATH) {\n if (req.method !== \"GET\" || parsedUrl.searchParams.has(\"model\")) {\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n\");\n return;\n }\n if (liveSessions.size >= liveLimits.maxSessions) {\n socket.end(\"HTTP/1.1 429 Too Many Requests\\r\\nConnection: close\\r\\n\\r\\n\");\n return;\n }\n liveId = Symbol(\"live-session\");\n const reservedId = liveId;\n liveSessions.set(reservedId, {\n testId: getTestId(req),\n dispose: () => {\n socket.destroy();\n liveSessions.delete(reservedId);\n },\n });\n }\n\n // Push any buffered data back before upgrading\n if (head.length > 0) {\n socket.unshift(head);\n }\n\n let ws: WebSocketConnection;\n try {\n ws = upgradeToWebSocket(req, socket, pathname === LIVE_PATH ? liveLimits : undefined);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"WebSocket upgrade failed\";\n if (liveId !== undefined) liveSessions.delete(liveId);\n logger.error(`WebSocket upgrade error: ${msg}`);\n if (!socket.destroyed) socket.destroy();\n return;\n }\n\n activeConnections.add(ws);\n\n ws.on(\"error\", (err: Error) => {\n logger.error(`WebSocket error: ${err.message}`);\n activeConnections.delete(ws);\n });\n\n ws.on(\"close\", () => {\n activeConnections.delete(ws);\n });\n\n // Route to handler\n const wsTestId = getTestId(req);\n if (pathname === LIVE_PATH && liveId !== undefined) {\n const sessionId = liveId;\n const dispose = handleLiveSession(ws, fixtures, journal, {\n defaults,\n limits: liveLimits,\n localApiKeys: resolvedAuth.publicConfig?.apiKeys,\n testId: wsTestId,\n headers: req.headers,\n onDispose: () => {\n liveSessions.delete(sessionId);\n activeConnections.delete(ws);\n },\n });\n liveSessions.set(sessionId, { testId: wsTestId, dispose });\n } else if (pathname === RESPONSES_PATH) {\n handleWebSocketResponses(ws, fixtures, journal, {\n ...defaults,\n model: \"gpt-4\",\n testId: wsTestId,\n upgradeHeaders: req.headers,\n beforeProcessMessage: ensureRawFixturePositions,\n });\n } else if (pathname === REALTIME_PATH) {\n const transcriptionIntent = parsedUrl.searchParams.get(\"intent\") === \"transcription\";\n const model = transcriptionIntent\n ? \"gpt-transcribe\"\n : (parsedUrl.searchParams.get(\"model\") ?? \"gpt-realtime-2\");\n handleWebSocketRealtime(ws, fixtures, journal, {\n ...defaults,\n model,\n transcriptionIntent,\n testId: wsTestId,\n upgradeHeaders: req.headers,\n beforeProcessMessage: ensureRawFixturePositions,\n });\n } else if (pathname === GEMINI_LIVE_PATH) {\n handleWebSocketGeminiLive(ws, fixtures, journal, {\n ...defaults,\n model: \"gemini-2.0-flash\",\n testId: wsTestId,\n upgradeHeaders: req.headers,\n beforeProcessMessage: ensureRawFixturePositions,\n });\n }\n }\n\n // Close active WS connections when server shuts down\n const originalClose = server.close.bind(server);\n server.close = function (this: http.Server, callback?: (err?: Error) => void) {\n closeLiveSessions();\n for (const ws of activeConnections) {\n ws.close(1001, \"Server shutting down\");\n }\n activeConnections.clear();\n videoStates.clear();\n openRouterVideoJobs.clear();\n veoVideoJobs.clear();\n grokVideoJobs.clear();\n bytePlusVideoJobs.clear();\n originalClose(callback);\n return this;\n } as typeof server.close;\n\n return new Promise<ServerInstance>((resolve, reject) => {\n server.on(\"error\", reject);\n server.listen(port, host, () => {\n const addr = server.address();\n if (!addr || typeof addr === \"string\") {\n reject(new Error(\"Unexpected address format\"));\n return;\n }\n const url = `http://${addr.address}:${addr.port}`;\n\n try {\n commitHandOff();\n } catch (err) {\n server.close(() => reject(err));\n return;\n }\n\n // Set base URL on mounted services that support it\n for (const { path: mountPath, handler } of mountList) {\n if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);\n }\n\n resolve({\n closeLiveSessions,\n server,\n journal,\n url,\n defaults,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\n });\n });\n });\n}\n"],"mappings":"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"}