@copilotkit/aimock 1.41.0 → 1.42.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/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +12 -1
- package/README.md +2 -1
- package/dist/a2a-mock.cjs +18 -11
- package/dist/a2a-mock.cjs.map +1 -1
- package/dist/a2a-mock.d.cts +1 -0
- package/dist/a2a-mock.d.cts.map +1 -1
- package/dist/a2a-mock.d.ts +1 -0
- package/dist/a2a-mock.d.ts.map +1 -1
- package/dist/a2a-mock.js +18 -11
- package/dist/a2a-mock.js.map +1 -1
- package/dist/agui-handler.d.ts.map +1 -1
- package/dist/agui-mock.cjs +2 -0
- package/dist/agui-mock.cjs.map +1 -1
- package/dist/agui-mock.d.cts.map +1 -1
- package/dist/agui-mock.d.ts.map +1 -1
- package/dist/agui-mock.js +2 -0
- package/dist/agui-mock.js.map +1 -1
- package/dist/bedrock-converse.cjs +36 -2
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +37 -3
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +50 -13
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +51 -14
- package/dist/bedrock.js.map +1 -1
- package/dist/byteplus-video.cjs +2 -2
- package/dist/byteplus-video.cjs.map +1 -1
- package/dist/byteplus-video.d.cts.map +1 -1
- package/dist/byteplus-video.d.ts.map +1 -1
- package/dist/byteplus-video.js +2 -2
- package/dist/byteplus-video.js.map +1 -1
- package/dist/chaos.cjs +36 -7
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts +8 -3
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts +8 -3
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +36 -8
- package/dist/chaos.js.map +1 -1
- package/dist/cohere.cjs +58 -5
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +59 -6
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/elevenlabs-audio.cjs +36 -2
- package/dist/elevenlabs-audio.cjs.map +1 -1
- package/dist/elevenlabs-audio.d.cts.map +1 -1
- package/dist/elevenlabs-audio.d.ts.map +1 -1
- package/dist/elevenlabs-audio.js +37 -3
- package/dist/elevenlabs-audio.js.map +1 -1
- package/dist/embeddings.cjs +58 -3
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +59 -4
- package/dist/embeddings.js.map +1 -1
- package/dist/fal-audio.cjs +38 -2
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.d.cts.map +1 -1
- package/dist/fal-audio.d.ts.map +1 -1
- package/dist/fal-audio.js +39 -3
- package/dist/fal-audio.js.map +1 -1
- package/dist/fixture-loader.cjs +0 -0
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +9 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +9 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +0 -0
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-embeddings.cjs +19 -1
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +20 -2
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +15 -1
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +16 -2
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +70 -6
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +71 -7
- package/dist/gemini.js.map +1 -1
- package/dist/grok-video.cjs +2 -2
- package/dist/grok-video.cjs.map +1 -1
- package/dist/grok-video.d.cts.map +1 -1
- package/dist/grok-video.d.ts.map +1 -1
- package/dist/grok-video.js +2 -2
- package/dist/grok-video.js.map +1 -1
- package/dist/helpers.cjs +160 -5
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +152 -6
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +22 -4
- package/dist/images.cjs.map +1 -1
- package/dist/images.d.cts.map +1 -1
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js +23 -5
- package/dist/images.js.map +1 -1
- package/dist/llmock.cjs +15 -0
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +12 -0
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +12 -0
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +16 -1
- package/dist/llmock.js.map +1 -1
- package/dist/mcp-mock.cjs +11 -0
- package/dist/mcp-mock.cjs.map +1 -1
- package/dist/mcp-mock.d.cts.map +1 -1
- package/dist/mcp-mock.d.ts.map +1 -1
- package/dist/mcp-mock.js +11 -0
- package/dist/mcp-mock.js.map +1 -1
- package/dist/messages.cjs +18 -1
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +19 -2
- package/dist/messages.js.map +1 -1
- package/dist/moderation.cjs +67 -3
- package/dist/moderation.cjs.map +1 -1
- package/dist/moderation.d.cts +1 -0
- package/dist/moderation.d.cts.map +1 -1
- package/dist/moderation.d.ts +1 -0
- package/dist/moderation.d.ts.map +1 -1
- package/dist/moderation.js +68 -4
- package/dist/moderation.js.map +1 -1
- package/dist/ollama.cjs +75 -5
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +76 -6
- package/dist/ollama.js.map +1 -1
- package/dist/openrouter-video.cjs +4 -4
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +4 -4
- package/dist/openrouter-video.js.map +1 -1
- package/dist/rerank.cjs +65 -2
- package/dist/rerank.cjs.map +1 -1
- package/dist/rerank.d.cts +1 -1
- package/dist/rerank.d.cts.map +1 -1
- package/dist/rerank.d.ts +1 -1
- package/dist/rerank.d.ts.map +1 -1
- package/dist/rerank.js +66 -3
- package/dist/rerank.js.map +1 -1
- package/dist/responses.cjs +18 -1
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +19 -2
- package/dist/responses.js.map +1 -1
- package/dist/search.cjs +67 -3
- package/dist/search.cjs.map +1 -1
- package/dist/search.d.cts +1 -0
- package/dist/search.d.cts.map +1 -1
- package/dist/search.d.ts +1 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +68 -4
- package/dist/search.js.map +1 -1
- package/dist/server.cjs +317 -13
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +320 -16
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +18 -1
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.d.cts.map +1 -1
- package/dist/speech.d.ts.map +1 -1
- package/dist/speech.js +19 -2
- package/dist/speech.js.map +1 -1
- package/dist/transcription.cjs +21 -2
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +21 -2
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +39 -2
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +39 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-mock.cjs +88 -0
- package/dist/vector-mock.cjs.map +1 -1
- package/dist/vector-mock.d.cts.map +1 -1
- package/dist/vector-mock.d.ts.map +1 -1
- package/dist/vector-mock.js +89 -1
- package/dist/vector-mock.js.map +1 -1
- package/dist/veo-video.cjs +2 -2
- package/dist/veo-video.cjs.map +1 -1
- package/dist/veo-video.d.cts.map +1 -1
- package/dist/veo-video.d.ts.map +1 -1
- package/dist/veo-video.js +2 -2
- package/dist/veo-video.js.map +1 -1
- package/dist/video.cjs +19 -2
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +20 -3
- package/dist/video.js.map +1 -1
- package/package.json +1 -1
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 {\n handleBytePlusVideoCreate,\n handleBytePlusVideoStatus,\n BytePlusVideoJobMap,\n} from \"./byteplus-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 BYTEPLUS_VIDEO_STATUS_RE,\n BYTEPLUS_VIDEO_SUBMIT_RE,\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 bytePlusVideoJobs: BytePlusVideoJobMap;\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 bytePlusVideoJobs: BytePlusVideoJobMap;\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 targets.bytePlusVideoJobs.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 bytePlusVideoJobs: BytePlusVideoJobMap,\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 // GET /__aimock/fixtures — inspect current fixture count\n if (subPath === \"/fixtures\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ count: fixtures.length }));\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 bytePlusVideoJobs,\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 get bytePlusVideo() {\n return serverOptions.bytePlusVideo;\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 { name: \"bytePlusVideo\", config: options?.bytePlusVideo },\n ]) {\n if (!config) continue;\n for (const field of [\"pollsBeforeInProgress\", \"pollsBeforeCompleted\"] as const) {\n const value = config[field];\n if (value === undefined) continue;\n if (!Number.isFinite(value)) {\n logger.warn(`${name}.${field} (${value}) is not a finite number — treating as unset`);\n } else if (!Number.isInteger(value) || value < 0) {\n logger.warn(\n `${name}.${field} (${value}) is not a non-negative integer — flooring/clamping to a non-negative integer`,\n );\n }\n }\n }\n\n // Validate the recorded-b64 cap: the capture path treats a negative or\n // non-integer record.openRouterVideo.maxContentBytes as the default rather\n // than letting `cap > 0` checks misbehave on negatives or NaN.\n {\n const cap = options?.record?.openRouterVideo?.maxContentBytes;\n if (cap !== undefined && (!Number.isInteger(cap) || cap < 0)) {\n logger.warn(\n `record.openRouterVideo.maxContentBytes (${cap}) is not a non-negative integer — using the default cap (${OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES})`,\n );\n }\n }\n\n // Reject a BytePlus upstream base that already carries Ark's `/api/v3`\n // prefix. `record.providers.byteplus` is an ORIGIN: the video handlers pass\n // the full `/api/v3/contents/generations/tasks[...]` constant to\n // resolveUpstreamUrl, and the chat/images proxies relay the client's raw\n // `req.url` (which is itself `/api/v3/...`). `@tanstack/ai-byteplus@0.3.4`\n // ships `https://ark.ap-southeast.bytepluses.com/api/v3` as its default Ark\n // `base_url` (`BYTEPLUS_ARK_BASE_URL`, which its own author labels\n // \"Docs-derived\" — this repo has not read BytePlus's docs), so pasting that\n // into --provider-byteplus is the expected mistake, and it composes\n // `/api/v3/api/v3/...` on every BytePlus path. The origin+prefix itself IS\n // observed to serve: a keyless GET under it answers 401, not 404.\n //\n // This THROWS rather than silently stripping the suffix, for two reasons.\n // (1) Nothing is being taken away: the doubled form cannot serve any\n // BytePlus request, so there is no working configuration to preserve —\n // whereas a silent strip would make aimock rewrite an operator-supplied URL\n // and would be flatly wrong for the one case where a path-suffixed base is\n // deliberate (a reverse proxy mounted under a path: stripping sends the\n // request to the origin, bypassing the mount). (2) A warn is easy to miss in\n // a mock server's log stream, and the symptom it leaves behind — a relayed\n // upstream 404 — does not name its cause. Fail at startup, where the message\n // can.\n {\n const bytePlusBase = options?.record?.providers?.byteplus;\n if (bytePlusBase !== undefined) {\n let basePath: string | undefined;\n try {\n basePath = new URL(bytePlusBase).pathname;\n } catch {\n // Not parseable as an absolute URL — leave it to the request path to\n // report; this guard only speaks to the prefix-doubling mistake.\n }\n if (basePath !== undefined && /(^|\\/)api\\/v3\\/?$/.test(basePath)) {\n throw new Error(\n `record.providers.byteplus (${bytePlusBase}) ends in /api/v3, but aimock ` +\n `appends the /api/v3 prefix itself — every BytePlus request would go to ` +\n `/api/v3/api/v3/... and fail upstream. Configure the ORIGIN only ` +\n `(e.g. https://ark.ap-southeast.bytepluses.com).`,\n );\n }\n }\n }\n\n // 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 const bytePlusVideoJobs = new BytePlusVideoJobMap();\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 // BytePlus Ark attribution, GATED ON CONFIGURATION. A path prefix is not\n // evidence of a vendor — the COMPAT_SUFFIXES comment above exists precisely\n // because arbitrary vendors ride arbitrary prefixes (BigModel uses /v4/).\n // Ungated, anyone serving an OpenAI-compatible vendor under /api/v3 with\n // `record.providers.openai` configured would suddenly look up a byteplus\n // upstream, find none, and lose record mode entirely. Requiring a\n // configured byteplus upstream makes the new behavior reachable only for\n // the user who asked for it.\n const isBytePlusArk =\n defaults.record?.providers.byteplus !== undefined && originalPathname.startsWith(\"/api/v3/\");\n\n // 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 bytePlusVideoJobs,\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 // ── BytePlus Ark (Seedance) async video task lifecycle ──────────────────\n // Registered in the PRE-REWRITE band, alongside the OpenRouter video routes\n // above: normalizeCompatPath does not currently claim these paths, but the\n // Ollama block documents that hazard and the mount dispatch also runs\n // pre-rewrite, so keeping every raw-path route in one band keeps one rule.\n //\n // The REs anchor an ENUMERATED optional `/api/v3` prefix (see metrics.ts).\n // That matters here specifically because this band runs ~1,100 lines ahead\n // of every fal branch, so a wildcard prefix would take\n // `/fal/contents/generations/tasks` away from the fal proxy.\n //\n // Status is tested BEFORE submit and each is method-guarded, so a future\n // DELETE .../tasks/{id} falls through to 404 rather than being mis-served.\n const bytePlusVideoStatusMatch = pathname.match(BYTEPLUS_VIDEO_STATUS_RE);\n if (bytePlusVideoStatusMatch && req.method === \"GET\") {\n try {\n await handleBytePlusVideoStatus(\n req,\n res,\n bytePlusVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`byteplus-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 `byteplus-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 if (BYTEPLUS_VIDEO_SUBMIT_RE.test(pathname) && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleBytePlusVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`byteplus-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 `byteplus-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(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"openai\",\n undefined,\n isBytePlusArk ? \"byteplus\" : undefined,\n );\n } catch (err: unknown) {\n 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 : isBytePlusArk\n ? \"byteplus\"\n : \"openai\";\n try {\n await handleCompletions(\n req,\n res,\n fixtures,\n journal,\n defaults,\n azureDeploymentId,\n completionsProvider,\n isOpenRouter,\n );\n } catch (err: unknown) {\n 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 /**\n * Body bytes the platform already parsed onto `req` for an upgrade request.\n *\n * Node >= 26 delivers an upgrade request's body here and leaves `head`\n * empty; Node <= 24 leaves the body in `head` and ends `req` with nothing.\n * The stream has already ended in both cases, so this resolves on the next\n * tick either way — it never waits on the network.\n */\n function drainParsedRequestBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n let settled = false;\n const done = (): void => {\n if (settled) return;\n settled = true;\n resolve(Buffer.concat(chunks));\n };\n req.on(\"data\", (c: Buffer) => chunks.push(c));\n req.on(\"end\", done);\n req.on(\"error\", done);\n req.on(\"close\", done);\n req.resume();\n });\n }\n\n async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n // `Upgrade: h2c` + `Connection: Upgrade` on plain requests — including\n // ones with a body — to probe for HTTP/2 cleartext support. Only actual\n // WebSocket upgrades belong on this path.\n //\n // Node fires \"upgrade\" instead of \"request\" for any `Connection: Upgrade`,\n // whatever protocol is named, and the request never reaches the normal\n // pipeline. Rather than reimplementing body parsing, rebuild the request\n // line and headers with `Upgrade`/`Connection` dropped — the only thing\n // that made this look like an upgrade — replay them onto the socket, and\n // let Node re-parse the connection from scratch as an ordinary request.\n //\n // WHERE THE BODY LIVES DEPENDS ON THE NODE VERSION, and both cases must be\n // replayed or the re-parsed request stalls forever waiting on a\n // `Content-Length` worth of bytes that will never arrive:\n //\n // - Node <= 24 detaches the parser at \"upgrade\", so `req` yields nothing\n // and any body bytes already read land in `head` (or, if the client\n // sent them later, still arrive on the socket afterwards).\n // - Node >= 26 parses the body onto `req` and leaves `head` EMPTY. The\n // bytes are not on the socket either — draining `req` is the only way\n // to get them back.\n //\n // Draining `req` is safe on both: on the older behaviour it ends\n // immediately with zero bytes, so the concat below is a no-op there and\n // `head` carries the body as before.\n if ((req.headers.upgrade ?? \"\").toLowerCase() !== \"websocket\") {\n const parsedBody = await drainParsedRequestBody(req);\n const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\\r\\n`;\n const headerLines: string[] = [];\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n if (/^(?:upgrade|connection)$/i.test(req.rawHeaders[i])) continue;\n headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);\n }\n const rebuilt = Buffer.from(requestLine + headerLines.join(\"\\r\\n\") + \"\\r\\n\\r\\n\");\n socket.unshift(Buffer.concat([rebuilt, parsedBody, head]));\n server.emit(\"connection\", socket);\n return;\n }\n\n 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 bytePlusVideoJobs.clear();\n originalClose(callback);\n return this;\n } as typeof server.close;\n\n return new Promise<ServerInstance>((resolve, reject) => {\n server.on(\"error\", reject);\n server.listen(port, host, () => {\n const addr = server.address();\n if (!addr || typeof addr === \"string\") {\n reject(new Error(\"Unexpected address format\"));\n return;\n }\n const url = `http://${addr.address}:${addr.port}`;\n\n // 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 bytePlusVideoJobs,\n });\n });\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4IA,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;AACtB,MAAM,mBACJ;AACF,MAAM,gBAAgB;AACtB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAC1B,MAAM,cAAc;AACpB,MAAM,cAAc;AACpB,MAAM,mBAAmB;AACzB,MAAM,cAAc;AACpB,MAAM,mBAAmB;AACzB,MAAM,yBAAyB;AAC/B,MAAM,cAAc;AACpB,MAAM,sBAAsB;AAC5B,MAAM,oBAAoB;AAC1B,MAAM,cAAc;AACpB,MAAM,oBAAoB;AAC1B,MAAM,mCAAmC;AACzC,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB;AAC9B,MAAM,aAAa;AACnB,MAAM,gBAAgB;AACtB,MAAM,qBAAqB;AAQ3B,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;AAOD,SAAS,oBAAoB,UAAkB,QAAyB;AAEtE,KAAI,SAAS,WAAW,WAAW,CACjC,YAAW,SAAS,MAAM,EAAiB;AAI7C,KAAI,CAAC,SAAS,WAAW,OAAO,IAAI,CAAC,SAAS,WAAW,OAAO,EAC9D;OAAK,MAAM,UAAU,gBACnB,KAAI,SAAS,SAAS,OAAO,EAAE;AAC7B,OAAI,OAAQ,QAAO,MAAM,oBAAoB,SAAS,QAAQ,SAAS;AACvE,cAAW,QAAQ;AACnB;;;AAKN,QAAO;;AAGT,MAAM,2BAA2B;AACjC,MAAM,iBAAiB;AACvB,MAAM,kBAAkB;AACxB,MAAM,sBAAsB;AAC5B,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;AAC5B,MAAM,6BAA6B;AACnC,MAAM,eACJ;AAEF,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAC7B,MAAM,yBAAyB;AAC/B,MAAM,oBAAoB;AAC1B,MAAM,mBAAmB;AAOzB,MAAM,yBAAyB;AAC/B,MAAM,+BAA+B;AAErC,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,cAAc;AACpB,MAAM,gBAAgB;AAEtB,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,eAAuC;CAC3C,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;CACjC;AAED,SAAS,eAAe,KAAgC;AACtD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,aAAa,CACrD,KAAI,UAAU,KAAK,MAAM;;AAI7B,SAAS,cAAc,KAAgC;AACrD,gBAAe,IAAI;AACnB,KAAI,UAAU,IAAI;AAClB,KAAI,KAAK;;AAGX,SAAS,eAAe,KAA0B,SAAuB;AACvE,gBAAe,IAAI;AACnB,oBAAmB,KAAK,KAAK,KAAK,UAAU,EAAE,OAAO;EAAE;EAAS,MAAM;EAAa,EAAE,CAAC,CAAC;;AASzF,MAAM,iBAAiB;;;;;;;;;;;;;;AA8BvB,SAAgB,iBAAiB,UAAqB,SAAwC;AAC5F,UAAS,SAAS;AAClB,SAAQ,OAAO;AACf,gBAAe,OAAO;AACtB,0BAAyB;AACzB,sBAAqB;AACrB,KAAI,CAAC,QAAS;AACd,SAAQ,QAAQ,OAAO;AACvB,SAAQ,YAAY,OAAO;AAC3B,SAAQ,oBAAoB,OAAO;AACnC,SAAQ,aAAa,OAAO;AAC5B,SAAQ,cAAc,OAAO;AAC7B,SAAQ,kBAAkB,OAAO;AACjC,KAAI,QAAQ,SAAS,SACnB,SAAQ,SAAS,SAAS,SAAS,0BAA0B,EAAE,EAAE,SAAS,OAAO;;;;;;AAQrF,eAAe,iBACb,KACA,KACA,UACA,UACA,SACA,aACA,qBACA,cACA,eACA,mBACA,UACkB;AAClB,KAAI,CAAC,SAAS,WAAW,eAAe,CAAE,QAAO;CAEjD,MAAM,UAAU,SAAS,MAAM,EAAsB;AACrD,gBAAe,IAAI;AAGnB,KAAI,YAAY,aAAa,IAAI,WAAW,OAAO;AACjD,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,MAAM,CAAC,CAAC;AACzC,SAAO;;AAIT,KAAI,YAAY,cAAc,IAAI,WAAW,OAAO;AAClD,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,QAAQ,QAAQ,CAAC,CAAC;AACzC,SAAO;;AAIT,KAAI,YAAY,eAAe,IAAI,WAAW,OAAO;AACnD,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,OAAO,SAAS,QAAQ,CAAC,CAAC;AACnD,SAAO;;AAIT,KAAI,YAAY,eAAe,IAAI,WAAW,QAAQ;EACpD,IAAI;AACJ,MAAI;AACF,SAAM,MAAM,SAAS,IAAI;WAClB,KAAK;GACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,YAAS,OAAO,MAAM,iDAAiD,MAAM;AAC7E,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,gCAAgC,OAAO,CAAC,CAAC;AACzE,UAAO;;EAGT,IAAI;AACJ,MAAI;AACF,YAAS,KAAK,MAAM,IAAI;WACjB,KAAK;GACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,YAAS,OAAO,MAAM,0CAA0C,MAAM;AACtE,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,iBAAiB,OAAO,CAAC,CAAC;AAC1D,UAAO;;AAGT,MAAI,CAAC,MAAM,QAAQ,OAAO,SAAS,EAAE;AACnC,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,yCAAuC,CAAC,CAAC;AACzE,UAAO;;EAGT,MAAM,YAAY,OAAO,SAAS,KAAK,MAAM,eAAe,EAAE,CAAC;EAE/D,MAAM,SADS,iBAAiB,UAAU,CACpB,QAAQ,MAAM,EAAE,aAAa,QAAQ;AAC3D,MAAI,OAAO,SAAS,GAAG;AACrB,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU;IAAE,OAAO;IAAqB,SAAS;IAAQ,CAAC,CAAC;AACxE,UAAO;;AAGT,WAAS,KAAK,GAAG,UAAU;AAC3B,MAAI,SAAS,SACX,UAAS,SAAS,SAAS,0BAA0B,EAAE,EAAE,SAAS,OAAO;AAE3E,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,OAAO,UAAU,QAAQ,CAAC,CAAC;AACpD,SAAO;;AAIT,KAAI,YAAY,eAAe,IAAI,WAAW,UAAU;AACtD,WAAS,SAAS;AAClB,MAAI,SAAS,SACX,UAAS,SAAS,SAAS,0BAA0B,EAAE,EAAE,SAAS,OAAO;AAE3E,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,SAAS,MAAM,CAAC,CAAC;AAC1C,SAAO;;CAGT,MAAM,sBAAwC;EAC5C;EACA;EACA;EACA;EACA;EACA;EACA;EACD;AAID,KAAI,YAAY,YAAY,IAAI,WAAW,QAAQ;AACjD,mBAAiB,UAAU,cAAc,CAAC;AAC1C,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,OAAO,MAAM,CAAC,CAAC;AACxC,SAAO;;AAKT,KAAI,YAAY,oBAAoB,IAAI,WAAW,QAAQ;AACzD,UAAQ,cAAc;AACtB,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,OAAO,MAAM,CAAC,CAAC;AACxC,SAAO;;AAMT,KAAI,YAAY,qBAAqB,IAAI,WAAW,QAAQ;AAC1D,mBAAiB,UAAU,cAAc,CAAC;EAC1C,MAAM,cACJ;AACF,WAAS,OAAO,KACd,8FACD;AACD,MAAI,UAAU,KAAK;GAAE,gBAAgB;GAAoB,aAAa;GAAQ,CAAC;AAC/E,MAAI,IAAI,KAAK,UAAU;GAAE,OAAO;GAAM,YAAY;GAAM;GAAa,CAAC,CAAC;AACvE,SAAO;;AAIT,KAAI,YAAY,YAAY,IAAI,WAAW,QAAQ;EACjD,IAAI;AACJ,MAAI;AACF,SAAM,MAAM,SAAS,IAAI;WAClB,KAAK;GACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,YAAS,OAAO,MAAM,8CAA8C,MAAM;AAC1E,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,gCAAgC,OAAO,CAAC,CAAC;AACzE,UAAO;;EAGT,IAAI;AACJ,MAAI;AACF,YAAS,KAAK,MAAM,IAAI;WACjB,KAAK;GACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,YAAS,OAAO,MAAM,uCAAuC,MAAM;AACnE,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,iBAAiB,OAAO,CAAC,CAAC;AAC1D,UAAO;;EAGT,MAAM,SAAS,OAAO,UAAU;EAChC,MAAM,YAAY,OAAO;EACzB,MAAM,eAAwB;GAC5B,OAAO,EAAE,iBAAiB,MAAM;GAChC,UAAU;IACR,OAAO;KACL,SAAS,WAAW,WAAW;KAC/B,MAAM,WAAW,QAAQ;KACzB,MAAM,WAAW;KAClB;IACD;IACD;GACF;AAED,WAAS,QAAQ,aAAa;EAK9B,IAAI,WAAW;EACf,MAAM,WAAW,aAAa,MAAM;AACpC,eAAa,MAAM,aAAa,QAAQ;AACtC,OAAI,SAAU,QAAO;GACrB,MAAM,SAAS,SAAS,IAAI;AAC5B,OAAI,QAAQ;AACV,eAAW;AACX,yBAAqB;KACnB,MAAM,MAAM,SAAS,QAAQ,aAAa;AAC1C,SAAI,QAAQ,GAAI,UAAS,OAAO,KAAK,EAAE;MACvC;;AAEJ,UAAO;;AAGT,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,MAAM,CAAC,CAAC;AACzC,SAAO;;AAIT,gBAAe,KAAK,6BAA6B,WAAW;AAC5D,QAAO;;AAGT,eAAe,kBACb,KACA,KACA,UACA,SACA,UACA,eACA,aACA,aAAa,OACE;AACf,gBAAe,IAAI;CAGnB,IAAI;AACJ,KAAI;AACF,QAAM,MAAM,SAAS,IAAI;UAClB,KAAK;EACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,qBACE,KACA,KACA,aACI,yBAAyB,KAAK,6BAA6B,MAAM,GACjE,KAAK,UAAU,EACb,OAAO;GACL,SAAS,6BAA6B;GACtC,MAAM;GACP,EACF,CAAC,CACP;AACD;;CAIF,IAAI;AACJ,KAAI;AACF,SAAO,KAAK,MAAM,IAAI;AAEtB,MAAI,iBAAiB,CAAC,KAAK,MACzB,MAAK,QAAQ;UAER,UAAmB;EAC1B,MAAM,SAAS,oBAAoB,QAAQ,SAAS,UAAU;AAC9D,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,qBACE,KACA,KACA,aACI,yBAAyB,KAAK,mBAAmB,SAAS,GAC1D,KAAK,UAAU,EACb,OAAO;GACL,SAAS,mBAAmB;GAC5B,MAAM;GACN,OAAO;GACP,MAAM;GACP,EACF,CAAC,CACP;AACD;;AAIF,KAAI,CAAC,MAAM,QAAQ,KAAK,SAAS,EAAE;AACjC,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,qBACE,KACA,KACA,aACI,yBAAyB,KAAK,yCAAyC,GACvE,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,OAAO;GACP,MAAM;GACP,EACF,CAAC,CACP;AACD;;CAGF,MAAM,SAAS,IAAI,UAAU;CAC7B,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,cAAc,eAAe,IAAI,QAAQ;AAG/C,MAAK,gBAAgB;AACrB,MAAK,WAAW,WAAW,IAAI;CAK/B,MAAM,SAAS,UAAU,IAAI;CAC7B,MAAM,eAAe,mBAKnB,CAAC,EAAE,SAAS,UAAU,cACtB,SAAS,OACV;CAkBD,IAAI,UAA0B;CAC9B,IAAI,0BAA0B;CAC9B,IAAI,sBAA8C;CAMlD,IAAI,gBAAgB,KAAK;CAGzB,IAAI,0BAA0B;AAG9B,KAF2B,cAAc,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,OAAO,SAAS,GAEpE;EACtB,MAAM,aAAa,0BAA0B,KAAK;EASlD,IAAI,cAAc,QAAQ,6BAA6B,OAAO;EAI9D,MAAM,iBAAiB,KAAK,UAAU,oBAAoB;EAC1D,IAAI,mBAAmC;EACvC,IAAI,oBAA4C;EAKhD,MAAM,mBAAmB,OACvB,cACsF;GACtF,MAAM,QAA+B;IAAE,GAAG;IAAM,OAAO;IAAW;GAClE,MAAM,UAAU,uBACd,UACA,OACA,aACA,SAAS,kBACT,aACD;AACD,6BAA0B,KAAK,IAAI,yBAAyB,QAAQ,wBAAwB;AAC5F,OAAI,CAAC,QAAQ,QAAS,QAAO;GAC7B,MAAM,WAAW,MAAM,gBAAgB,QAAQ,SAAS,MAAM;AAC9D,UAAO;IAAE,SAAS,QAAQ;IAAS;IAAU,SAAS,gBAAgB,SAAS;IAAE;;AAEnF,OAAK,MAAM,aAAa,YAAY;GAClC,MAAM,UAAU,MAAM,iBAAiB,UAAU;AACjD,OAAI,CAAC,SAAS;AAEZ,QAAI,CAAC,eAAgB;AACrB;;AAOF,WAAQ,2BAA2B,QAAQ,SAAS,UAAU,OAAO;AACrE,6BAA0B;AAG1B,iBAAc,QAAQ,6BAA6B,OAAO;AAC1D,mBAAgB;AAChB,OAAI,QAAQ,SAAS;IAQnB,MAAM,oBAAqB,QAAQ,SAA2B,gBAAgB;AAC9E,QAAI,kBAAkB,mBAAmB;AAEvC,wBAAmB,QAAQ;AAC3B,yBAAoB,QAAQ;AAC5B;;;AAIJ,aAAU,QAAQ;AAClB,yBAAsB,QAAQ;AAC9B;;AAEF,MAAI,CAAC,WAAW,kBAAkB;AAGhC,aAAU;AACV,yBAAsB;;QAEnB;EACL,MAAM,SAAS,uBACb,UACA,MACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,kBACT,aACD;AACD,YAAU,OAAO;AACjB,4BAA0B,OAAO;;AAGnC,KAAI,SAAS;AAGX,MAAI,CAAC,wBAAyB,SAAQ,2BAA2B,SAAS,UAAU,OAAO;AAC3F,WAAS,OAAO,MAAM,oBAAoB,KAAK,UAAU,QAAQ,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG;QACnF;EACL,MAAM,cAAc,KAAK,SAAS,QAAQ,MAAM,EAAE,SAAS,OAAO,CAAC,KAAK;EACxE,MAAM,UACJ,OAAO,aAAa,YAAY,WAAW,YAAY,QAAQ,MAAM,GAAG,GAAG,GAAG;AAChF,WAAS,OAAO,MACd,yCAAyC,KAAK,SAAS,IAAI,SAAS,QAAQ,IAC7E;;CAWH,MAAM,cAAc,cAAc,SAAS,SAAS,OAAO,IAAI,SAAS,SAAS,OAAO;CACxF,MAAM,eAAe;EAAE;EAAQ;EAAM,SAAS;EAAa;EAAM;AAEjE,KAAI,gBAAgB,UAAU,gBAAgB,cAAc;AAC1D,mBACE,aACA,KACA,SACA,SACA,cACA,UAAU,YAAY,SACtB,SAAS,SACV;AACD;;AAGF,KAAI,WAAW,gBAAgB,aAAa;AAC1C,mBACE,aACA,KACA,SACA,SACA,cACA,WACA,SAAS,SACV;AACD;;AAGF,KAAI,CAAC,SAAS;AAEZ,MADwB,kBAAkB,SAAS,QAAQ,IAAI,QAAQ,EAClD;GACnB,MAAM,eAAe;GACrB,MAAM,gBAAgB,qBAAqB,wBAAwB;AACnE,YAAS,OAAO,MACd,qBACE,IAAI,UAAU,QACd,IAAI,OAAO,kBACX,wBACD,CACF;AACD,WAAQ,IAAI;IACV,QAAQ,IAAI,UAAU;IACtB,MAAM,IAAI,OAAO;IACjB,SAAS,eAAe,IAAI,QAAQ;IACpC;IACA,UAAU;KACR,QAAQ;KACR,SAAS;KACT,GAAG,oBAAoB,SAAS,QAAQ,IAAI,QAAQ;KACrD;IACF,CAAC;AACF,sBACE,KACA,cACA,aACI,yBAAyB,cAAc,cAAc,GACrD,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACN,OAAO;IACP,MAAM;IACP,EACF,CAAC,CACP;AACD;;AAIF,MAAI,SAAS,UAAU,aAAa;GAKlC,MAAM,cACJ,gBAAgB,cACZ;IAME,2BAA2B;AACzB,sBACE,aACA,KACA,MACA,SACA,cACA,SACA,SAAS,SACV;AACD,YAAO;;IAKT,iBAAiB,WAAmE;AAClF,cAAS,OAAO,KACd,8EAA8E,OAAO,GACtF;AACD,cAAS,UAAU,iBAAiB,+BAA+B;MACjE,QAAQ;MACR,QAAQ;MACR;MACD,CAAC;;IAEL,GACD;GAEN,MAAM,UAAU,MAAM,eACpB,KACA,KACA,MACA,aACA,IAAI,OAAO,kBACX,UACA,UACA,KACA,YACD;AACD,OAAI,YAAY,kBAAmB;AACnC,OAAI,YAAY,kBAAkB;AAChC,YAAQ,IAAI;KACV,QAAQ,IAAI,UAAU;KACtB,MAAM,IAAI,OAAO;KACjB,SAAS,eAAe,IAAI,QAAQ;KACpC;KACA,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM,QAAQ;MAAS;KAC5E,CAAC;AACF;;;AAKJ,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IACR,QAAQ;IACR,SAAS;IACT,GAAG,oBAAoB,SAAS,QAAQ,IAAI,QAAQ;IACrD;GACF,CAAC;AACF,qBACE,KACA,KACA,aACI,yBAAyB,KAAK,qBAAqB,GACnD,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,OAAO;GACP,MAAM;GACP,EACF,CAAC,CACP;AACD;;CAKF,MAAM,WAAW,uBAAwB,MAAM,gBAAgB,SAAS,KAAK;CAC7E,MAAM,UAAU,QAAQ,WAAW,SAAS;CAC5C,MAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,aAAa,SAAS,UAAU;CAKtE,MAAM,qBADe,KAAK,WAAW,QAAQ,KAAK,gBAAgB,kBAAkB,QACzC;CAS3C,MAAM,sBAAsB,KAAK,SAC9B,KAAK,MACJ,OAAO,EAAE,YAAY,WACjB,EAAE,UACF,MAAM,QAAQ,EAAE,QAAQ,GACtB,EAAE,QAAQ,KAAK,MAAM,EAAE,QAAQ,GAAG,CAAC,KAAK,GAAG,GAC3C,GACP,CACA,KAAK,GAAG;CACX,MAAM,+BACJ,WACA,mBAEA,aAAa,WAAW,qBAAqB,eAAe;CAO9D,MAAM,qBACJ,YACA,cACmB;AACnB,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO,0BACL,YACA,yBAAyB,WAAW,WAAW,SAAS,cAAc,EACtE,WAAW,OAAO,OACnB;;CAEH,MAAM,iBACJ,QACA,YACA,cACS;AACT,MAAI,CAAC,WAAY;EACjB,MAAM,UAAU,yBAAyB,WAAW,WAAW,SAAS,cAAc;AACtF,wBAAsB,QAAQ,SAAS,WAAW,OAAO,OAAU;AAGnE,MAAI,WAAY,uBAAsB,CAAC,WAAW,EAAE,SAAS,WAAW,OAAO,OAAU;;CAG3F,MAAM,uBAAuB,CAAC,EAAE,cAAc,QAAQ;AAGtD,KAAI,gBAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,qBACE,KACA,QACA,aACI,yBAAyB,QAAQ,SAAS,MAAM,SAAS,SAAS,MAAM,SAAS,GACjF,uBAAuB,SAAS,EACpC,EACE,YAAY,SAAS,YACtB,CACF;AACD;;AAIF,KAAI,gBAAgB,SAAS,EAAE;AAC7B,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,qBACE,KACA,KACA,aACI,yBACE,KACA,gIACD,GACD,KAAK,UAAU,EACb,OAAO;GACL,SACE;GACF,MAAM;GACP,EACF,CAAC,CACP;AACD;;AAIF,KAAI,+BAA+B,SAAS,EAAE;AAC5C,MAAI,SAAS,aAAa,OACxB,UAAS,OAAO,KACd,wFACD;EAEH,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,kBAAkB,kBAAkB,SAAS,QAAQ,IAAI,QAAQ;EACvE,MAAM,eAAe,yBACnB,SAAS,WACT,eACA,iBACA,SAAS,OACV;EAYD,MAAM,YAAY,KAAK,WAAW;EAClC,MAAM,kBACJ,aAAa,SAAS,UAAU,SAAS,OAAO,SAAS,IACrD,qBAAqB,SAAS,OAAO,GACrC;EACN,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,CAAC,WAAW;GACd,MAAM,aAAa,oCACjB,SAAS,WAAW,IACpB,SAAS,aAAa,EAAE,EACxB,eACA,cACA,WACA,KAAK,SACN;AACD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,kBAAkB,YAAY,UAAU,CAAC,CAAC;SAC5D;GACL,MAAM,SAAS,gCACb,SAAS,WAAW,IACpB,SAAS,aAAa,EAAE,EACxB,eACA,WACA,cACA,WACA,gBACD;GAOD,MAAM,iBAAiB,kBACnB,gBAAgB,KAAK,MAAO,EAAE,SAAS,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,UAAW,CAAC,KAAK,GAAG,IACvF,SAAS,WAAW,OACpB,SAAS,aAAa,EAAE,EAAE,KAAK,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC,KAAK,GAAG;GAC3E,MAAM,aAAa,qBACf,gBACE,OAAO,IAAI,MAAM,oBACjB,WAAW,SAAS,eACpB,OAAO,IAAI,WAAW,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,EACnD,4BAA4B,WAAW,eAAe,EACtD,WAAW,kBACZ,GACD;AACJ,iBAAc,QAAQ,YAAY,UAAU;GAC5C,MAAM,eAAe,yBAAyB,QAAQ;AAWtD,OAAI,CAVc,MAAM,eAAe,KAAK,QAAQ;IAClD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC3B;IACA,iBAAiB,QAAQ;IACzB,aAAa,QAAQ,eAAe,SAAS;IAC7C;IACD,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAI,eAAe,SAAS,EAAE;AAC5B,MAAI,SAAS,aAAa,OACxB,UAAS,OAAO,KACd,wFACD;EAEH,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,kBAAkB,kBAAkB,SAAS,QAAQ,IAAI,QAAQ;EACvE,MAAM,eAAe,yBACnB,SAAS,WACT,eACA,iBACA,SAAS,OACV;EACD,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,KAAK,WAAW,MAAM;GACxB,MAAM,aAAa,oBACjB,SAAS,SACT,eACA,cACA,WACA,KAAK,SACN;AACD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,kBAAkB,YAAY,UAAU,CAAC,CAAC;SAC5D;GACL,MAAM,SAAS,gBACb,SAAS,SACT,eACA,WACA,cACA,UACD;GACD,MAAM,aAAa,qBACf,gBACE,OAAO,IAAI,MAAM,oBACjB,WAAW,SAAS,eACpB,OAAO,IAAI,WAAW,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,EACnD,4BAA4B,WAAW,SAAS,QAAQ,EACxD,WAAW,kBACZ,GACD;AACJ,iBAAc,QAAQ,YAAY,UAAU;GAC5C,MAAM,eAAe,yBAAyB,QAAQ;AAWtD,OAAI,CAVc,MAAM,eAAe,KAAK,QAAQ;IAClD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC3B;IACA,iBAAiB,QAAQ;IACzB,aAAa,QAAQ,eAAe,SAAS;IAC7C;IACD,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAI,mBAAmB,SAAS,EAAE;AAChC,MAAI,SAAS,aAAa,OACxB,UAAS,OAAO,KACd,wFACD;EAEH,MAAM,YAAY,iBAAiB,SAAS;EAC5C,MAAM,kBAAkB,kBAAkB,SAAS,QAAQ,IAAI,QAAQ;EACvE,MAAM,eAAe,yBACnB,SAAS,WACT,eACA,iBACA,SAAS,OACV;EACD,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAAS,eAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,KAAK,WAAW,MAAM;GACxB,MAAM,aAAa,wBACjB,SAAS,WACT,eACA,cACA,WACA,KAAK,SACN;AACD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,kBAAkB,YAAY,UAAU,CAAC,CAAC;SAC5D;GACL,MAAM,SAAS,oBACb,SAAS,WACT,eACA,WACA,cACA,UACD;GACD,MAAM,iBAAiB,SAAS,UAAU,KAAK,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC,KAAK,GAAG;GACtF,MAAM,aAAa,qBACf,gBACE,OAAO,IAAI,MAAM,oBACjB,WAAW,SAAS,eACpB,OAAO,IAAI,WAAW,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,EACnD,4BAA4B,WAAW,eAAe,EACtD,WAAW,kBACZ,GACD;AACJ,iBAAc,QAAQ,YAAY,UAAU;GAC5C,MAAM,eAAe,yBAAyB,QAAQ;AAWtD,OAAI,CAVc,MAAM,eAAe,KAAK,QAAQ;IAClD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC3B;IACA,iBAAiB,QAAQ;IACzB,aAAa,QAAQ,eAAe,SAAS;IAC7C;IACD,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,SAAQ,IAAI;EACV,QAAQ,IAAI,UAAU;EACtB,MAAM,IAAI,OAAO;EACjB,SAAS,eAAe,IAAI,QAAQ;EACpC;EACA,UAAU;GAAE,QAAQ;GAAK;GAAS;EACnC,CAAC;AACF,oBACE,KACA,KACA,aACI,yBAAyB,KAAK,gDAAgD,GAC9E,KAAK,UAAU,EACb,OAAO;EACL,SAAS;EACT,MAAM;EACP,EACF,CAAC,CACP;;AAYH,eAAsB,aACpB,UACA,SACA,QACA,iBACyB;AAEzB,QAAO,6BAA6B,UAAU,SADzB,mBAAmB;EAAE,OAAO,SAAS;EAAM,OAAO;EAAgB,CAAC,EACnB,QAAQ,gBAAgB;;;AAI/F,eAAsB,6BACpB,UACA,SACA,cACA,QACA,iBACyB;CACzB,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,IAAI,OAAO,SAAS,YAAY,SAAS;CACxD,MAAM,WAAW,SAAS,UAAU,uBAAuB,GAAG;CAC9D,MAAM,gBAAgB,WAAW,EAAE;CACnC,MAAM,WAAW;EACf,SAAS,cAAc,WAAW;EAClC,WAAW,KAAK,IAAI,GAAG,cAAc,aAAa,mBAAmB;EACrE,aAAa,cAAc,eAAe;EAC1C;EACA,IAAI,QAAQ;AACV,UAAO,cAAc;;EAEvB;EACA,IAAI,SAAS;AACX,UAAO,cAAc;;EAEvB,IAAI,SAAS;AACX,UAAO,cAAc;;EAEvB,IAAI,mBAAmB;AACrB,UAAO,cAAc;;EAEvB,IAAI,WAAW;AACb,UAAO,cAAc;;EAEvB,IAAI,kBAAkB;AACpB,UAAO,cAAc;;EAEvB,IAAI,WAAW;AACb,UAAO,cAAc;;EAEvB,IAAI,YAAY;AACd,UAAO,cAAc;;EAEvB,IAAI,gBAAgB;AAClB,UAAO,cAAc;;EAExB;AAGD,KAAI,SAAS,OAAO;EAClB,MAAM,aAAa;GACjB;IAAE,MAAM;IAAY,OAAO,QAAQ,MAAM;IAAU;GACnD;IAAE,MAAM;IAAiB,OAAO,QAAQ,MAAM;IAAe;GAC7D;IAAE,MAAM;IAAkB,OAAO,QAAQ,MAAM;IAAgB;GAChE;AACD,OAAK,MAAM,EAAE,MAAM,WAAW,WAC5B,KAAI,UAAU,WAAc,QAAQ,KAAK,QAAQ,GAC/C,QAAO,KAAK,SAAS,KAAK,IAAI,MAAM,qDAAqD;;AAO/F,MAAK,MAAM,EAAE,MAAM,YAAY;EAC7B;GAAE,MAAM;GAAY,QAAQ,SAAS;GAAU;EAC/C;GAAE,MAAM;GAAmB,QAAQ,SAAS;GAAiB;EAC7D;GAAE,MAAM;GAAY,QAAQ,SAAS;GAAU;EAC/C;GAAE,MAAM;GAAa,QAAQ,SAAS;GAAW;EACjD;GAAE,MAAM;GAAiB,QAAQ,SAAS;GAAe;EAC1D,EAAE;AACD,MAAI,CAAC,OAAQ;AACb,OAAK,MAAM,SAAS,CAAC,yBAAyB,uBAAuB,EAAW;GAC9E,MAAM,QAAQ,OAAO;AACrB,OAAI,UAAU,OAAW;AACzB,OAAI,CAAC,OAAO,SAAS,MAAM,CACzB,QAAO,KAAK,GAAG,KAAK,GAAG,MAAM,IAAI,MAAM,8CAA8C;YAC5E,CAAC,OAAO,UAAU,MAAM,IAAI,QAAQ,EAC7C,QAAO,KACL,GAAG,KAAK,GAAG,MAAM,IAAI,MAAM,+EAC5B;;;CAQP;EACE,MAAM,MAAM,SAAS,QAAQ,iBAAiB;AAC9C,MAAI,QAAQ,WAAc,CAAC,OAAO,UAAU,IAAI,IAAI,MAAM,GACxD,QAAO,KACL,2CAA2C,IAAI,2DAA2D,2CAA2C,GACtJ;;CA0BL;EACE,MAAM,eAAe,SAAS,QAAQ,WAAW;AACjD,MAAI,iBAAiB,QAAW;GAC9B,IAAI;AACJ,OAAI;AACF,eAAW,IAAI,IAAI,aAAa,CAAC;WAC3B;AAIR,OAAI,aAAa,UAAa,oBAAoB,KAAK,SAAS,CAC9D,OAAM,IAAI,MACR,8BAA8B,aAAa,sNAI5C;;;CAQP,MAAM,UAAU,IAAI,QAAQ;EAC1B,YAAY,SAAS,qBAAqB;EAC1C,yBAAyB,SAAS,2BAA2B;EAC9D,CAAC;CACF,MAAM,cAAc,IAAI,eAAe;CACvC,MAAM,sBAAsB,IAAI,uBAAuB;CACvD,MAAM,eAAe,IAAI,gBAAgB;CACzC,MAAM,gBAAgB,IAAI,iBAAiB;CAC3C,MAAM,oBAAoB,IAAI,qBAAqB;AAGnD,KAAI,OACF,MAAK,MAAM,EAAE,aAAa,QAAQ;AAChC,MAAI,QAAQ,WAAY,SAAQ,WAAW,QAAQ;AACnD,MAAI,YAAY,QAAQ,YAAa,SAAQ,YAAY,SAAS;;AAKtE,KAAI,SACF,UAAS,SAAS,0BAA0B,EAAE,EAAE,SAAS,OAAO;CAGlE,MAAM,SAASA,OAAK,cAAc,KAA2B,QAA6B;AAExF,oBAAkB,KAAK,IAAI,CAAC,OAAO,QAAiB;GAClD,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;GACjD,MAAM,QAAQ,eAAe,QAAS,IAAI,SAAS,MAAO;GAC1D,MAAM,SAAS,IAAI,UAAU;GAC7B,MAAM,MAAM,IAAI,OAAO;AACvB,YAAS,OAAO,KAAK,8BAA8B,OAAO,GAAG,IAAI,IAAI,IAAI,IAAI,QAAQ;AACrF,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,QAAI,IAAI,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAAC;cACjE,CAAC,IAAI,cACd,KAAI,KAAK;IAEX;GACF;CAEF,eAAe,kBACb,KACA,KACe;EAEf,MAAM,YAAY,WAAW,QAAQ,OAAO,QAAQ,GAAG;EAGvD,MAAM,YAAY,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,QAAQ,cAAc;EACtF,IAAI,WAAW,UAAU;EAIzB,MAAM,mBAAmB;EACzB,MAAM,eAAe,iBAAiB,iBAAiB;EASvD,MAAM,gBACJ,SAAS,QAAQ,UAAU,aAAa,UAAa,iBAAiB,WAAW,WAAW;AAK9F,MAAI,SACF,KAAI,GAAG,gBAAgB;AACrB,OAAI;IACF,MAAM,iBAAiB,mBAAmB,SAAS;IACnD,MAAM,SAAS,IAAI,UAAU;IAC7B,MAAM,SAAS,OAAO,IAAI,WAAW;AACrC,aAAS,iBAAiB,yBAAyB;KACjD;KACA,MAAM;KACN;KACD,CAAC;IACF,MAAM,UAAU,OAAO,QAAQ,OAAO,QAAQ,GAAG,UAAU,GAAG;AAC9D,aAAS,iBACP,mCACA;KAAE;KAAQ,MAAM;KAAgB,EAChC,QACD;YACM,KAAK;AACZ,aAAS,OAAO,KAAK,iCAAiC,IAAI;;IAE5D;AAKJ,MACE,IAAI,WAAW,cACd,CAAC,aAAa,OAAO,WACnB,IAAI,QAAQ,WAAW,UACtB,IAAI,QAAQ,qCAAqC,SACrD;AACA,iBAAc,IAAI;AAClB;;AAMF,MAAI,EAFF,IAAI,WAAW,UACd,aAAa,eAAe,aAAa,cAAc,aAAa,cACnD;AAClB,OAAI,CAAC,sBAAsB,KAAK,aAAa,OAAO,CAAC,IAAI;AACvD,6BAAyB,KAAK,eAAe;AAC7C;;AAEF,4BAAyB,KAAK,aAAa,OAAO;;AAIpD,MAAI,SAAS,WAAW,eAAe,EAAE;AACvC,SAAM,iBACJ,KACA,KACA,UACA,UACA,SACA,aACA,qBACA,cACA,eACA,mBACA,SACD;AACD;;AAIF,MAAI,QACF;QAAK,MAAM,EAAE,MAAM,WAAW,aAAa,OACzC,KAAI,aAAa,aAAa,SAAS,WAAW,YAAY,IAAI,EAAE;IAClE,MAAM,UAAU,SAAS,MAAM,UAAU,OAAO,IAAI;AAEpD,QADgB,MAAM,QAAQ,cAAc,KAAK,KAAK,QAAQ,CACjD;;;AAanB,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,OAAI;AAEF,UAAM,aAAa,KAAK,KADZ,MAAM,SAAS,IAAI,EACG,UAAU,SAAS,UAAU,eAAe;YACvE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAGF,MAAI,aAAa,wBAAwB,IAAI,WAAW,QAAQ;AAC9D,OAAI;AAEF,UAAM,qBAAqB,KAAK,KADpB,MAAM,SAAS,IAAI,EACW,UAAU,SAAS,UAAU,eAAe;YAC/E,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAGF,OACG,aAAa,0BAA0B,aAAa,sBACrD,IAAI,WAAW,QACf;AACA,OAAI;AAEF,UAAM,uBAAuB,KAAK,KADtB,MAAM,SAAS,IAAI,EACa,UAAU,SAAS,UAAU,eAAe;YACjF,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAGF,MAAI,aAAa,oBAAoB,IAAI,WAAW,OAAO;AACzD,kBAAe,IAAI;GACnB,MAAM,2BAAW,IAAI,KAAa;AAClC,QAAK,MAAM,KAAK,SACd,KAAI,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,UAAU,SAC5C,UAAS,IAAI,EAAE,MAAM,MAAM;GAI/B,MAAM,UADM,SAAS,OAAO,IAAI,CAAC,GAAG,SAAS,GAAG,gBAC7B,KAAK,UAAU;IAChC;IACA,OAAO;IACP,8BAAa,IAAI,MAAM,EAAC,aAAa;IACrC,MAAM;IACN,QAAQ;IACR,SAAS,EAAE;IACZ,EAAE;AACH,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,CAAC,CAAC;AACnC;;EAUF,MAAM,8BAA8B,SAAS,MAAM,4BAA4B;AAC/E,MAAI,+BAA+B,IAAI,WAAW,OAAO;AACvD,OAAI;AACF,UAAM,6BACJ,KACA,KACA,4BAA4B,IAC5B,SACA,UACA,gBACA,oBACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,6BAA6B,MAAM;AACzD,QAAI,CAAC,IAAI,aAAa;AAKpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,uEAAuE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GAC3H;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAKF,MAAI,aAAa,gCAAgC,IAAI,WAAW,OAAO;AACrE,OAAI;AACF,UAAM,4BAA4B,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe;YACjF,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,4BAA4B,MAAM;AACxD,QAAI,CAAC,IAAI,aAAa;AAKpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,sEAAsE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GAC1H;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,6BAA6B,SAAS,MAAM,2BAA2B;AAC7E,MAAI,8BAA8B,IAAI,WAAW,OAAO;AACtD,OAAI;AACF,UAAM,4BACJ,KACA,KACA,2BAA2B,IAC3B,UACA,SACA,UACA,gBACA,oBACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,4BAA4B,MAAM;AACxD,QAAI,CAAC,IAAI,aAAa;AAKpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,sEAAsE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GAC1H;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,0BAA0B,IAAI,WAAW,QAAQ;AAKhE,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,4BACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,oBACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,4BAA4B,MAAM;AACxD,QAAI,CAAC,IAAI,aAAa;AAUpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,sEAAsE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GAC1H;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAgBF,MAAM,2BAA2B,SAAS,MAAM,yBAAyB;AACzE,MAAI,4BAA4B,IAAI,WAAW,OAAO;AACpD,OAAI;AACF,UAAM,0BACJ,KACA,KACA,yBAAyB,IACzB,UACA,SACA,UACA,gBACA,kBACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,0BAA0B,MAAM;AACtD,QAAI,CAAC,IAAI,aAAa;AACpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,oEAAoE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GACxH;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAGF,MAAI,yBAAyB,KAAK,SAAS,IAAI,IAAI,WAAW,QAAQ;AACpE,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,0BACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,kBACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,0BAA0B,MAAM;AACtD,QAAI,CAAC,IAAI,aAAa;AACpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,oEAAoE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GACxH;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAOF,MAAI,aAAa,oBAAoB,IAAI,WAAW,OAAO;AACzD,0BAAuB,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe;AAC7E;;AAEF,MAAI,aAAa,iBAAiB,IAAI,WAAW,OAAO;AACtD,uBAAoB,KAAK,KAAK,SAAS,eAAe;AACtD;;AAEF,MAAI,aAAa,qBAAqB,IAAI,WAAW,OAAO;AAC1D,2BAAwB,KAAK,KAAK,SAAS,eAAe;AAC1D;;EAKF,IAAI;EACJ,MAAM,aAAa,SAAS,MAAM,oBAAoB;AACtD,MAAI,cAAc,IAAI,WAAW,QAAQ;AACvC,uBAAoB,WAAW;AAE/B,cAAW,OADO,WAAW;;AAK/B,MAAI,CAAC,kBACH,YAAW,oBAAoB,UAAU,OAAO;AAIlD,MAAI,aAAa,eAAe,IAAI,WAAW,OAAO;AACpD,kBAAe,IAAI;AACnB,OAAI,UAAU,OAAO,SAAS,GAAG;IAC/B,MAAM,WAAoC,EACxC,KAAK;KAAE,QAAQ;KAAM,UAAU,SAAS;KAAQ,EACjD;AACD,SAAK,MAAM,EAAE,MAAM,WAAW,aAAa,OACzC,KAAI,QAAQ,QAAQ;KAClB,MAAM,OAAO,UAAU,QAAQ,OAAO,GAAG;AACzC,cAAS,QAAQ,QAAQ,QAAQ;;AAGrC,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,QAAI,IAAI,KAAK,UAAU;KAAE,QAAQ;KAAM;KAAU,CAAC,CAAC;UAC9C;AACL,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,QAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,MAAM,CAAC,CAAC;;AAE3C;;AAGF,MAAI,aAAa,cAAc,IAAI,WAAW,OAAO;AACnD,kBAAe,IAAI;AACnB,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,QAAQ,SAAS,CAAC,CAAC;AAC5C;;AAIF,MAAI,aAAa,cAAc,IAAI,WAAW,OAAO;AACnD,OAAI,CAAC,UAAU;AACb,mBAAe,KAAK,YAAY;AAChC;;AAEF,kBAAe,IAAI;AACnB,OAAI,UAAU,KAAK,EAAE,gBAAgB,4CAA4C,CAAC;AAClF,OAAI,IAAI,SAAS,WAAW,CAAC;AAC7B;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,OAAO;AACpD,kBAAe,IAAI;GACnB,MAAM,2BAAW,IAAI,KAAa;AAClC,QAAK,MAAM,KAAK,SACd,KAAI,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,UAAU,SAC5C,UAAS,IAAI,EAAE,MAAM,MAAM;GAI/B,MAAM,QADM,SAAS,OAAO,IAAI,CAAC,GAAG,SAAS,GAAG,gBAC/B,KAAK,QAAQ;IAC5B;IACA,QAAQ;IACR,SAAS;IACT,UAAU;IACX,EAAE;AACH,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU;IAAE,QAAQ;IAAQ;IAAM,CAAC,CAAC;AACjD;;AAIF,MAAI,aAAa,eAAe;AAC9B,kBAAe,IAAI;AACnB,OAAI,IAAI,WAAW,OAAO;IACxB,MAAM,aAAa,UAAU,aAAa,IAAI,QAAQ;IACtD,IAAI;AACJ,QAAI,YAAY;KACd,MAAM,QAAQ,SAAS,YAAY,GAAG;AACtC,SAAI,OAAO,MAAM,MAAM,IAAI,SAAS,GAAG;AACrC,yBACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;OACL,SAAS,6BAA6B,WAAW;OACjD,MAAM;OACP,EACF,CAAC,CACH;AACD;;AAEF,YAAO,EAAE,OAAO;;IAElB,MAAM,UAAU,QAAQ,OAAO,KAAK;AACpC,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,QAAI,IAAI,KAAK,UAAU,QAAQ,CAAC;AAChC;;AAEF,OAAI,IAAI,WAAW,UAAU;AAK3B,YAAQ,cAAc;AACtB,QAAI,UAAU,IAAI;AAClB,QAAI,KAAK;AACT;;AAEF,kBAAe,KAAK,YAAY;AAChC;;AAIF,MAAI,aAAa,kBAAkB,IAAI,WAAW,QAAQ;AACxD,OAAI;AAEF,UAAM,gBAAgB,KAAK,KADf,MAAM,SAAS,IAAI,EACM,UAAU,SAAS,UAAU,eAAe;YAC1E,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI;AACF,SAAI,MAAM,uBAAuB,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;AACnF,SAAI,KAAK;aACF,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;;AAIxE;;AAIF,MAAI,aAAa,iBAAiB,IAAI,WAAW,QAAQ;AACvD,OAAI;AAEF,UAAM,eAAe,KAAK,KADd,MAAM,SAAS,IAAI,EACK,UAAU,SAAS,UAAU,eAAe;YACzE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI;AACF,SAAI,MAAM,uBAAuB,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;AACnF,SAAI,KAAK;aACF,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;;AAIxE;;AAIF,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,OAAI;AAEF,UAAM,aAAa,KAAK,KADZ,MAAM,SAAS,IAAI,EACG,UAAU,SAAS,UAAU,eAAe;YACvE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI;AACF,SAAI,MAAM,uBAAuB,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;AACnF,SAAI,KAAK;aACF,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;;AAIxE;;AAIF,MAAI,aAAa,qBAAqB,IAAI,WAAW,QAAQ;AAC3D,OAAI;AAEF,UAAM,kBAAkB,KAAK,KADjB,MAAM,SAAS,IAAI,EACQ,UAAU,SAAS,UAAU,eAAe;YAC5E,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,mBAAmB,IAAI,WAAW,QAAQ;AACzD,OAAI;IACF,MAAM,eAAe;IACrB,MAAM,qBAAwC,oBAAoB,UAAU;IAC5E,IAAI,MAAM,MAAM,SAAS,IAAI;AAE7B,QAAI,aACF,KAAI;KACF,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAI,CAAC,OAAO,OAAO;AACjB,aAAO,QAAQ;AACf,YAAM,KAAK,UAAU,OAAO;;aAEvB,KAAK;AACZ,SAAI,EAAE,eAAe,aACnB,UAAS,OAAO,MACd,8CAA8C,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GAC/F;;AAKP,UAAM,iBACJ,KACA,KACA,KACA,UACA,SACA,UACA,gBACA,mBACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,OAAI;AAEF,UAAM,aACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,UACA,QACA,gBAAgB,aAAa,OAC9B;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,OAAI;AAEF,UAAM,gBAAgB,KAAK,KADf,MAAM,SAAS,IAAI,EACM,UAAU,SAAS,UAAU,eAAe;YAC1E,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,0BAA0B,IAAI,WAAW,QAAQ;AAChE,OAAI;AAEF,UAAM,sBAAsB,KAAK,KADrB,MAAM,SAAS,IAAI,EACY,UAAU,SAAS,UAAU,eAAe;YAChF,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,OAAI;AAEF,UAAM,aAAa,KAAK,KADZ,MAAM,SAAS,IAAI,EACG,UAAU,SAAS,UAAU,eAAe;YACvE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,uBAAuB,IAAI,WAAW,QAAQ;AAC7D,OAAI;AAEF,UAAM,oBAAoB,KAAK,KADnB,MAAM,SAAS,IAAI,EACU,UAAU,SAAS,UAAU,eAAe;YAC9E,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,qBAAqB,IAAI,WAAW,QAAQ;AAC3D,OAAI;AAEF,UAAM,oBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,cACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAQF,MAAI,aAAa,0BAA0B,IAAI,WAAW,QAAQ;AAChE,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,sBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,cACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,sBAAsB,MAAM;AAClD,QAAI,CAAC,IAAI,aAAa;AACpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,gEAAgE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GACpH;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,OAAI;AAEF,UAAM,kBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,YACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EASF,MAAM,uBAAuB,SAAS,MAAM,qBAAqB;AACjE,MAAI,wBAAwB,qBAAqB,OAAO,iBAAiB,IAAI,WAAW,OAAO;AAC7F,OAAI;AACF,UAAM,sBACJ,KACA,KACA,qBAAqB,IACrB,UACA,SACA,UACA,gBACA,eACA,YACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,sBAAsB,MAAM;AAClD,QAAI,CAAC,IAAI,aAAa;AACpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,gEAAgE,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GACpH;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAMF,MAAM,kBAAkB,SAAS,MAAM,mBAAmB;AAC1D,MAAI,mBAAmB,IAAI,WAAW,QAAQ;AAC5C,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,qBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,gBAAgB,IAChB,UACA,SACA,UACA,gBACA,aACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,qBAAqB,MAAM;AACjD,QAAI,CAAC,IAAI,aAAa;AACpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,+DAA+D,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GACnH;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAKF,MAAM,oBAAoB,SAAS,MAAM,iBAAiB;AAC1D,MAAI,qBAAqB,IAAI,WAAW,OAAO;AAC7C,OAAI;AACF,UAAM,qBACJ,KACA,KACA,kBAAkB,IAClB,UACA,SACA,UACA,gBACA,aACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,aAAS,OAAO,MAAM,qBAAqB,MAAM;AACjD,QAAI,CAAC,IAAI,aAAa;AACpB,SAAI;AACF,cAAQ,IAAI;OACV,QAAQ,IAAI,UAAU;OACtB,MAAM,IAAI,OAAO;OACjB,SAAS,eAAe,IAAI,QAAQ;OACpC,MAAM;OACN,UAAU;QAAE,QAAQ;QAAK,SAAS;QAAM;OACzC,CAAC;cACK,MAAM;AACb,eAAS,OAAO,KACd,+DAA+D,gBAAgB,QAAQ,KAAK,UAAU,OAAO,KAAK,GACnH;;AAEH,wBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAClE;eACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,qBAAqB,SAAS,MAAM,kBAAkB;AAC5D,MAAI,sBAAsB,IAAI,WAAW,QAAQ;GAC/C,MAAM,eAAe,mBAAmB;AACxC,OAAI;AAEF,UAAM,aACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,UACA,SACA,UACA,gBACA,UACA,aACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,4BAA4B,IAAI,WAAW,QAAQ;AAClE,OAAI;AAEF,UAAM,yBAAyB,KAAK,KADxB,MAAM,SAAS,IAAI,EACe,UAAU,SAAS,UAAU,eAAe;YACnF,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI;AACF,SAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;AACrE,SAAI,KAAK;aACF,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;;AAIxE;;EAIF,MAAM,mBAAmB,SAAS,MAAM,gBAAgB;AACxD,MAAI,oBAAoB,IAAI,WAAW,QAAQ;GAC7C,MAAM,aAAa,iBAAiB;AACpC,OAAI;AAEF,UAAM,yBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,YACA,UACA,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,cAAc,SAAS,MAAM,eAAe;AAClD,MAAI,eAAe,IAAI,WAAW,QAAQ;GACxC,MAAM,cAAc,YAAY;GAChC,MAAM,YAAY,YAAY,OAAO;AACrC,OAAI;AAEF,UAAM,aACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,aACA,WACA,UACA,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI;AACF,SAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;AACrE,SAAI,KAAK;aACF,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;;AAIxE;;EAIF,MAAM,cAAc,SAAS,MAAM,aAAa;AAChD,MAAI,eAAe,IAAI,WAAW,QAAQ;GACxC,MAAM,cAAc,YAAY;GAChC,MAAM,YAAY,YAAY,OAAO;AACrC,OAAI;AAEF,UAAM,aACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,aACA,WACA,UACA,SACA,UACA,gBACA,WACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI;AACF,SAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;AACrE,SAAI,KAAK;aACF,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;;AAIxE;;EAIF,MAAM,eAAe,SAAS,MAAM,kBAAkB;AACtD,MAAI,gBAAgB,IAAI,WAAW,QAAQ;GACzC,MAAM,iBAAiB,aAAa;AACpC,OAAI;AAEF,UAAM,cACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,gBACA,UACA,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,qBAAqB,SAAS,MAAM,kBAAkB;AAC5D,MAAI,sBAAsB,IAAI,WAAW,QAAQ;GAC/C,MAAM,iBAAiB,mBAAmB;AAC1C,OAAI;AAEF,UAAM,oBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,gBACA,UACA,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,gBAAgB,SAAS,MAAM,oBAAoB;AACzD,MAAI,iBAAiB,IAAI,WAAW,QAAQ;GAC1C,MAAM,kBAAkB,cAAc;AACtC,OAAI;AAEF,UAAM,eACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,iBACA,UACA,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,sBAAsB,SAAS,MAAM,2BAA2B;AACtE,MAAI,uBAAuB,IAAI,WAAW,QAAQ;GAChD,MAAM,wBAAwB,oBAAoB;AAClD,OAAI;AAEF,UAAM,qBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,uBACA,UACA,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,OAAI;AAEF,UAAM,aACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,iBAAiB,UAAU,EAAE,EAC7B,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,OAAI;AAEF,UAAM,aACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,iBAAiB,UAAU,EAAE,EAC7B,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,OAAI;AAEF,UAAM,iBACJ,KACA,KAHU,MAAM,SAAS,IAAI,EAK7B,iBAAiB,cAAc,EAAE,EACjC,SACA,UACA,eACD;YACM,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,oCAAoC,IAAI,WAAW,QAAQ;AAC1E,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,sBAAsB,KAAK,KADrB,MAAM,SAAS,IAAI,EACY,UAAU,UAAU,SAAS,mBAAmB;YACpF,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,qBAAqB,SAAS,MAAM,kBAAkB;AAC5D,MAAI,sBAAsB,IAAI,WAAW,QAAQ;AAC/C,kBAAe,IAAI;GACnB,MAAM,UAAU,mBAAmB;AACnC,OAAI;AAEF,UAAM,oBAAoB,KAAK,KADnB,MAAM,SAAS,IAAI,EACU,UAAU,UAAU,SAAS,QAAQ;YACvE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAIF,MAAM,aAAa,SAAS,MAAM,oBAAoB;AACtD,MAAI,cAAc,IAAI,WAAW,QAAQ;AACvC,kBAAe,IAAI;GACnB,MAAM,eAAe,WAAW,MAAM;AACtC,OAAI;AAEF,UAAM,sBAAsB,KAAK,KADrB,MAAM,SAAS,IAAI,EACY,UAAU,UAAU,SAAS,aAAa;YAC9E,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;EAKF,IAAI;AAMJ,MAAI,cAAc,KAAK,SAAS,IAAI,IAAI,QAAQ,sBAAsB;AACpE,kBAAe,IAAI;AACnB,OAAI;AACF,cAAU,IAAI,WAAW,UAAU,IAAI,WAAW,QAAQ,MAAM,SAAS,IAAI,GAAG;IAChF,MAAM,MAAM;IACZ,MAAM,cAAc,cAAc,MAAM,SAAS,OAAO,IAAI,SAAS,SAAS,OAAO;AACrF,QAAI,aAAa;AACf,sBACE,aACA,KACA,MACA,SACA;MACE,QAAQ,IAAI,UAAU;MACtB,MAAM;MACN,SAAS,eAAe,IAAI,QAAQ;MACpC,MAAM;OAAE,OAAO;OAAI,UAAU,EAAE;OAAE;MAClC,EACD,WACA,SAAS,SACV;AACD;;AAGF,QADgB,MAAM,UAAU,KAAK,KAAK,KAAK,UAAU,UAAU,UAAU,QAAQ,KACrE,UAAW;YAEpB,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;AAEf;;;AAMJ,MAD4B,SAAS,MAAM,oBAAoB,IACpC,IAAI,WAAW,QAAQ;AAChD,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,eAAe,KAAK,KADd,WAAY,MAAM,SAAS,IAAI,EACP,UAAU,UAAU,UAAU,QAAQ;YACnE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAKF,MAD8B,SAAS,MAAM,sBAAsB,KAGhE,IAAI,WAAW,SAAS,IAAI,WAAW,UAAU,IAAI,WAAW,QACjE;AACA,kBAAe,IAAI;AACnB,OAAI;IACF,MAAM,MACJ,IAAI,WAAW,UAAU,IAAI,WAAW,QAAS,WAAY,MAAM,SAAS,IAAI,GAAK;IACvF,MAAM,cAAc,cAAc,MAAM,SAAS,OAAO,IAAI,SAAS,SAAS,OAAO;AACrF,QAAI,aAAa;AACf,sBACE,aACA,KACA,MACA,SACA;MACE,QAAQ,IAAI,UAAU;MACtB,MAAM;MACN,SAAS,eAAe,IAAI,QAAQ;MACpC,MAAM;OAAE,OAAO;OAAI,UAAU,EAAE;OAAE;MAClC,EACD,WACA,SAAS,SACV;AACD;;AAEF,UAAM,eAAe,KAAK,KAAK,KAAK,UAAU,UAAU,UAAU,QAAQ;YACnE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAKF,MADoB,SAAS,MAAM,WAAW,IAC3B,IAAI,WAAW,QAAQ;AACxC,kBAAe,IAAI;AACnB,OAAI;AAEF,UAAM,eAAe,KAAK,KADd,WAAY,MAAM,SAAS,IAAI,EACP,UAAU,UAAU,UAAU,QAAQ;YACnE,KAAc;IACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;;AAGjB;;AAIF,MAAI,aAAa,kBAAkB;AACjC,kBAAe,KAAK,YAAY;AAChC;;AAEF,MAAI,IAAI,WAAW,QAAQ;AACzB,kBAAe,KAAK,YAAY;AAChC;;EAKF,MAAM,sBAAyC,oBAC3C,UACA,eACE,eACA,gBACE,aACA;AACR,MAAI;AACF,SAAM,kBACJ,KACA,KACA,UACA,SACA,UACA,mBACA,qBACA,aACD;WACM,KAAc;GACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,OAAI,CAAC,IAAI,YACP,oBACE,KACA,KACA,eACI,yBAAyB,KAAK,IAAI,GAClC,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACP,EACF,CAAC,CACP;YACQ,CAAC,IAAI,cAEd,KAAI;AACF,QAAI,MACF,SACE,eACI,yBAAyB,KAAK,IAAI,GAClC,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CACtE,MACF;AACD,QAAI,KAAK;YACF,UAAU;AACjB,WAAO,MAAM,4CAA4C,SAAS;;;;CAQ1E,MAAM,oCAAoB,IAAI,KAA0B;AAExD,QAAO,GACL,YACC,KAA2B,QAAmC,SAAiB;AAC9E,uBAAqB,KAAK,QAAQ,KAAK,CAAC,OAAO,QAAiB;GAC9D,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,YAAS,OAAO,KAAK,4BAA4B,MAAM;AACvD,OAAI,CAAC,OAAO,UAAW,QAAO,SAAS;IACvC;GAEL;;;;;;;;;CAUD,SAAS,uBAAuB,KAA4C;AAC1E,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,SAAmB,EAAE;GAC3B,IAAI,UAAU;GACd,MAAM,aAAmB;AACvB,QAAI,QAAS;AACb,cAAU;AACV,YAAQ,OAAO,OAAO,OAAO,CAAC;;AAEhC,OAAI,GAAG,SAAS,MAAc,OAAO,KAAK,EAAE,CAAC;AAC7C,OAAI,GAAG,OAAO,KAAK;AACnB,OAAI,GAAG,SAAS,KAAK;AACrB,OAAI,GAAG,SAAS,KAAK;AACrB,OAAI,QAAQ;IACZ;;CAGJ,eAAe,qBACb,KACA,QACA,MACe;AA0Bf,OAAK,IAAI,QAAQ,WAAW,IAAI,aAAa,KAAK,aAAa;GAC7D,MAAM,aAAa,MAAM,uBAAuB,IAAI;GACpD,MAAM,cAAc,GAAG,IAAI,OAAO,GAAG,IAAI,IAAI,QAAQ,IAAI,YAAY;GACrE,MAAM,cAAwB,EAAE;AAChC,QAAK,IAAI,IAAI,GAAG,IAAI,IAAI,WAAW,QAAQ,KAAK,GAAG;AACjD,QAAI,4BAA4B,KAAK,IAAI,WAAW,GAAG,CAAE;AACzD,gBAAY,KAAK,GAAG,IAAI,WAAW,GAAG,IAAI,IAAI,WAAW,IAAI,KAAK;;GAEpE,MAAM,UAAU,OAAO,KAAK,cAAc,YAAY,KAAK,OAAO,GAAG,WAAW;AAChF,UAAO,QAAQ,OAAO,OAAO;IAAC;IAAS;IAAY;IAAK,CAAC,CAAC;AAC1D,UAAO,KAAK,cAAc,OAAO;AACjC;;EAGF,MAAM,YAAY,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,QAAQ,cAAc;EACtF,IAAI,WAAW,UAAU;AAEzB,MAAI,CAAC,sBAAsB,KAAK,aAAa,OAAO,CAAC,IAAI;AACvD,+BAA4B,OAAO;AACnC;;AAIF,MAAI,QACF;QAAK,MAAM,EAAE,MAAM,WAAW,aAAa,OACzC,MACG,aAAa,aAAa,SAAS,WAAW,YAAY,IAAI,KAC/D,QAAQ,eACR;IACA,MAAM,UAAU,SAAS,MAAM,UAAU,OAAO,IAAI;AACpD,QAAI,MAAM,QAAQ,cAAc,QAAQ,MAAM,QAAQ,CAAE;;;AAO9D,MAAI,CAAC,SAAS,MAAM,oBAAoB,CACtC,YAAW,oBAAoB,UAAU,OAAO;AAGlD,MACE,aAAa,kBACb,aAAa,iBACb,aAAa,kBACb;AACA,UAAO,MAAM,iCAAiC;AAC9C,UAAO,SAAS;AAChB;;AAIF,MAAI,KAAK,SAAS,EAChB,QAAO,QAAQ,KAAK;EAGtB,IAAI;AACJ,MAAI;AACF,QAAK,mBAAmB,KAAK,OAAO;WAC7B,KAAc;GACrB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,UAAO,MAAM,4BAA4B,MAAM;AAC/C,OAAI,CAAC,OAAO,UAAW,QAAO,SAAS;AACvC;;AAGF,oBAAkB,IAAI,GAAG;AAEzB,KAAG,GAAG,UAAU,QAAe;AAC7B,UAAO,MAAM,oBAAoB,IAAI,UAAU;AAC/C,qBAAkB,OAAO,GAAG;IAC5B;AAEF,KAAG,GAAG,eAAe;AACnB,qBAAkB,OAAO,GAAG;IAC5B;EAGF,MAAM,WAAW,UAAU,IAAI;AAC/B,MAAI,aAAa,eACf,0BAAyB,IAAI,UAAU,SAAS;GAC9C,GAAG;GACH,OAAO;GACP,QAAQ;GACR,gBAAgB,IAAI;GACrB,CAAC;WACO,aAAa,eAAe;GACrC,MAAM,sBAAsB,UAAU,aAAa,IAAI,SAAS,KAAK;GACrE,MAAM,QAAQ,sBACV,mBACC,UAAU,aAAa,IAAI,QAAQ,IAAI;AAC5C,2BAAwB,IAAI,UAAU,SAAS;IAC7C,GAAG;IACH;IACA;IACA,QAAQ;IACR,gBAAgB,IAAI;IACrB,CAAC;aACO,aAAa,iBACtB,2BAA0B,IAAI,UAAU,SAAS;GAC/C,GAAG;GACH,OAAO;GACP,QAAQ;GACR,gBAAgB,IAAI;GACrB,CAAC;;CAKN,MAAM,gBAAgB,OAAO,MAAM,KAAK,OAAO;AAC/C,QAAO,QAAQ,SAA6B,UAAkC;AAC5E,OAAK,MAAM,MAAM,kBACf,IAAG,MAAM,MAAM,uBAAuB;AAExC,oBAAkB,OAAO;AACzB,cAAY,OAAO;AACnB,sBAAoB,OAAO;AAC3B,eAAa,OAAO;AACpB,gBAAc,OAAO;AACrB,oBAAkB,OAAO;AACzB,gBAAc,SAAS;AACvB,SAAO;;AAGT,QAAO,IAAI,SAAyB,SAAS,WAAW;AACtD,SAAO,GAAG,SAAS,OAAO;AAC1B,SAAO,OAAO,MAAM,YAAY;GAC9B,MAAM,OAAO,OAAO,SAAS;AAC7B,OAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,2BAAO,IAAI,MAAM,4BAA4B,CAAC;AAC9C;;GAEF,MAAM,MAAM,UAAU,KAAK,QAAQ,GAAG,KAAK;AAG3C,OAAI,QACF;SAAK,MAAM,EAAE,MAAM,WAAW,aAAa,OACzC,KAAI,QAAQ,WAAY,SAAQ,WAAW,MAAM,UAAU;;AAI/D,WAAQ;IACN;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD,CAAC;IACF;GACF"}
|
|
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 ChaosConfig,\n ChaosDefaults,\n HandlerDefaults,\n JournalEntry,\n MockServerOptions,\n Mountable,\n RecordProviderKey,\n} from \"./types.js\";\nimport { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic, recordMatchOptions } from \"./router.js\";\nimport {\n validateFixtures,\n entryToFixture,\n isInjectableStatus,\n INJECTED_STATUS_RANGE,\n} 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 isResponseFactory,\n isVideoResponse,\n isTranscriptionResponse,\n isImageResponse,\n isEmbeddingResponse,\n isJSONResponse,\n flattenHeaders,\n isJsonObject,\n getTestId,\n readBody,\n resolveResponse,\n resolveStrictMode,\n resolveReasoningForModel,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n getContext,\n} from \"./helpers.js\";\nimport { DEFAULT_TEST_ID } from \"./constants.js\";\nimport {\n isOpenRouterPath,\n buildOpenRouterCandidates,\n resolveOpenRouterShaping,\n shapeOpenRouterCompletion,\n shapeOpenRouterChunks,\n serializeOpenRouterError,\n handleOpenRouterModels,\n handleOpenRouterKey,\n handleOpenRouterCredits,\n} from \"./openrouter-chat.js\";\nimport type {\n FixtureResponse,\n ErrorResponse,\n ChatCompletion,\n SSEChunk,\n ResponseOverrides,\n} from \"./types.js\";\nimport { handleResponses } from \"./responses.js\";\nimport { handleMessages } from \"./messages.js\";\nimport { handleGemini } from \"./gemini.js\";\nimport { handleGeminiEmbedContent } from \"./gemini-embeddings.js\";\nimport { handleBedrock, handleBedrockStream } from \"./bedrock.js\";\nimport { handleConverse, handleConverseStream } from \"./bedrock-converse.js\";\nimport {\n handleGeminiInteractions,\n resetInteractionCounter,\n resetEventIdCounter,\n} from \"./gemini-interactions.js\";\nimport { handleEmbeddings } from \"./embeddings.js\";\nimport { handleImages, handleImageEdit, handleImageVariations } from \"./images.js\";\nimport { handleSpeech } from \"./speech.js\";\nimport { handleTranscription } from \"./transcription.js\";\nimport { handleVideoCreate, VideoStateMap } from \"./video.js\";\nimport {\n handleOpenRouterVideoCreate,\n handleOpenRouterVideoStatus,\n handleOpenRouterVideoContent,\n handleOpenRouterVideoModels,\n OpenRouterVideoJobMap,\n OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES,\n} from \"./openrouter-video.js\";\nimport { handleVeoVideoCreate, handleVeoVideoStatus, VeoVideoJobMap } from \"./veo-video.js\";\nimport { handleGrokVideoCreate, handleGrokVideoStatus, GrokVideoJobMap } from \"./grok-video.js\";\nimport {\n handleBytePlusVideoCreate,\n handleBytePlusVideoStatus,\n BytePlusVideoJobMap,\n} from \"./byteplus-video.js\";\nimport { handleElevenLabsAudio, handleElevenLabsTTS } from \"./elevenlabs-audio.js\";\nimport { 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, isChaosScope } from \"./chaos.js\";\nimport {\n createMetricsRegistry,\n normalizePathLabel,\n BYTEPLUS_VIDEO_STATUS_RE,\n BYTEPLUS_VIDEO_SUBMIT_RE,\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 bytePlusVideoJobs: BytePlusVideoJobMap;\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 // Response headers are invisible to cross-origin JS unless exposed. The\n // journal's pagination total is a response header (the body stays a bare\n // array for back-compat), so a browser harness needs this to read it.\n \"Access-Control-Expose-Headers\": \"X-Total-Count\",\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/** The complete `GET /__aimock/fixtures` query-param vocabulary; anything else 400s. */\nconst FIXTURES_PARAMS: ReadonlySet<string> = new Set([\"include\"]);\n\n/** The complete `GET /__aimock/journal` query-param vocabulary; anything else 400s. */\nconst JOURNAL_PARAMS: ReadonlySet<string> = new Set([\n \"limit\",\n \"offset\",\n \"path\",\n \"method\",\n \"status\",\n \"service\",\n \"testId\",\n]);\n\n/**\n * The per-server state a full reset clears. `ServerInstance` structurally\n * satisfies this, so `LLMock.reset()` and the control-API full-reset route\n * share a single definition of \"everything\" instead of two lists that drift.\n */\nexport interface FullResetTargets {\n journal: Journal;\n videoStates: VideoStateMap;\n openRouterVideoJobs: OpenRouterVideoJobMap;\n veoVideoJobs: VeoVideoJobMap;\n grokVideoJobs: GrokVideoJobMap;\n bytePlusVideoJobs: BytePlusVideoJobMap;\n defaults: HandlerDefaults;\n}\n\n/**\n * Perform a full reset: clear the fixtures array, the journal (entries *and*\n * per-test fixture match-counts, i.e. sequence position), the video and fal.ai\n * job/queue state, the Gemini interaction/event-id counters, and any runtime\n * chaos override (reverting to the construction-time chaos config), then\n * re-zero 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 // Drop any runtime chaos override installed via POST /__aimock/chaos, so the\n // server returns to the chaos configuration it was STARTED with. Reset is the\n // isolation barrier every parallel harness leans on; chaos leaking past it\n // poisons later tests with 500s that look like application bugs.\n targets.defaults.chaos = undefined;\n targets.videoStates.clear();\n targets.openRouterVideoJobs.clear();\n targets.veoVideoJobs.clear();\n targets.grokVideoJobs.clear();\n targets.bytePlusVideoJobs.clear();\n if (targets.defaults.registry) {\n targets.defaults.registry.setGauge(\"aimock_fixtures_loaded\", {}, fixtures.length);\n }\n}\n\n/**\n * JSON-safe redaction for control-API inspection output. Functions (fixture\n * `predicate`s, response factories) and RegExps do not survive\n * JSON.stringify as anything useful, so they become marker strings.\n */\nfunction redactForInspection(value: unknown): unknown {\n if (typeof value === \"function\") return \"[function]\";\n if (value instanceof RegExp) return String(value);\n if (Array.isArray(value)) return value.map(redactForInspection);\n if (value !== null && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n out[key] = redactForInspection(entry);\n }\n return out;\n }\n return value;\n}\n\n/**\n * One-line kind label for a fixture response used by\n * `GET /__aimock/fixtures?include=fixtures` (e.g. \"text\", \"error\").\n * Response factories are reported as \"factory\".\n *\n * Discriminates with the same `is*Response` guards the request handlers use,\n * in the same order — NOT by inspecting keys. Every response shape extends\n * `ResponseOverrides` (`id`/`created`/`model`/`usage`), so a recorded fixture's\n * first key is usually an envelope override rather than the discriminant. The\n * audio-before-content/toolCalls order is the ORDERING CONTRACT documented on\n * `AudioResponse` in types.ts: those shapes structurally overlap.\n */\nfunction fixtureResponseKind(response: Fixture[\"response\"]): string {\n if (isResponseFactory(response)) return \"factory\";\n if (isErrorResponse(response)) return \"error\";\n if (isAudioResponse(response)) return \"audio\";\n if (isVideoResponse(response)) return \"video\";\n if (isTranscriptionResponse(response)) return \"transcription\";\n if (isImageResponse(response)) return \"image\";\n if (isEmbeddingResponse(response)) return \"embedding\";\n if (isJSONResponse(response)) return \"json\";\n if (isContentWithToolCallsResponse(response)) return \"contentWithToolCalls\";\n if (isToolCallResponse(response)) return \"toolCalls\";\n if (isTextResponse(response)) return \"text\";\n return \"unknown\";\n}\n\n/**\n * Resolve a journal entry's testId exactly the way `getTestId` resolves an\n * incoming request's: the `X-Test-Id` header wins, then `?testId=` parsed out\n * of the query string, then `DEFAULT_TEST_ID`. The\n * filter and the server's own per-test isolation must never disagree — and a\n * raw `path.includes(\"testId=t1\")` both prefix-collides with `t10` and matches\n * unrelated params like `notTestId`.\n */\nfunction journalEntryTestId(entry: JournalEntry): string {\n const header = entry.headers[\"x-test-id\"];\n if (header) return header;\n const qIdx = entry.path.indexOf(\"?\");\n if (qIdx !== -1) {\n const queryValue = new URLSearchParams(entry.path.slice(qIdx + 1)).get(\"testId\");\n if (queryValue) return queryValue;\n }\n return DEFAULT_TEST_ID;\n}\n\n/**\n * The testId a chaos override is stored under, and read back with — resolved by\n * `getTestId`, i.e. `X-Test-Id` header then `?testId=`, exactly as\n * `resolveScopedDefaults` resolves the traffic being evaluated. A control call\n * and the requests it is meant to affect can then never land in different\n * scopes. `DEFAULT_TEST_ID` (neither header nor param) means the server-wide\n * baseline.\n *\n * Returns `null` when `X-Test-Id` is PRESENT but blank. `String(testId ?? \"\")`\n * in a harness produces that trivially, and silently treating it as \"untagged\"\n * would install a server-wide baseline that fails every other test — the exact\n * cross-test leak per-testId scoping exists to prevent. Callers must 400.\n */\nfunction chaosScopeId(req: http.IncomingMessage): string | null {\n const headerValue = req.headers[\"x-test-id\"];\n const raw = Array.isArray(headerValue) ? headerValue[0] : headerValue;\n if (typeof raw === \"string\" && raw.trim() === \"\") return null;\n return getTestId(req);\n}\n\n/** 400 for a control call whose `X-Test-Id` is present but blank. */\nfunction writeBlankTestId(res: http.ServerResponse): true {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'X-Test-Id': header is present but empty\" }));\n return true;\n}\n\n/** The chaos config in effect for one testId: its override, else the baseline. */\nfunction effectiveChaos(defaults: HandlerDefaults, scopeId: string): ChaosConfig {\n const scoped = defaults.chaosByTestId?.get(scopeId);\n if (scoped) return scoped;\n const current = defaults.chaos;\n if (!current) return {};\n return isChaosScope(current) ? (current.base ?? {}) : current;\n}\n\n/**\n * Handle requests under `/__aimock/`. Returns `true` if the request was\n * handled, `false` if the path doesn't match the control prefix.\n */\nasync function handleControlAPI(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n searchParams: URLSearchParams,\n fixtures: Fixture[],\n journal: Journal,\n videoStates: VideoStateMap,\n openRouterVideoJobs: OpenRouterVideoJobMap,\n veoVideoJobs: VeoVideoJobMap,\n grokVideoJobs: GrokVideoJobMap,\n bytePlusVideoJobs: BytePlusVideoJobMap,\n defaults: HandlerDefaults,\n): 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 — optionally filtered/paginated.\n // No query params → full array (historical behaviour, unchanged).\n // Supported params: limit (int >= 0), offset (int >= 0, default 0),\n // path (SUBSTRING), method (exact, case-insensitive), status (int),\n // service (EXACT), testId (resolved exactly as the server resolves it).\n // Anything else is a 400: silently ignoring an unknown param would let\n // `?statusCode=404` return the whole journal and pass a caller's assertion\n // against traffic it never meant to select.\n if (subPath === \"/journal\" && req.method === \"GET\") {\n const bad = (message: string): true => {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: message }));\n return true;\n };\n for (const key of searchParams.keys()) {\n if (!JOURNAL_PARAMS.has(key)) {\n return bad(\n `Unknown query parameter: '${key}'. Supported: ${[...JOURNAL_PARAMS].join(\", \")}`,\n );\n }\n }\n const parseNonNegativeInt = (name: string, fallback: number): number | null => {\n const raw = searchParams.get(name);\n if (raw === null) return fallback;\n if (!/^\\d+$/.test(raw.trim())) return null;\n return Number(raw);\n };\n const limit = parseNonNegativeInt(\"limit\", -1);\n const offset = parseNonNegativeInt(\"offset\", 0);\n if (limit === null) return bad(\"Invalid 'limit': must be an integer >= 0\");\n if (offset === null) return bad(\"Invalid 'offset': must be an integer >= 0\");\n let statusFilter: number | undefined;\n const statusRaw = searchParams.get(\"status\");\n if (statusRaw !== null) {\n if (!/^\\d+$/.test(statusRaw.trim())) return bad(\"Invalid 'status': must be an integer\");\n statusFilter = Number(statusRaw);\n }\n const pathFilter = searchParams.get(\"path\");\n const methodFilter = searchParams.get(\"method\");\n const serviceFilter = searchParams.get(\"service\");\n const testIdFilter = searchParams.get(\"testId\");\n\n let entries: JournalEntry[] = journal.getAll();\n if (methodFilter !== null) {\n const want = methodFilter.toUpperCase();\n entries = entries.filter((e) => e.method.toUpperCase() === want);\n }\n if (pathFilter !== null) {\n entries = entries.filter((e) => e.path.includes(pathFilter));\n }\n if (statusFilter !== undefined) {\n entries = entries.filter((e) => e.response.status === statusFilter);\n }\n if (serviceFilter !== null) {\n entries = entries.filter((e) => e.service === serviceFilter);\n }\n if (testIdFilter !== null) {\n entries = entries.filter((e) => journalEntryTestId(e) === testIdFilter);\n }\n // Count AFTER filtering but BEFORE pagination, so a paging caller can tell\n // when it is done. It ships as a header because the body is a bare array\n // for back-compat and can never grow an envelope.\n const total = entries.length;\n if (offset > 0) entries = entries.slice(offset);\n if (limit >= 0) entries = entries.slice(0, limit);\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"X-Total-Count\": String(total),\n });\n res.end(JSON.stringify(entries));\n return true;\n }\n\n // GET /__aimock/fixtures — inspect current fixture count. With\n // ?include=fixtures, also dump each fixture's (redacted) match criteria\n // and response kind so harnesses can assert what would match.\n if (subPath === \"/fixtures\" && req.method === \"GET\") {\n // Unknown params 400 for the same reason `/journal` does: a typo like\n // `?incluide=fixtures` must never quietly return the count-only body and\n // pass an assertion against a dump the caller never received.\n for (const key of searchParams.keys()) {\n if (!FIXTURES_PARAMS.has(key)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Unknown query parameter: '${key}'. Supported: ${[...FIXTURES_PARAMS].join(\", \")}`,\n }),\n );\n return true;\n }\n }\n const include = searchParams.get(\"include\");\n if (include === null) {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ count: fixtures.length }));\n return true;\n }\n if (include !== \"fixtures\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'include': expected 'fixtures'\" }));\n return true;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n count: fixtures.length,\n fixtures: fixtures.map((fixture, index) => ({\n index,\n match: redactForInspection(fixture.match),\n // NOT `response` — that name already means the response ITSELF on\n // `Fixture`, and this is only a one-word kind label.\n responseKind: fixtureResponseKind(fixture.response),\n ...(fixture.latency !== undefined ? { latency: fixture.latency } : {}),\n ...(fixture.chaos !== undefined ? { chaos: fixture.chaos } : {}),\n })),\n }),\n );\n return true;\n }\n\n // GET /__aimock/chaos — read the chaos config in effect for THIS caller's\n // testId: its own override if one is installed, else the server-wide\n // baseline (the construction config, or an untagged override).\n if (subPath === \"/chaos\" && req.method === \"GET\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // DELETE /__aimock/chaos — drop the override for this caller's testId (or the\n // server-wide baseline when untagged), falling back to what it shadowed.\n // `POST {}` means \"explicitly no chaos\"; this means \"forget I said anything\".\n //\n // SYMMETRIC with POST: an untagged DELETE drops the untagged baseline ONLY.\n // Dropping every per-testId override too would let one test's cleanup revoke\n // a concurrently-running test's opt-out. `POST /__aimock/reset` is the one\n // route that clears everything.\n if (subPath === \"/chaos\" && req.method === \"DELETE\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n defaults.chaosByTestId?.delete(scopeId);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // POST /__aimock/chaos — replace the server chaos config at runtime (no\n // restart). Accepts any subset of dropRate/malformedRate/disconnectRate as\n // numbers in [0, 1]; `{}` means explicitly no chaos. Unknown fields and\n // out-of-range values are rejected with 400.\n //\n // SCOPED to the caller's testId (`X-Test-Id`, else `?testId=`), like every\n // other mutable axis in the server (fixture match-counts, video job maps): an\n // override installed by test `t1` applies only to traffic resolving to `t1`.\n // An untagged call sets the server-wide baseline. `POST /__aimock/reset`\n // drops all of it, restoring the chaos config the server was STARTED with.\n if (subPath === \"/chaos\" && req.method === \"POST\") {\n const scopeId = chaosScopeId(req);\n if (scopeId === null) return writeBlankTestId(res);\n let raw: string;\n try {\n raw = await readBody(req);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/chaos: failed to read body: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Failed to read request body: ${msg}` }));\n return true;\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n defaults.logger.error(`POST /__aimock/chaos: invalid JSON: ${msg}`);\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid JSON: ${msg}` }));\n return true;\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid body: expected a JSON object\" }));\n return true;\n }\n const allowed = [\"dropRate\", \"malformedRate\", \"disconnectRate\"] as const;\n for (const key of Object.keys(parsed)) {\n if (!(allowed as readonly string[]).includes(key)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Unknown chaos field: '${key}'` }));\n return true;\n }\n }\n const next: ChaosConfig = {};\n for (const key of allowed) {\n const value = parsed[key];\n if (value === undefined) continue;\n if (typeof value !== \"number\" || Number.isNaN(value) || value < 0 || value > 1) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid '${key}': must be a number between 0 and 1` }));\n return true;\n }\n next[key] = value;\n }\n defaults.chaosByTestId?.set(scopeId, next);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ chaos: effectiveChaos(defaults, scopeId) }));\n return true;\n }\n\n // 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 bytePlusVideoJobs,\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 // Validate the payload — an unchecked `status` reaches\n // `res.writeHead(status)` on the next matched request and throws\n // ERR_HTTP_INVALID_STATUS_CODE for 99, 0, 1000 or 99.5, losing the\n // injected error and degrading to a generic 500.\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid body: expected a JSON object\" }));\n return true;\n }\n // Omitted — or an explicit null, which is how a serializer spells an absent\n // optional — keeps the historic default of 500.\n const status = parsed.status ?? 500;\n if (!isInjectableStatus(status)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid 'status': must be ${INJECTED_STATUS_RANGE}` }));\n return true;\n }\n const errorBody = parsed.body;\n // `body: null` is an absent body, not a malformed one — same rule as the\n // fields below and as `status`. Rejecting it broke a call that worked\n // (main defaulted every field) for a shape any serializer emits for an\n // unset optional.\n if (errorBody !== undefined && errorBody !== null) {\n if (typeof errorBody !== \"object\" || Array.isArray(errorBody)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid 'body': must be an object\" }));\n return true;\n }\n for (const field of [\"message\", \"type\", \"code\"] as const) {\n const value = errorBody[field];\n // null means absent, not invalid: aimock's own error envelope\n // (`serializeErrorResponse`) emits `code: null`, and so does a real\n // OpenAI error, so a captured body can be pasted back verbatim.\n if (value !== undefined && value !== null && typeof value !== \"string\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: `Invalid 'body.${field}': must be a string` }));\n return true;\n }\n }\n }\n 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 } catch (parseErr: unknown) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown parse error\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, `Malformed JSON: ${detail}`)\n : JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n param: null,\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `body.messages` throws a TypeError that\n // surfaces as a 500 instead of a 400.\n if (!isJsonObject(body)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, \"Request body must be a JSON object\")\n : JSON.stringify({\n error: {\n message: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Azure deployments may omit model from body — use deployment ID as fallback\n if (modelFallback && !body.model) {\n body.model = modelFallback;\n }\n\n // Validate messages array\n if (!Array.isArray(body.messages)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n openRouter\n ? serializeOpenRouterError(400, \"Missing required parameter: 'messages'\")\n : JSON.stringify({\n error: {\n message: \"Missing required parameter: 'messages'\",\n type: \"invalid_request_error\",\n param: null,\n code: null,\n },\n }),\n );\n return;\n }\n\n const 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, req.url);\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 // Runtime-mutable server chaos config. Reads fall through to the construction\n // options until POST /__aimock/chaos installs an override, which is scoped to\n // the caller's testId. The untagged baseline lives in the SAME map under\n // DEFAULT_TEST_ID, so \"drop the baseline\" and \"drop one test's override\" are\n // one operation and neither can accidentally take the other's overrides with\n // it; only assigning `undefined` (a full reset) clears the map.\n const chaosByTestId = new Map<string, ChaosConfig>();\n const defaults = {\n latency: serverOptions.latency ?? 0,\n chunkSize: Math.max(1, serverOptions.chunkSize ?? DEFAULT_CHUNK_SIZE),\n replaySpeed: serverOptions.replaySpeed ?? 1.0,\n logger,\n chaosByTestId,\n // Handlers get a SCOPE, not a flat config: chaos.ts picks the override for\n // the request's X-Test-Id and falls back to the baseline.\n get chaos(): ChaosDefaults {\n return {\n base: chaosByTestId.get(DEFAULT_TEST_ID) ?? serverOptions.chaos,\n byTestId: chaosByTestId,\n };\n },\n // Assigning `undefined` drops EVERY runtime override instead of latching an\n // empty one, so the construction-time chaos config is always recoverable\n // (that is what `POST /__aimock/reset` does). `POST {}` still installs a\n // real, empty override: \"explicitly no chaos\".\n set chaos(value: ChaosDefaults | undefined) {\n if (value === undefined) {\n chaosByTestId.clear();\n return;\n }\n const base = isChaosScope(value) ? value.base : value;\n if (base === undefined) chaosByTestId.delete(DEFAULT_TEST_ID);\n else chaosByTestId.set(DEFAULT_TEST_ID, base);\n },\n registry,\n get record() {\n return serverOptions.record;\n },\n get strict() {\n return serverOptions.strict;\n },\n get requestTransform() {\n return serverOptions.requestTransform;\n },\n get falQueue() {\n return serverOptions.falQueue;\n },\n get openRouterVideo() {\n return serverOptions.openRouterVideo;\n },\n get veoVideo() {\n return serverOptions.veoVideo;\n },\n get grokVideo() {\n return serverOptions.grokVideo;\n },\n get bytePlusVideo() {\n return serverOptions.bytePlusVideo;\n },\n };\n\n // Validate chaos 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 { name: \"bytePlusVideo\", config: options?.bytePlusVideo },\n ]) {\n if (!config) continue;\n for (const field of [\"pollsBeforeInProgress\", \"pollsBeforeCompleted\"] as const) {\n const value = config[field];\n if (value === undefined) continue;\n if (!Number.isFinite(value)) {\n logger.warn(`${name}.${field} (${value}) is not a finite number — treating as unset`);\n } else if (!Number.isInteger(value) || value < 0) {\n logger.warn(\n `${name}.${field} (${value}) is not a non-negative integer — flooring/clamping to a non-negative integer`,\n );\n }\n }\n }\n\n // Validate the recorded-b64 cap: the capture path treats a negative or\n // non-integer record.openRouterVideo.maxContentBytes as the default rather\n // than letting `cap > 0` checks misbehave on negatives or NaN.\n {\n const cap = options?.record?.openRouterVideo?.maxContentBytes;\n if (cap !== undefined && (!Number.isInteger(cap) || cap < 0)) {\n logger.warn(\n `record.openRouterVideo.maxContentBytes (${cap}) is not a non-negative integer — using the default cap (${OPENROUTER_VIDEO_DEFAULT_MAX_CONTENT_BYTES})`,\n );\n }\n }\n\n // Reject a BytePlus upstream base that already carries Ark's `/api/v3`\n // prefix. `record.providers.byteplus` is an ORIGIN: the video handlers pass\n // the full `/api/v3/contents/generations/tasks[...]` constant to\n // resolveUpstreamUrl, and the chat/images proxies relay the client's raw\n // `req.url` (which is itself `/api/v3/...`). `@tanstack/ai-byteplus@0.3.4`\n // ships `https://ark.ap-southeast.bytepluses.com/api/v3` as its default Ark\n // `base_url` (`BYTEPLUS_ARK_BASE_URL`, which its own author labels\n // \"Docs-derived\" — this repo has not read BytePlus's docs), so pasting that\n // into --provider-byteplus is the expected mistake, and it composes\n // `/api/v3/api/v3/...` on every BytePlus path. The origin+prefix itself IS\n // observed to serve: a keyless GET under it answers 401, not 404.\n //\n // This THROWS rather than silently stripping the suffix, for two reasons.\n // (1) Nothing is being taken away: the doubled form cannot serve any\n // BytePlus request, so there is no working configuration to preserve —\n // whereas a silent strip would make aimock rewrite an operator-supplied URL\n // and would be flatly wrong for the one case where a path-suffixed base is\n // deliberate (a reverse proxy mounted under a path: stripping sends the\n // request to the origin, bypassing the mount). (2) A warn is easy to miss in\n // a mock server's log stream, and the symptom it leaves behind — a relayed\n // upstream 404 — does not name its cause. Fail at startup, where the message\n // can.\n {\n const bytePlusBase = options?.record?.providers?.byteplus;\n if (bytePlusBase !== undefined) {\n let basePath: string | undefined;\n try {\n basePath = new URL(bytePlusBase).pathname;\n } catch {\n // Not parseable as an absolute URL — leave it to the request path to\n // report; this guard only speaks to the prefix-doubling mistake.\n }\n if (basePath !== undefined && /(^|\\/)api\\/v3\\/?$/.test(basePath)) {\n throw new Error(\n `record.providers.byteplus (${bytePlusBase}) ends in /api/v3, but aimock ` +\n `appends the /api/v3 prefix itself — every BytePlus request would go to ` +\n `/api/v3/api/v3/... and fail upstream. Configure the ORIGIN only ` +\n `(e.g. https://ark.ap-southeast.bytepluses.com).`,\n );\n }\n }\n }\n\n // 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 const bytePlusVideoJobs = new BytePlusVideoJobMap();\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 // BytePlus Ark attribution, GATED ON CONFIGURATION. A path prefix is not\n // evidence of a vendor — the COMPAT_SUFFIXES comment above exists precisely\n // because arbitrary vendors ride arbitrary prefixes (BigModel uses /v4/).\n // Ungated, anyone serving an OpenAI-compatible vendor under /api/v3 with\n // `record.providers.openai` configured would suddenly look up a byteplus\n // upstream, find none, and lose record mode entirely. Requiring a\n // configured byteplus upstream makes the new behavior reachable only for\n // the user who asked for it.\n const isBytePlusArk =\n defaults.record?.providers.byteplus !== undefined && originalPathname.startsWith(\"/api/v3/\");\n\n // 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 parsedUrl.searchParams,\n fixtures,\n journal,\n videoStates,\n openRouterVideoJobs,\n veoVideoJobs,\n grokVideoJobs,\n bytePlusVideoJobs,\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 // ── BytePlus Ark (Seedance) async video task lifecycle ──────────────────\n // Registered in the PRE-REWRITE band, alongside the OpenRouter video routes\n // above: normalizeCompatPath does not currently claim these paths, but the\n // Ollama block documents that hazard and the mount dispatch also runs\n // pre-rewrite, so keeping every raw-path route in one band keeps one rule.\n //\n // The REs anchor an ENUMERATED optional `/api/v3` prefix (see metrics.ts).\n // That matters here specifically because this band runs ~1,100 lines ahead\n // of every fal branch, so a wildcard prefix would take\n // `/fal/contents/generations/tasks` away from the fal proxy.\n //\n // Status is tested BEFORE submit and each is method-guarded, so a future\n // DELETE .../tasks/{id} falls through to 404 rather than being mis-served.\n const bytePlusVideoStatusMatch = pathname.match(BYTEPLUS_VIDEO_STATUS_RE);\n if (bytePlusVideoStatusMatch && req.method === \"GET\") {\n try {\n await handleBytePlusVideoStatus(\n req,\n res,\n bytePlusVideoStatusMatch[1],\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`byteplus-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 `byteplus-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 if (BYTEPLUS_VIDEO_SUBMIT_RE.test(pathname) && req.method === \"POST\") {\n setCorsHeaders(res);\n try {\n const raw = await readBody(req);\n await handleBytePlusVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n bytePlusVideoJobs,\n );\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.error(`byteplus-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 `byteplus-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(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"openai\",\n undefined,\n isBytePlusArk ? \"byteplus\" : undefined,\n );\n } catch (err: unknown) {\n 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(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n if (chaosAction) {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n {\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: { 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(\n null,\n defaults.chaos,\n req.headers,\n defaults.logger,\n req.url,\n );\n if (chaosAction) {\n applyChaosAction(\n chaosAction,\n res,\n null,\n journal,\n {\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: { 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 : isBytePlusArk\n ? \"byteplus\"\n : \"openai\";\n try {\n await handleCompletions(\n req,\n res,\n fixtures,\n journal,\n defaults,\n azureDeploymentId,\n completionsProvider,\n isOpenRouter,\n );\n } catch (err: unknown) {\n 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 /**\n * Body bytes the platform already parsed onto `req` for an upgrade request.\n *\n * Node >= 26 delivers an upgrade request's body here and leaves `head`\n * empty; Node <= 24 leaves the body in `head` and ends `req` with nothing.\n * The stream has already ended in both cases, so this resolves on the next\n * tick either way — it never waits on the network.\n */\n function drainParsedRequestBody(req: http.IncomingMessage): Promise<Buffer> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n let settled = false;\n const done = (): void => {\n if (settled) return;\n settled = true;\n resolve(Buffer.concat(chunks));\n };\n req.on(\"data\", (c: Buffer) => chunks.push(c));\n req.on(\"end\", done);\n req.on(\"error\", done);\n req.on(\"close\", done);\n req.resume();\n });\n }\n\n async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n // `Upgrade: h2c` + `Connection: Upgrade` on plain requests — including\n // ones with a body — to probe for HTTP/2 cleartext support. Only actual\n // WebSocket upgrades belong on this path.\n //\n // Node fires \"upgrade\" instead of \"request\" for any `Connection: Upgrade`,\n // whatever protocol is named, and the request never reaches the normal\n // pipeline. Rather than reimplementing body parsing, rebuild the request\n // line and headers with `Upgrade`/`Connection` dropped — the only thing\n // that made this look like an upgrade — replay them onto the socket, and\n // let Node re-parse the connection from scratch as an ordinary request.\n //\n // WHERE THE BODY LIVES DEPENDS ON THE NODE VERSION, and both cases must be\n // replayed or the re-parsed request stalls forever waiting on a\n // `Content-Length` worth of bytes that will never arrive:\n //\n // - Node <= 24 detaches the parser at \"upgrade\", so `req` yields nothing\n // and any body bytes already read land in `head` (or, if the client\n // sent them later, still arrive on the socket afterwards).\n // - Node >= 26 parses the body onto `req` and leaves `head` EMPTY. The\n // bytes are not on the socket either — draining `req` is the only way\n // to get them back.\n //\n // Draining `req` is safe on both: on the older behaviour it ends\n // immediately with zero bytes, so the concat below is a no-op there and\n // `head` carries the body as before.\n if ((req.headers.upgrade ?? \"\").toLowerCase() !== \"websocket\") {\n const parsedBody = await drainParsedRequestBody(req);\n const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\\r\\n`;\n const headerLines: string[] = [];\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n if (/^(?:upgrade|connection)$/i.test(req.rawHeaders[i])) continue;\n headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);\n }\n const rebuilt = Buffer.from(requestLine + headerLines.join(\"\\r\\n\") + \"\\r\\n\\r\\n\");\n socket.unshift(Buffer.concat([rebuilt, parsedBody, head]));\n server.emit(\"connection\", socket);\n return;\n }\n\n 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 bytePlusVideoJobs.clear();\n originalClose(callback);\n return this;\n } as typeof server.close;\n\n return new Promise<ServerInstance>((resolve, reject) => {\n server.on(\"error\", reject);\n server.listen(port, host, () => {\n const addr = server.address();\n if (!addr || typeof addr === \"string\") {\n reject(new Error(\"Unexpected address format\"));\n return;\n }\n const url = `http://${addr.address}:${addr.port}`;\n\n // 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 bytePlusVideoJobs,\n });\n });\n });\n}\n"],"mappings":"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"}
|