@copilotkit/aimock 1.38.0 → 1.39.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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +26 -0
- package/README.md +23 -2
- package/dist/agui-handler.cjs +20 -18
- package/dist/agui-handler.cjs.map +1 -1
- package/dist/agui-handler.d.cts +8 -1
- package/dist/agui-handler.d.cts.map +1 -1
- package/dist/agui-handler.d.ts +8 -1
- package/dist/agui-handler.d.ts.map +1 -1
- package/dist/agui-handler.js +20 -18
- package/dist/agui-handler.js.map +1 -1
- package/dist/agui-stub.d.cts +2 -2
- package/dist/agui-stub.d.ts +2 -2
- package/dist/agui-types.d.cts +19 -1
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts +19 -1
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +1 -1
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.js +1 -1
- package/dist/aimock-cli.js.map +1 -1
- package/dist/cli.cjs +10 -10
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +10 -10
- package/dist/cli.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/llmock.cjs +23 -9
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +22 -0
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +22 -0
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +25 -11
- package/dist/llmock.js.map +1 -1
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.js.map +1 -1
- package/dist/server.cjs +34 -17
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +6 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +6 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +34 -18
- package/dist/server.js.map +1 -1
- package/dist/stream-collapse.cjs +77 -0
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +77 -0
- package/dist/stream-collapse.js.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/ws-gemini-live.cjs +41 -6
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.js +41 -6
- package/dist/ws-gemini-live.js.map +1 -1
- package/package.json +3 -2
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["http"],"sources":["../src/server.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport type {\n Fixture,\n FixtureFileEntry,\n ChatCompletionRequest,\n HandlerDefaults,\n MockServerOptions,\n Mountable,\n RecordProviderKey,\n} from \"./types.js\";\nimport { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { validateFixtures, entryToFixture } 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 resolveFixtureBlocks,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n serializeErrorResponse,\n isAudioResponse,\n flattenHeaders,\n getTestId,\n readBody,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n getContext,\n} from \"./helpers.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 { handleElevenLabsAudio, handleElevenLabsTTS } from \"./elevenlabs-audio.js\";\nimport { handleFalQueue, falJobs } from \"./fal-audio.js\";\nimport { handleFal, falQueueStates } 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 { upgradeToWebSocket, type WebSocketConnection } from \"./ws-framing.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 { applyChaosAction, evaluateChaos } from \"./chaos.js\";\nimport {\n createMetricsRegistry,\n normalizePathLabel,\n OPENROUTER_VIDEO_CONTENT_RE,\n OPENROUTER_VIDEO_STATUS_RE,\n VEO_PREDICT_LRO_RE,\n VEO_OPERATION_RE,\n GROK_VIDEO_SUBMIT_PATH,\n GROK_VIDEO_STATUS_RE,\n} 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\";\n\nexport interface ServerInstance {\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}\n\nconst COMPLETIONS_PATH = \"/v1/chat/completions\";\nconst RESPONSES_PATH = \"/v1/responses\";\nconst REALTIME_PATH = \"/v1/realtime\";\nconst GEMINI_LIVE_PATH =\n \"/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent\";\nconst MESSAGES_PATH = \"/v1/messages\";\nconst EMBEDDINGS_PATH = \"/v1/embeddings\";\nconst COHERE_CHAT_PATH = \"/v2/chat\";\nconst COHERE_EMBED_PATH = \"/v2/embed\";\nconst SEARCH_PATH = \"/search\";\nconst RERANK_PATH = \"/v2/rerank\";\nconst MODERATIONS_PATH = \"/v1/moderations\";\nconst IMAGES_PATH = \"/v1/images/generations\";\nconst IMAGES_EDIT_PATH = \"/v1/images/edits\";\nconst IMAGES_VARIATIONS_PATH = \"/v1/images/variations\";\nconst SPEECH_PATH = \"/v1/audio/speech\";\nconst TRANSCRIPTIONS_PATH = \"/v1/audio/transcriptions\";\nconst TRANSLATIONS_PATH = \"/v1/audio/translations\";\nconst VIDEOS_PATH = \"/v1/videos\";\nconst GEMINI_PREDICT_RE = /^\\/v1beta\\/models\\/([^:]+):predict$/;\nconst ELEVENLABS_SOUND_GENERATION_PATH = \"/v1/sound-generation\";\nconst ELEVENLABS_TTS_RE = /^\\/v1\\/text-to-speech\\/([^/]+)$/;\nconst ELEVENLABS_MUSIC_RE = /^\\/v1\\/music(?:\\/(.+))?$/;\nconst FAL_QUEUE_SUBMIT_RE = /^\\/fal\\/queue\\/submit\\/(.+)$/;\nconst FAL_QUEUE_REQUESTS_RE = /^\\/fal\\/queue\\/requests\\/(.+)$/;\nconst FAL_RUN_RE = /^\\/fal\\/run\\/(.+)$/;\nconst FAL_PREFIX_RE = /^\\/fal(?:\\/.*)?$/;\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\nconst GEMINI_INTERACTIONS_PATH = \"/v1beta/interactions\";\nconst GEMINI_PATH_RE = /^\\/v1beta\\/models\\/([^:]+):(generateContent|streamGenerateContent)$/;\nconst GEMINI_EMBED_RE = /^\\/v1beta\\/models\\/([^:]+):embedContent$/;\nconst AZURE_DEPLOYMENT_RE = /^\\/openai\\/deployments\\/([^/]+)\\/(chat\\/completions|embeddings)$/;\nconst BEDROCK_INVOKE_RE = /^\\/model\\/([^/]+)\\/invoke$/;\nconst BEDROCK_STREAM_RE = /^\\/model\\/([^/]+)\\/invoke-with-response-stream$/;\nconst BEDROCK_CONVERSE_RE = /^\\/model\\/([^/]+)\\/converse$/;\nconst BEDROCK_CONVERSE_STREAM_RE = /^\\/model\\/([^/]+)\\/converse-stream$/;\nconst VERTEX_AI_RE =\n /^\\/v1\\/projects\\/[^/]+\\/locations\\/[^/]+\\/publishers\\/google\\/models\\/([^/:]+):(generateContent|streamGenerateContent)$/;\n\nconst OLLAMA_CHAT_PATH = \"/api/chat\";\nconst OLLAMA_GENERATE_PATH = \"/api/generate\";\nconst OLLAMA_EMBEDDINGS_PATH = \"/api/embeddings\";\nconst OLLAMA_EMBED_PATH = \"/api/embed\";\nconst OLLAMA_TAGS_PATH = \"/api/tags\";\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 metrics.ts path-label normalization\n// (imported above).\nconst OPENROUTER_VIDEOS_PATH = \"/api/v1/videos\";\nconst OPENROUTER_VIDEO_MODELS_PATH = \"/api/v1/videos/models\";\n\nconst HEALTH_PATH = \"/health\";\nconst READY_PATH = \"/ready\";\nconst MODELS_PATH = \"/v1/models\";\nconst REQUESTS_PATH = \"/v1/_requests\";\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 \"Access-Control-Allow-Methods\": \"GET, POST, DELETE, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"*\",\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\nconst CONTROL_PREFIX = \"/__aimock\";\n\n/**\n * Perform a full fixtures reset: clear the fixtures array, journal, video/fal\n * generation state, and the interaction/event-id counters, then zero the\n * `aimock_fixtures_loaded` gauge. Shared by `/reset/fixtures` and the\n * deprecated `/reset` alias.\n */\nfunction performFixturesReset(\n fixtures: Fixture[],\n journal: Journal,\n videoStates: VideoStateMap,\n openRouterVideoJobs: OpenRouterVideoJobMap,\n veoVideoJobs: VeoVideoJobMap,\n grokVideoJobs: GrokVideoJobMap,\n defaults: HandlerDefaults,\n): void {\n fixtures.length = 0;\n journal.clear();\n videoStates.clear();\n openRouterVideoJobs.clear();\n veoVideoJobs.clear();\n grokVideoJobs.clear();\n falJobs.clear();\n falQueueStates.clear();\n resetInteractionCounter();\n resetEventIdCounter();\n if (defaults.registry) {\n defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\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 fixtures: Fixture[],\n journal: Journal,\n videoStates: VideoStateMap,\n openRouterVideoJobs: OpenRouterVideoJobMap,\n veoVideoJobs: VeoVideoJobMap,\n grokVideoJobs: GrokVideoJobMap,\n defaults: HandlerDefaults,\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/journal\n if (subPath === \"/journal\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(journal.getAll()));\n return true;\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[] };\n try {\n parsed = JSON.parse(raw) as { fixtures?: FixtureFileEntry[] };\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 if (!Array.isArray(parsed.fixtures)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: 'Missing or invalid \"fixtures\" array' }));\n return true;\n }\n\n const converted = parsed.fixtures.map((e) => entryToFixture(e));\n const issues = validateFixtures(converted);\n const errors = issues.filter((i) => i.severity === \"error\");\n if (errors.length > 0) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Validation failed\", details: errors }));\n return true;\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(JSON.stringify({ added: converted.length }));\n return true;\n }\n\n // DELETE /__aimock/fixtures — clear all fixtures\n if (subPath === \"/fixtures\" && req.method === \"DELETE\") {\n fixtures.length = 0;\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 // POST /__aimock/reset/fixtures — full reset (fixtures + journal + match counts)\n if (subPath === \"/reset/fixtures\" && req.method === \"POST\") {\n performFixturesReset(\n fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n defaults,\n );\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 — DEPRECATED alias for /reset/fixtures (full reset)\n if (subPath === \"/reset\" && req.method === \"POST\") {\n performFixturesReset(\n fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n defaults,\n );\n const deprecation =\n \"POST /__aimock/reset is deprecated; use POST /__aimock/reset/fixtures (full reset) or POST /__aimock/reset/journal (journal only)\";\n defaults.logger.warn(\n \"POST /__aimock/reset is deprecated; use /__aimock/reset/fixtures 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 const status = parsed.status ?? 500;\n const errorBody = parsed.body;\n const errorFixture: Fixture = {\n match: { predicate: () => true },\n response: {\n error: {\n message: errorBody?.message ?? \"Injected error\",\n type: errorBody?.type ?? \"server_error\",\n code: errorBody?.code,\n },\n status,\n },\n };\n // Insert at front so it matches before everything else\n fixtures.unshift(errorFixture);\n // One-shot: match once then self-remove. We use a `consumed` flag to\n // prevent double-matching from concurrent requests and defer the actual\n // splice via queueMicrotask so it never mutates the fixtures array while\n // matchFixture is iterating over it.\n let consumed = false;\n const original = errorFixture.match.predicate!;\n errorFixture.match.predicate = (req) => {\n if (consumed) return false;\n const result = original(req);\n if (result) {\n consumed = true;\n queueMicrotask(() => {\n const idx = fixtures.indexOf(errorFixture);\n if (idx !== -1) fixtures.splice(idx, 1);\n });\n }\n return result;\n };\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\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 journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n writeErrorResponse(\n res,\n 500,\n openRouter\n ? serializeOpenRouterError(500, `Request body read failed: ${msg}`)\n : JSON.stringify({\n error: {\n message: `Request body read failed: ${msg}`,\n type: \"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 // Azure deployments may omit model from body — use deployment ID as fallback\n if (modelFallback && !body.model) {\n body.model = modelFallback;\n }\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 // 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 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\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 = matchFixtureDiagnostic(\n fixtures,\n probe,\n matchCounts,\n defaults.requestTransform,\n matchOptions,\n );\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 = matchFixtureDiagnostic(\n fixtures,\n body,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n matchOptions,\n );\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 defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\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 const chaosAction = evaluateChaos(fixture, defaults.chaos, req.headers, defaults.logger);\n const chaosContext = { method, path, headers: flatHeaders, body };\n\n if (chaosAction === \"drop\" || chaosAction === \"disconnect\") {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n );\n return;\n }\n\n if (fixture && chaosAction === \"malformed\") {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n \"fixture\",\n defaults.registry,\n );\n return;\n }\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\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 );\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 const 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 if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n // outcome === \"not_configured\" — fall through to 404\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 // Resolve the ordered streaming blocks ONCE, BEFORE recording success in the\n // journal. resolveFixtureBlocks validates and can throw on a malformed\n // `blocks` array; doing it here (rather than inside the chunk builder AND a\n // second time for the usage estimate, both of which previously ran AFTER\n // journal.add) guarantees a malformed fixture never leaves a spurious\n // status-200 journal entry. The single resolved array is reused for both\n // chunk emission and the completion-token estimate — the builder re-normalizes\n // it idempotently (a can't-fail pass on already-validated blocks), so this is\n // the only resolution that can throw. Only the streaming path consumes blocks\n // (the non-streaming builder ignores them), so gate on `stream` to leave the\n // non-streaming path's behavior byte-identical.\n const streaming = body.stream === true;\n const streamingBlocks =\n streaming && response.blocks && response.blocks.length > 0\n ? resolveFixtureBlocks(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 response.content ?? \"\",\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 = buildContentWithToolCallsChunks(\n response.content ?? \"\",\n response.toolCalls ?? [],\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n streamingBlocks,\n );\n // Build usage chunk for stream_options.include_usage (always for OpenRouter).\n // When the fixture is blocks-driven, the streamed text comes from the\n // ordered blocks (content/toolCalls are ignored by the chunk builder), so\n // the completion-token estimate must derive from the SAME block text —\n // otherwise a blocks-only fixture reports ~1 completion token. Reuse the\n // single pre-resolved `streamingBlocks` (no second resolveFixtureBlocks).\n const completionText = streamingBlocks\n ? streamingBlocks.map((b) => (b.type === \"text\" ? b.text : b.name + b.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}\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 host = options?.host ?? \"127.0.0.1\";\n const port = options?.port ?? 0;\n const logger = new Logger(options?.logLevel ?? \"silent\");\n const registry = options?.metrics ? createMetricsRegistry() : undefined;\n const serverOptions = options ?? {};\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 get chaos() {\n return serverOptions.chaos;\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 };\n\n // Validate chaos config rates\n if (options?.chaos) {\n const chaosRates = [\n { name: \"dropRate\", value: options.chaos.dropRate },\n { name: \"malformedRate\", value: options.chaos.malformedRate },\n { name: \"disconnectRate\", value: options.chaos.disconnectRate },\n ];\n for (const { name, value } of chaosRates) {\n if (value !== undefined && (value < 0 || value > 1)) {\n logger.warn(`Chaos ${name} (${value}) is outside 0-1 range — will be clamped at runtime`);\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 ]) {\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 // 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 });\n const videoStates = new VideoStateMap();\n const openRouterVideoJobs = new OpenRouterVideoJobMap();\n const veoVideoJobs = new VeoVideoJobMap();\n const grokVideoJobs = new GrokVideoJobMap();\n\n // Share journal and metrics registry with mounted services\n if (mounts) {\n for (const { handler } of mounts) {\n if (handler.setJournal) handler.setJournal(journal);\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n }\n }\n\n // Set initial fixtures-loaded gauge\n if (registry) {\n registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\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 handleHttpRequest(req, res).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n const stack = err instanceof Error ? (err.stack ?? msg) : msg;\n const method = req.method ?? \"?\";\n const url = req.url ?? \"?\";\n defaults.logger.warn(`Unhandled request error on ${method} ${url}: ${msg}\\n${stack}`);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: { message: msg, type: \"server_error\" } }));\n } else if (!res.writableEnded) {\n res.end();\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 // Parse the URL pathname (strip query string)\n const parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n let 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\n // Instrument response completion for metrics. The finish callback reads\n // pathname via closure after normalizeCompatPath has rewritten it, so\n // metrics record the canonical /v1/... path.\n if (registry) {\n res.on(\"finish\", () => {\n try {\n const normalizedPath = normalizePathLabel(pathname);\n const method = req.method ?? \"UNKNOWN\";\n const status = String(res.statusCode);\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 }\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\");\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 fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n defaults,\n );\n return;\n }\n\n // Dispatch to mounted services before any path rewrites\n if (mounts) {\n for (const { path: mountPath, handler } of mounts) {\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\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video content: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // guarded on headersSent so a throw after a successful journal +\n // response does not double-journal. Wrapped so journaling can\n // never mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video content: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video models: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // guarded on headersSent so a throw after a successful journal +\n // response does not double-journal. Wrapped so journaling can\n // never mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video models: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video status: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // guarded on headersSent so a throw after a successful journal +\n // response does not double-journal. Wrapped so journaling can\n // never mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\n }\n return;\n }\n\n // POST /api/v1/videos — submit a video generation job\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video submit: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // on submit a throw may have already consumed a fixture-sequence\n // slot, which would otherwise leave no trace. Guarded on\n // headersSent so a throw after a successful journal + response\n // does not double-journal (the guard only covers post-write\n // throws — a throw between the handler's journal.add and its\n // writeHead would still double-journal, though that window is\n // effectively throw-free today). Wrapped so journaling can never\n // mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 === \"/api/v1/models\" && req.method === \"GET\") {\n handleOpenRouterModels(req, res, fixtures, journal, defaults, setCorsHeaders);\n return;\n }\n if (pathname === \"/api/v1/key\" && req.method === \"GET\") {\n handleOpenRouterKey(req, res, journal, setCorsHeaders);\n return;\n }\n if (pathname === \"/api/v1/credits\" && 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 (mounts && mounts.length > 0) {\n const services: Record<string, unknown> = {\n llm: { status: \"ok\", fixtures: fixtures.length },\n };\n for (const { path: mountPath, handler } of mounts) {\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\" && 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 // 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 = parseInt(limitParam, 10);\n if (Number.isNaN(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/fixtures.\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 );\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`grok-video submit: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `grok-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`grok-video status: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `grok-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`veo-video submit: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `veo-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`veo-video status: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `veo-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`data: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`data: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`data: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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_PREFIX_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 const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);\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: { model: \"\", messages: [] },\n },\n \"fixture\",\n defaults.registry,\n );\n return;\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);\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: { model: \"\", messages: [] },\n },\n \"fixture\",\n defaults.registry,\n );\n return;\n }\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\n }\n return;\n }\n\n // POST /v1/chat/completions — Chat Completions API\n if (pathname !== COMPLETIONS_PATH) {\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 : \"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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n isOpenRouter\n ? serializeOpenRouterError(500, msg)\n : JSON.stringify({\n error: {\n message: msg,\n type: \"server_error\",\n },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (SSE stream in progress) — write error event then close\n try {\n res.write(\n `data: ${\n isOpenRouter\n ? serializeOpenRouterError(500, msg)\n : JSON.stringify({ error: { message: msg, type: \"server_error\" } })\n }\\n\\n`,\n );\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n }\n }\n }\n\n // ─── WebSocket upgrade handling ──────────────────────────────────────────\n\n const activeConnections = new Set<WebSocketConnection>();\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 async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n const parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\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 if (mounts) {\n for (const { path: mountPath, handler } of mounts) {\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\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 ) {\n socket.write(\"HTTP/1.1 404 Not Found\\r\\n\\r\\n\");\n socket.destroy();\n return;\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);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"WebSocket upgrade failed\";\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 === 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 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 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 // Set base URL on mounted services that support it\n if (mounts) {\n for (const { path: mountPath, handler } of mounts) {\n if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);\n }\n }\n\n resolve({\n server,\n journal,\n url,\n defaults,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\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 type {\n Fixture,\n FixtureFileEntry,\n ChatCompletionRequest,\n HandlerDefaults,\n MockServerOptions,\n Mountable,\n RecordProviderKey,\n} from \"./types.js\";\nimport { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport { validateFixtures, entryToFixture } 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 resolveFixtureBlocks,\n extractOverrides,\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n serializeErrorResponse,\n isAudioResponse,\n flattenHeaders,\n getTestId,\n readBody,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n getContext,\n} from \"./helpers.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 { handleElevenLabsAudio, handleElevenLabsTTS } from \"./elevenlabs-audio.js\";\nimport { handleFalQueue, falJobs } from \"./fal-audio.js\";\nimport { handleFal, falQueueStates } 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 { upgradeToWebSocket, type WebSocketConnection } from \"./ws-framing.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 { applyChaosAction, evaluateChaos } from \"./chaos.js\";\nimport {\n createMetricsRegistry,\n normalizePathLabel,\n OPENROUTER_VIDEO_CONTENT_RE,\n OPENROUTER_VIDEO_STATUS_RE,\n VEO_PREDICT_LRO_RE,\n VEO_OPERATION_RE,\n GROK_VIDEO_SUBMIT_PATH,\n GROK_VIDEO_STATUS_RE,\n} 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\";\n\nexport interface ServerInstance {\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}\n\nconst COMPLETIONS_PATH = \"/v1/chat/completions\";\nconst RESPONSES_PATH = \"/v1/responses\";\nconst REALTIME_PATH = \"/v1/realtime\";\nconst GEMINI_LIVE_PATH =\n \"/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent\";\nconst MESSAGES_PATH = \"/v1/messages\";\nconst EMBEDDINGS_PATH = \"/v1/embeddings\";\nconst COHERE_CHAT_PATH = \"/v2/chat\";\nconst COHERE_EMBED_PATH = \"/v2/embed\";\nconst SEARCH_PATH = \"/search\";\nconst RERANK_PATH = \"/v2/rerank\";\nconst MODERATIONS_PATH = \"/v1/moderations\";\nconst IMAGES_PATH = \"/v1/images/generations\";\nconst IMAGES_EDIT_PATH = \"/v1/images/edits\";\nconst IMAGES_VARIATIONS_PATH = \"/v1/images/variations\";\nconst SPEECH_PATH = \"/v1/audio/speech\";\nconst TRANSCRIPTIONS_PATH = \"/v1/audio/transcriptions\";\nconst TRANSLATIONS_PATH = \"/v1/audio/translations\";\nconst VIDEOS_PATH = \"/v1/videos\";\nconst GEMINI_PREDICT_RE = /^\\/v1beta\\/models\\/([^:]+):predict$/;\nconst ELEVENLABS_SOUND_GENERATION_PATH = \"/v1/sound-generation\";\nconst ELEVENLABS_TTS_RE = /^\\/v1\\/text-to-speech\\/([^/]+)$/;\nconst ELEVENLABS_MUSIC_RE = /^\\/v1\\/music(?:\\/(.+))?$/;\nconst FAL_QUEUE_SUBMIT_RE = /^\\/fal\\/queue\\/submit\\/(.+)$/;\nconst FAL_QUEUE_REQUESTS_RE = /^\\/fal\\/queue\\/requests\\/(.+)$/;\nconst FAL_RUN_RE = /^\\/fal\\/run\\/(.+)$/;\nconst FAL_PREFIX_RE = /^\\/fal(?:\\/.*)?$/;\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\nconst GEMINI_INTERACTIONS_PATH = \"/v1beta/interactions\";\nconst GEMINI_PATH_RE = /^\\/v1beta\\/models\\/([^:]+):(generateContent|streamGenerateContent)$/;\nconst GEMINI_EMBED_RE = /^\\/v1beta\\/models\\/([^:]+):embedContent$/;\nconst AZURE_DEPLOYMENT_RE = /^\\/openai\\/deployments\\/([^/]+)\\/(chat\\/completions|embeddings)$/;\nconst BEDROCK_INVOKE_RE = /^\\/model\\/([^/]+)\\/invoke$/;\nconst BEDROCK_STREAM_RE = /^\\/model\\/([^/]+)\\/invoke-with-response-stream$/;\nconst BEDROCK_CONVERSE_RE = /^\\/model\\/([^/]+)\\/converse$/;\nconst BEDROCK_CONVERSE_STREAM_RE = /^\\/model\\/([^/]+)\\/converse-stream$/;\nconst VERTEX_AI_RE =\n /^\\/v1\\/projects\\/[^/]+\\/locations\\/[^/]+\\/publishers\\/google\\/models\\/([^/:]+):(generateContent|streamGenerateContent)$/;\n\nconst OLLAMA_CHAT_PATH = \"/api/chat\";\nconst OLLAMA_GENERATE_PATH = \"/api/generate\";\nconst OLLAMA_EMBEDDINGS_PATH = \"/api/embeddings\";\nconst OLLAMA_EMBED_PATH = \"/api/embed\";\nconst OLLAMA_TAGS_PATH = \"/api/tags\";\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 metrics.ts path-label normalization\n// (imported above).\nconst OPENROUTER_VIDEOS_PATH = \"/api/v1/videos\";\nconst OPENROUTER_VIDEO_MODELS_PATH = \"/api/v1/videos/models\";\n\nconst HEALTH_PATH = \"/health\";\nconst READY_PATH = \"/ready\";\nconst MODELS_PATH = \"/v1/models\";\nconst REQUESTS_PATH = \"/v1/_requests\";\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 \"Access-Control-Allow-Methods\": \"GET, POST, DELETE, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"*\",\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\nconst CONTROL_PREFIX = \"/__aimock\";\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 defaults: HandlerDefaults;\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, and the Gemini interaction/event-id counters, then re-zero\n * the `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 fixtures.length = 0;\n falJobs.clear();\n falQueueStates.clear();\n resetInteractionCounter();\n resetEventIdCounter();\n if (!targets) return;\n targets.journal.clear();\n targets.videoStates.clear();\n targets.openRouterVideoJobs.clear();\n targets.veoVideoJobs.clear();\n targets.grokVideoJobs.clear();\n if (targets.defaults.registry) {\n targets.defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\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 fixtures: Fixture[],\n journal: Journal,\n videoStates: VideoStateMap,\n openRouterVideoJobs: OpenRouterVideoJobMap,\n veoVideoJobs: VeoVideoJobMap,\n grokVideoJobs: GrokVideoJobMap,\n defaults: HandlerDefaults,\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/journal\n if (subPath === \"/journal\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(journal.getAll()));\n return true;\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[] };\n try {\n parsed = JSON.parse(raw) as { fixtures?: FixtureFileEntry[] };\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 if (!Array.isArray(parsed.fixtures)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: 'Missing or invalid \"fixtures\" array' }));\n return true;\n }\n\n const converted = parsed.fixtures.map((e) => entryToFixture(e));\n const issues = validateFixtures(converted);\n const errors = issues.filter((i) => i.severity === \"error\");\n if (errors.length > 0) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Validation failed\", details: errors }));\n return true;\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(JSON.stringify({ added: converted.length }));\n return true;\n }\n\n // DELETE /__aimock/fixtures — clear all fixtures\n if (subPath === \"/fixtures\" && req.method === \"DELETE\") {\n fixtures.length = 0;\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 defaults,\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 const status = parsed.status ?? 500;\n const errorBody = parsed.body;\n const errorFixture: Fixture = {\n match: { predicate: () => true },\n response: {\n error: {\n message: errorBody?.message ?? \"Injected error\",\n type: errorBody?.type ?? \"server_error\",\n code: errorBody?.code,\n },\n status,\n },\n };\n // Insert at front so it matches before everything else\n fixtures.unshift(errorFixture);\n // One-shot: match once then self-remove. We use a `consumed` flag to\n // prevent double-matching from concurrent requests and defer the actual\n // splice via queueMicrotask so it never mutates the fixtures array while\n // matchFixture is iterating over it.\n let consumed = false;\n const original = errorFixture.match.predicate!;\n errorFixture.match.predicate = (req) => {\n if (consumed) return false;\n const result = original(req);\n if (result) {\n consumed = true;\n queueMicrotask(() => {\n const idx = fixtures.indexOf(errorFixture);\n if (idx !== -1) fixtures.splice(idx, 1);\n });\n }\n return result;\n };\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\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 journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n writeErrorResponse(\n res,\n 500,\n openRouter\n ? serializeOpenRouterError(500, `Request body read failed: ${msg}`)\n : JSON.stringify({\n error: {\n message: `Request body read failed: ${msg}`,\n type: \"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 // Azure deployments may omit model from body — use deployment ID as fallback\n if (modelFallback && !body.model) {\n body.model = modelFallback;\n }\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 // 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 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\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 = matchFixtureDiagnostic(\n fixtures,\n probe,\n matchCounts,\n defaults.requestTransform,\n matchOptions,\n );\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 = matchFixtureDiagnostic(\n fixtures,\n body,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n matchOptions,\n );\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 defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\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 const chaosAction = evaluateChaos(fixture, defaults.chaos, req.headers, defaults.logger);\n const chaosContext = { method, path, headers: flatHeaders, body };\n\n if (chaosAction === \"drop\" || chaosAction === \"disconnect\") {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n );\n return;\n }\n\n if (fixture && chaosAction === \"malformed\") {\n applyChaosAction(\n chaosAction,\n res,\n fixture,\n journal,\n chaosContext,\n \"fixture\",\n defaults.registry,\n );\n return;\n }\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\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 );\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 const 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 if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n // outcome === \"not_configured\" — fall through to 404\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 // Resolve the ordered streaming blocks ONCE, BEFORE recording success in the\n // journal. resolveFixtureBlocks validates and can throw on a malformed\n // `blocks` array; doing it here (rather than inside the chunk builder AND a\n // second time for the usage estimate, both of which previously ran AFTER\n // journal.add) guarantees a malformed fixture never leaves a spurious\n // status-200 journal entry. The single resolved array is reused for both\n // chunk emission and the completion-token estimate — the builder re-normalizes\n // it idempotently (a can't-fail pass on already-validated blocks), so this is\n // the only resolution that can throw. Only the streaming path consumes blocks\n // (the non-streaming builder ignores them), so gate on `stream` to leave the\n // non-streaming path's behavior byte-identical.\n const streaming = body.stream === true;\n const streamingBlocks =\n streaming && response.blocks && response.blocks.length > 0\n ? resolveFixtureBlocks(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 response.content ?? \"\",\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 = buildContentWithToolCallsChunks(\n response.content ?? \"\",\n response.toolCalls ?? [],\n responseModel,\n chunkSize,\n effReasoning,\n overrides,\n streamingBlocks,\n );\n // Build usage chunk for stream_options.include_usage (always for OpenRouter).\n // When the fixture is blocks-driven, the streamed text comes from the\n // ordered blocks (content/toolCalls are ignored by the chunk builder), so\n // the completion-token estimate must derive from the SAME block text —\n // otherwise a blocks-only fixture reports ~1 completion token. Reuse the\n // single pre-resolved `streamingBlocks` (no second resolveFixtureBlocks).\n const completionText = streamingBlocks\n ? streamingBlocks.map((b) => (b.type === \"text\" ? b.text : b.name + b.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}\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 host = options?.host ?? \"127.0.0.1\";\n const port = options?.port ?? 0;\n const logger = new Logger(options?.logLevel ?? \"silent\");\n const registry = options?.metrics ? createMetricsRegistry() : undefined;\n const serverOptions = options ?? {};\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 get chaos() {\n return serverOptions.chaos;\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 };\n\n // Validate chaos config rates\n if (options?.chaos) {\n const chaosRates = [\n { name: \"dropRate\", value: options.chaos.dropRate },\n { name: \"malformedRate\", value: options.chaos.malformedRate },\n { name: \"disconnectRate\", value: options.chaos.disconnectRate },\n ];\n for (const { name, value } of chaosRates) {\n if (value !== undefined && (value < 0 || value > 1)) {\n logger.warn(`Chaos ${name} (${value}) is outside 0-1 range — will be clamped at runtime`);\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 ]) {\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 // 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 });\n const videoStates = new VideoStateMap();\n const openRouterVideoJobs = new OpenRouterVideoJobMap();\n const veoVideoJobs = new VeoVideoJobMap();\n const grokVideoJobs = new GrokVideoJobMap();\n\n // Share journal and metrics registry with mounted services\n if (mounts) {\n for (const { handler } of mounts) {\n if (handler.setJournal) handler.setJournal(journal);\n if (registry && handler.setRegistry) handler.setRegistry(registry);\n }\n }\n\n // Set initial fixtures-loaded gauge\n if (registry) {\n registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\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 handleHttpRequest(req, res).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n const stack = err instanceof Error ? (err.stack ?? msg) : msg;\n const method = req.method ?? \"?\";\n const url = req.url ?? \"?\";\n defaults.logger.warn(`Unhandled request error on ${method} ${url}: ${msg}\\n${stack}`);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: { message: msg, type: \"server_error\" } }));\n } else if (!res.writableEnded) {\n res.end();\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 // Parse the URL pathname (strip query string)\n const parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n let 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\n // Instrument response completion for metrics. The finish callback reads\n // pathname via closure after normalizeCompatPath has rewritten it, so\n // metrics record the canonical /v1/... path.\n if (registry) {\n res.on(\"finish\", () => {\n try {\n const normalizedPath = normalizePathLabel(pathname);\n const method = req.method ?? \"UNKNOWN\";\n const status = String(res.statusCode);\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 }\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\");\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 fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n defaults,\n );\n return;\n }\n\n // Dispatch to mounted services before any path rewrites\n if (mounts) {\n for (const { path: mountPath, handler } of mounts) {\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\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video content: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // guarded on headersSent so a throw after a successful journal +\n // response does not double-journal. Wrapped so journaling can\n // never mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video content: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video models: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // guarded on headersSent so a throw after a successful journal +\n // response does not double-journal. Wrapped so journaling can\n // never mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video models: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video status: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // guarded on headersSent so a throw after a successful journal +\n // response does not double-journal. Wrapped so journaling can\n // never mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\n }\n return;\n }\n\n // POST /api/v1/videos — submit a video generation job\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`openrouter-video submit: ${msg}`);\n if (!res.headersSent) {\n // Journal the failed request so it isn't invisible to consumers —\n // on submit a throw may have already consumed a fixture-sequence\n // slot, which would otherwise leave no trace. Guarded on\n // headersSent so a throw after a successful journal + response\n // does not double-journal (the guard only covers post-write\n // throws — a throw between the handler's journal.add and its\n // writeHead would still double-journal, though that window is\n // effectively throw-free today). Wrapped so journaling can never\n // mask the 500 write below.\n try {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `openrouter-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 === \"/api/v1/models\" && req.method === \"GET\") {\n handleOpenRouterModels(req, res, fixtures, journal, defaults, setCorsHeaders);\n return;\n }\n if (pathname === \"/api/v1/key\" && req.method === \"GET\") {\n handleOpenRouterKey(req, res, journal, setCorsHeaders);\n return;\n }\n if (pathname === \"/api/v1/credits\" && 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 (mounts && mounts.length > 0) {\n const services: Record<string, unknown> = {\n llm: { status: \"ok\", fixtures: fixtures.length },\n };\n for (const { path: mountPath, handler } of mounts) {\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\" && 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 // 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 = parseInt(limitParam, 10);\n if (Number.isNaN(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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`event: error\\ndata: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 );\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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(req, res, raw, fixtures, journal, defaults, setCorsHeaders);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`grok-video submit: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `grok-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`grok-video status: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `grok-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`veo-video submit: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `veo-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`veo-video status: ${msg}`);\n if (!res.headersSent) {\n try {\n journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 500, fixture: null },\n });\n } catch (jErr) {\n defaults.logger.warn(\n `veo-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`,\n );\n }\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`data: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`data: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n try {\n res.write(`data: ${JSON.stringify({ error: { message: msg } })}\\n\\n`);\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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_PREFIX_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 const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);\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: { model: \"\", messages: [] },\n },\n \"fixture\",\n defaults.registry,\n );\n return;\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const chaosAction = evaluateChaos(null, defaults.chaos, req.headers, defaults.logger);\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: { model: \"\", messages: [] },\n },\n \"fixture\",\n defaults.registry,\n );\n return;\n }\n await handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\n }\n return;\n }\n\n // POST /v1/chat/completions — Chat Completions API\n if (pathname !== COMPLETIONS_PATH) {\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 : \"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 const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n isOpenRouter\n ? serializeOpenRouterError(500, msg)\n : JSON.stringify({\n error: {\n message: msg,\n type: \"server_error\",\n },\n }),\n );\n } else if (!res.writableEnded) {\n // Headers already sent (SSE stream in progress) — write error event then close\n try {\n res.write(\n `data: ${\n isOpenRouter\n ? serializeOpenRouterError(500, msg)\n : JSON.stringify({ error: { message: msg, type: \"server_error\" } })\n }\\n\\n`,\n );\n res.end();\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n }\n }\n }\n\n // ─── WebSocket upgrade handling ──────────────────────────────────────────\n\n const activeConnections = new Set<WebSocketConnection>();\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 async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n const parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\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 if (mounts) {\n for (const { path: mountPath, handler } of mounts) {\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\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 ) {\n socket.write(\"HTTP/1.1 404 Not Found\\r\\n\\r\\n\");\n socket.destroy();\n return;\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);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"WebSocket upgrade failed\";\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 === 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 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 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 // Set base URL on mounted services that support it\n if (mounts) {\n for (const { path: mountPath, handler } of mounts) {\n if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);\n }\n }\n\n resolve({\n server,\n journal,\n url,\n defaults,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n });\n });\n });\n}\n"],"mappings":"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"}
|