@copilotkit/aimock 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +2 -0
  4. package/dist/a2a-types.d.ts.map +1 -1
  5. package/dist/bedrock-converse.cjs +6 -4
  6. package/dist/bedrock-converse.cjs.map +1 -1
  7. package/dist/bedrock-converse.d.cts.map +1 -1
  8. package/dist/bedrock-converse.d.ts.map +1 -1
  9. package/dist/bedrock-converse.js +7 -5
  10. package/dist/bedrock-converse.js.map +1 -1
  11. package/dist/bedrock.cjs +6 -4
  12. package/dist/bedrock.cjs.map +1 -1
  13. package/dist/bedrock.d.cts.map +1 -1
  14. package/dist/bedrock.d.ts.map +1 -1
  15. package/dist/bedrock.js +7 -5
  16. package/dist/bedrock.js.map +1 -1
  17. package/dist/cohere.cjs +3 -2
  18. package/dist/cohere.cjs.map +1 -1
  19. package/dist/cohere.d.cts.map +1 -1
  20. package/dist/cohere.d.ts.map +1 -1
  21. package/dist/cohere.js +4 -3
  22. package/dist/cohere.js.map +1 -1
  23. package/dist/embeddings.cjs +3 -2
  24. package/dist/embeddings.cjs.map +1 -1
  25. package/dist/embeddings.d.cts.map +1 -1
  26. package/dist/embeddings.d.ts.map +1 -1
  27. package/dist/embeddings.js +4 -3
  28. package/dist/embeddings.js.map +1 -1
  29. package/dist/gemini.cjs +105 -30
  30. package/dist/gemini.cjs.map +1 -1
  31. package/dist/gemini.d.cts.map +1 -1
  32. package/dist/gemini.d.ts.map +1 -1
  33. package/dist/gemini.js +106 -31
  34. package/dist/gemini.js.map +1 -1
  35. package/dist/helpers.cjs +150 -14
  36. package/dist/helpers.cjs.map +1 -1
  37. package/dist/helpers.d.cts.map +1 -1
  38. package/dist/helpers.d.ts.map +1 -1
  39. package/dist/helpers.js +147 -15
  40. package/dist/helpers.js.map +1 -1
  41. package/dist/index.cjs +1 -0
  42. package/dist/index.d.cts +2 -2
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.js +2 -2
  45. package/dist/journal.cjs +26 -9
  46. package/dist/journal.cjs.map +1 -1
  47. package/dist/journal.d.cts +10 -5
  48. package/dist/journal.d.cts.map +1 -1
  49. package/dist/journal.d.ts +10 -5
  50. package/dist/journal.d.ts.map +1 -1
  51. package/dist/journal.js +26 -10
  52. package/dist/journal.js.map +1 -1
  53. package/dist/llmock.cjs +2 -2
  54. package/dist/llmock.cjs.map +1 -1
  55. package/dist/llmock.d.cts +1 -1
  56. package/dist/llmock.d.ts +1 -1
  57. package/dist/llmock.js +2 -2
  58. package/dist/llmock.js.map +1 -1
  59. package/dist/messages.cjs +192 -2
  60. package/dist/messages.cjs.map +1 -1
  61. package/dist/messages.d.cts.map +1 -1
  62. package/dist/messages.d.ts.map +1 -1
  63. package/dist/messages.js +193 -3
  64. package/dist/messages.js.map +1 -1
  65. package/dist/ollama.cjs +6 -4
  66. package/dist/ollama.cjs.map +1 -1
  67. package/dist/ollama.d.cts.map +1 -1
  68. package/dist/ollama.d.ts.map +1 -1
  69. package/dist/ollama.js +7 -5
  70. package/dist/ollama.js.map +1 -1
  71. package/dist/responses.cjs +250 -126
  72. package/dist/responses.cjs.map +1 -1
  73. package/dist/responses.d.cts.map +1 -1
  74. package/dist/responses.d.ts.map +1 -1
  75. package/dist/responses.js +251 -127
  76. package/dist/responses.js.map +1 -1
  77. package/dist/server.cjs +42 -5
  78. package/dist/server.cjs.map +1 -1
  79. package/dist/server.d.cts.map +1 -1
  80. package/dist/server.d.ts.map +1 -1
  81. package/dist/server.js +43 -6
  82. package/dist/server.js.map +1 -1
  83. package/dist/stream-collapse.cjs +48 -40
  84. package/dist/stream-collapse.cjs.map +1 -1
  85. package/dist/stream-collapse.d.cts.map +1 -1
  86. package/dist/stream-collapse.d.ts.map +1 -1
  87. package/dist/stream-collapse.js +48 -40
  88. package/dist/stream-collapse.js.map +1 -1
  89. package/dist/types.d.cts +9 -1
  90. package/dist/types.d.cts.map +1 -1
  91. package/dist/types.d.ts +9 -1
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/ws-gemini-live.cjs +4 -2
  94. package/dist/ws-gemini-live.cjs.map +1 -1
  95. package/dist/ws-gemini-live.d.cts +1 -0
  96. package/dist/ws-gemini-live.d.ts +1 -0
  97. package/dist/ws-gemini-live.js +4 -2
  98. package/dist/ws-gemini-live.js.map +1 -1
  99. package/dist/ws-realtime.cjs +4 -2
  100. package/dist/ws-realtime.cjs.map +1 -1
  101. package/dist/ws-realtime.d.cts +1 -0
  102. package/dist/ws-realtime.d.ts +1 -0
  103. package/dist/ws-realtime.js +4 -2
  104. package/dist/ws-realtime.js.map +1 -1
  105. package/dist/ws-responses.cjs +4 -2
  106. package/dist/ws-responses.cjs.map +1 -1
  107. package/dist/ws-responses.d.cts +1 -0
  108. package/dist/ws-responses.d.ts +1 -0
  109. package/dist/ws-responses.js +4 -2
  110. package/dist/ws-responses.js.map +1 -1
  111. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["entryToFixture","validateFixtures","flattenHeaders","matchFixture","applyChaos","proxyAndRecord","isErrorResponse","isTextResponse","buildTextCompletion","buildTextChunks","createInterruptionSignal","writeSSEStream","isToolCallResponse","buildToolCallCompletion","buildToolCallChunks","Logger","createMetricsRegistry","Journal","http","normalizePathLabel","handleResponses","handleMessages","handleCohere","handleEmbeddings","handleGemini","handleBedrock","handleBedrockStream","handleConverse","handleConverseStream","handleOllama","handleOllamaGenerate","handleSearch","handleRerank","handleModeration","upgradeToWebSocket"],"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 { matchFixture } 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 isTextResponse,\n isToolCallResponse,\n isErrorResponse,\n flattenHeaders,\n} from \"./helpers.js\";\nimport { handleResponses } from \"./responses.js\";\nimport { handleMessages } from \"./messages.js\";\nimport { handleGemini } from \"./gemini.js\";\nimport { handleBedrock, handleBedrockStream } from \"./bedrock.js\";\nimport { handleConverse, handleConverseStream } from \"./bedrock-converse.js\";\nimport { handleEmbeddings } from \"./embeddings.js\";\nimport { handleOllama, handleOllamaGenerate } from \"./ollama.js\";\nimport { handleCohere } 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 { applyChaos } from \"./chaos.js\";\nimport { createMetricsRegistry, normalizePathLabel } from \"./metrics.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\nexport interface ServerInstance {\n server: http.Server;\n journal: Journal;\n url: string;\n defaults: HandlerDefaults;\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 SEARCH_PATH = \"/search\";\nconst RERANK_PATH = \"/v2/rerank\";\nconst MODERATIONS_PATH = \"/v1/moderations\";\nconst DEFAULT_CHUNK_SIZE = 20;\n\nconst GEMINI_PATH_RE = /^\\/v1beta\\/models\\/([^:]+):(generateContent|streamGenerateContent)$/;\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_TAGS_PATH = \"/api/tags\";\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\": \"Content-Type, Authorization\",\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\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n const buffers: Buffer[] = [];\n for await (const chunk of req) buffers.push(chunk as Buffer);\n return Buffer.concat(buffers).toString();\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 * 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): Promise<boolean> {\n if (!pathname.startsWith(CONTROL_PREFIX)) return false;\n\n const subPath = pathname.slice(CONTROL_PREFIX.length);\n setCorsHeaders(res);\n\n // GET /__aimock/health\n if (subPath === \"/health\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n return true;\n }\n\n // GET /__aimock/journal\n if (subPath === \"/journal\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(journal.getAll()));\n return true;\n }\n\n // POST /__aimock/fixtures — add fixtures dynamically\n if (subPath === \"/fixtures\" && req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Failed to read request body\" }));\n return true;\n }\n\n let parsed: { fixtures?: FixtureFileEntry[] };\n try {\n parsed = JSON.parse(raw) as { fixtures?: FixtureFileEntry[] };\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON\" }));\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(entryToFixture);\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 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 res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ cleared: true }));\n return true;\n }\n\n // POST /__aimock/reset — clear fixtures + journal + match counts\n if (subPath === \"/reset\" && req.method === \"POST\") {\n fixtures.length = 0;\n journal.clear();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ reset: true }));\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 {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Failed to read request body\" }));\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 {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON\" }));\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 // Remove after first match\n const original = errorFixture.match.predicate!;\n errorFixture.match.predicate = (req) => {\n const result = original(req);\n if (result) {\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): 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 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 {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Malformed JSON\",\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const fixture = matchFixture(\n fixtures,\n body,\n journal.fixtureMatchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures);\n }\n\n const method = req.method ?? \"POST\";\n const path = req.url ?? COMPLETIONS_PATH;\n const flatHeaders = flattenHeaders(req.headers);\n\n // Apply chaos before normal response handling\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method,\n path,\n headers: flatHeaders,\n body,\n },\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n // Try record-and-replay proxy if configured\n if (defaults.record && providerKey) {\n const proxied = await proxyAndRecord(\n req,\n res,\n body,\n providerKey,\n req.url ?? COMPLETIONS_PATH,\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 },\n });\n return;\n }\n }\n\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n defaults.logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? COMPLETIONS_PATH}`,\n );\n }\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = fixture.response;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\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(res, status, JSON.stringify(response));\n return;\n }\n\n // Text response\n if (isTextResponse(response)) {\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(response.content, body.model, response.reasoning);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(completion));\n } else {\n const chunks = buildTextChunks(response.content, body.model, chunkSize, response.reasoning);\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 });\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 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(response.toolCalls, body.model);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(completion));\n } else {\n const chunks = buildToolCallChunks(response.toolCalls, body.model, chunkSize);\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 });\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 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 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 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 };\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 const journal = new Journal();\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 defaults.logger.warn(`Unhandled request error: ${msg}`);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: { message: msg, type: \"server_error\" } }));\n }\n });\n });\n\n async function handleHttpRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n // OPTIONS preflight\n if (req.method === \"OPTIONS\") {\n handleOptions(res);\n return;\n }\n\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\n // Instrument response completion for metrics\n if (registry) {\n const rawPathname = pathname;\n res.on(\"finish\", () => {\n try {\n const normalizedPath = normalizePathLabel(rawPathname);\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 // Control API — must be checked before mounts and path rewrites\n if (pathname.startsWith(CONTROL_PREFIX)) {\n await handleControlAPI(req, res, pathname, fixtures, journal);\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 // 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 // Groq/OpenAI-compatible alias: strip /openai prefix so that\n // /openai/v1/chat/completions → /v1/chat/completions, etc.\n if (!azureDeploymentId && pathname.startsWith(\"/openai/\")) {\n pathname = pathname.slice(7); // remove \"/openai\" prefix, keep the rest\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 journal.clear();\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 readBody(req)\n .then((raw) => 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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n return;\n }\n\n // POST /v1/messages — Anthropic Claude Messages API\n if (pathname === MESSAGES_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => 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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n return;\n }\n\n // POST /v2/chat — Cohere v2 Chat API\n if (pathname === COHERE_CHAT_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => 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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n return;\n }\n\n // POST /v1/embeddings — OpenAI Embeddings API\n if (pathname === EMBEDDINGS_PATH && req.method === \"POST\") {\n const deploymentId = azureDeploymentId;\n readBody(req)\n .then((raw) => {\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 return handleEmbeddings(\n req,\n res,\n JSON.stringify(parsed),\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n }\n } catch {\n // Fall through — let handleEmbeddings report the parse error\n }\n }\n return handleEmbeddings(req, res, raw, fixtures, journal, defaults, 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 readBody(req)\n .then((raw) =>\n handleGemini(\n req,\n res,\n raw,\n geminiModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\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 readBody(req)\n .then((raw) =>\n handleGemini(\n req,\n res,\n raw,\n vertexModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"vertexai\",\n ),\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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\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 readBody(req)\n .then((raw) =>\n handleBedrock(req, res, raw, bedrockModelId, fixtures, journal, defaults, 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 readBody(req)\n .then((raw) =>\n handleBedrockStream(\n req,\n res,\n raw,\n bedrockModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleConverse(\n req,\n res,\n raw,\n converseModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleConverseStream(\n req,\n res,\n raw,\n converseStreamModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 /api/chat — Ollama Chat API\n if (pathname === OLLAMA_CHAT_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => 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 // POST /api/generate — Ollama Generate API\n if (pathname === OLLAMA_GENERATE_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) =>\n handleOllamaGenerate(req, res, raw, fixtures, journal, defaults, 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 // GET /api/tags — Ollama Models listing\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 // POST /search — Web Search API (Tavily-compatible)\n if (pathname === SEARCH_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) =>\n handleSearch(\n req,\n res,\n raw,\n serviceFixtures?.search ?? [],\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleRerank(\n req,\n res,\n raw,\n serviceFixtures?.rerank ?? [],\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleModeration(\n req,\n res,\n raw,\n serviceFixtures?.moderation ?? [],\n journal,\n defaults,\n setCorsHeaders,\n ),\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/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 const completionsProvider: RecordProviderKey = azureDeploymentId ? \"azure\" : \"openai\";\n handleCompletions(\n req,\n res,\n fixtures,\n journal,\n defaults,\n azureDeploymentId,\n completionsProvider,\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({\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: ${JSON.stringify({ error: { message: msg, type: \"server_error\" } })}\\n\\n`,\n );\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n }\n\n // ─── WebSocket upgrade handling ──────────────────────────────────────────\n\n const activeConnections = new Set<WebSocketConnection>();\n\n server.on(\n \"upgrade\",\n (req: http.IncomingMessage, socket: import(\"node:net\").Socket, head: Buffer) => {\n handleUpgradeRequest(req, socket, head).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.warn(`Unhandled upgrade error: ${msg}`);\n if (!socket.destroyed) socket.destroy();\n });\n },\n );\n\n async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n const parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const pathname = parsedUrl.pathname;\n\n // Dispatch to mounted services\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 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 if (pathname === RESPONSES_PATH) {\n handleWebSocketResponses(ws, fixtures, journal, {\n ...defaults,\n model: \"gpt-4\",\n });\n } else if (pathname === REALTIME_PATH) {\n const model = parsedUrl.searchParams.get(\"model\") ?? \"gpt-4o-realtime\";\n handleWebSocketRealtime(ws, fixtures, journal, {\n ...defaults,\n model,\n });\n } else if (pathname === GEMINI_LIVE_PATH) {\n handleWebSocketGeminiLive(ws, fixtures, journal, {\n ...defaults,\n model: \"gemini-2.0-flash\",\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 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({ server, journal, url, defaults });\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":["entryToFixture","validateFixtures","flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","isErrorResponse","isContentWithToolCallsResponse","buildContentWithToolCallsCompletion","buildContentWithToolCallsChunks","createInterruptionSignal","writeSSEStream","isTextResponse","buildTextCompletion","buildTextChunks","isToolCallResponse","buildToolCallCompletion","buildToolCallChunks","Logger","createMetricsRegistry","Journal","http","normalizePathLabel","handleResponses","handleMessages","handleCohere","handleEmbeddings","handleGemini","handleBedrock","handleBedrockStream","handleConverse","handleConverseStream","handleOllama","handleOllamaGenerate","handleSearch","handleRerank","handleModeration","upgradeToWebSocket"],"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 { matchFixture } 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 isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n} from \"./helpers.js\";\nimport { handleResponses } from \"./responses.js\";\nimport { handleMessages } from \"./messages.js\";\nimport { handleGemini } from \"./gemini.js\";\nimport { handleBedrock, handleBedrockStream } from \"./bedrock.js\";\nimport { handleConverse, handleConverseStream } from \"./bedrock-converse.js\";\nimport { handleEmbeddings } from \"./embeddings.js\";\nimport { handleOllama, handleOllamaGenerate } from \"./ollama.js\";\nimport { handleCohere } 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 { applyChaos } from \"./chaos.js\";\nimport { createMetricsRegistry, normalizePathLabel } from \"./metrics.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\nexport interface ServerInstance {\n server: http.Server;\n journal: Journal;\n url: string;\n defaults: HandlerDefaults;\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 SEARCH_PATH = \"/search\";\nconst RERANK_PATH = \"/v2/rerank\";\nconst MODERATIONS_PATH = \"/v1/moderations\";\nconst DEFAULT_CHUNK_SIZE = 20;\n\nconst GEMINI_PATH_RE = /^\\/v1beta\\/models\\/([^:]+):(generateContent|streamGenerateContent)$/;\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_TAGS_PATH = \"/api/tags\";\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\": \"Content-Type, Authorization\",\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\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n const buffers: Buffer[] = [];\n for await (const chunk of req) buffers.push(chunk as Buffer);\n return Buffer.concat(buffers).toString();\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 * 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): Promise<boolean> {\n if (!pathname.startsWith(CONTROL_PREFIX)) return false;\n\n const subPath = pathname.slice(CONTROL_PREFIX.length);\n setCorsHeaders(res);\n\n // GET /__aimock/health\n if (subPath === \"/health\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\" }));\n return true;\n }\n\n // GET /__aimock/journal\n if (subPath === \"/journal\" && req.method === \"GET\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(journal.getAll()));\n return true;\n }\n\n // POST /__aimock/fixtures — add fixtures dynamically\n if (subPath === \"/fixtures\" && req.method === \"POST\") {\n let raw: string;\n try {\n raw = await readBody(req);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Failed to read request body\" }));\n return true;\n }\n\n let parsed: { fixtures?: FixtureFileEntry[] };\n try {\n parsed = JSON.parse(raw) as { fixtures?: FixtureFileEntry[] };\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON\" }));\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(entryToFixture);\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 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 res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ cleared: true }));\n return true;\n }\n\n // POST /__aimock/reset — clear fixtures + journal + match counts\n if (subPath === \"/reset\" && req.method === \"POST\") {\n fixtures.length = 0;\n journal.clear();\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ reset: true }));\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 {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Failed to read request body\" }));\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 {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON\" }));\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 // Remove after first match\n const original = errorFixture.match.predicate!;\n errorFixture.match.predicate = (req) => {\n const result = original(req);\n if (result) {\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): 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 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 {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Malformed JSON\",\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n body,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n const method = req.method ?? \"POST\";\n const path = req.url ?? COMPLETIONS_PATH;\n const flatHeaders = flattenHeaders(req.headers);\n\n // Apply chaos before normal response handling\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method,\n path,\n headers: flatHeaders,\n body,\n },\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n // Try record-and-replay proxy if configured\n if (defaults.record && providerKey) {\n const proxied = await proxyAndRecord(\n req,\n res,\n body,\n providerKey,\n req.url ?? COMPLETIONS_PATH,\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 },\n });\n return;\n }\n }\n\n const strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n if (defaults.strict) {\n defaults.logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? COMPLETIONS_PATH}`,\n );\n }\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? COMPLETIONS_PATH,\n headers: flattenHeaders(req.headers),\n body,\n response: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = fixture.response;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\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(res, status, JSON.stringify(response));\n return;\n }\n\n // Content + tool calls response\n if (isContentWithToolCallsResponse(response)) {\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 = buildContentWithToolCallsCompletion(\n response.content,\n response.toolCalls,\n body.model,\n );\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(completion));\n } else {\n const chunks = buildContentWithToolCallsChunks(\n response.content,\n response.toolCalls,\n body.model,\n chunkSize,\n );\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 });\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 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(response.content, body.model, response.reasoning);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(completion));\n } else {\n const chunks = buildTextChunks(response.content, body.model, chunkSize, response.reasoning);\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 });\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 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(response.toolCalls, body.model);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(completion));\n } else {\n const chunks = buildToolCallChunks(response.toolCalls, body.model, chunkSize);\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 });\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 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 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 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 };\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 const journal = new Journal();\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 defaults.logger.warn(`Unhandled request error: ${msg}`);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: { message: msg, type: \"server_error\" } }));\n }\n });\n });\n\n async function handleHttpRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n // OPTIONS preflight\n if (req.method === \"OPTIONS\") {\n handleOptions(res);\n return;\n }\n\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\n // Instrument response completion for metrics\n if (registry) {\n const rawPathname = pathname;\n res.on(\"finish\", () => {\n try {\n const normalizedPath = normalizePathLabel(rawPathname);\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 // Control API — must be checked before mounts and path rewrites\n if (pathname.startsWith(CONTROL_PREFIX)) {\n await handleControlAPI(req, res, pathname, fixtures, journal);\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 // 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 // Groq/OpenAI-compatible alias: strip /openai prefix so that\n // /openai/v1/chat/completions → /v1/chat/completions, etc.\n if (!azureDeploymentId && pathname.startsWith(\"/openai/\")) {\n pathname = pathname.slice(7); // remove \"/openai\" prefix, keep the rest\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 journal.clear();\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 readBody(req)\n .then((raw) => 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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n return;\n }\n\n // POST /v1/messages — Anthropic Claude Messages API\n if (pathname === MESSAGES_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => 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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n return;\n }\n\n // POST /v2/chat — Cohere v2 Chat API\n if (pathname === COHERE_CHAT_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => 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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n return;\n }\n\n // POST /v1/embeddings — OpenAI Embeddings API\n if (pathname === EMBEDDINGS_PATH && req.method === \"POST\") {\n const deploymentId = azureDeploymentId;\n readBody(req)\n .then((raw) => {\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 return handleEmbeddings(\n req,\n res,\n JSON.stringify(parsed),\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n );\n }\n } catch {\n // Fall through — let handleEmbeddings report the parse error\n }\n }\n return handleEmbeddings(req, res, raw, fixtures, journal, defaults, 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 readBody(req)\n .then((raw) =>\n handleGemini(\n req,\n res,\n raw,\n geminiModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\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 readBody(req)\n .then((raw) =>\n handleGemini(\n req,\n res,\n raw,\n vertexModel,\n streaming,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"vertexai\",\n ),\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 } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\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 readBody(req)\n .then((raw) =>\n handleBedrock(req, res, raw, bedrockModelId, fixtures, journal, defaults, 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 readBody(req)\n .then((raw) =>\n handleBedrockStream(\n req,\n res,\n raw,\n bedrockModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleConverse(\n req,\n res,\n raw,\n converseModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleConverseStream(\n req,\n res,\n raw,\n converseStreamModelId,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n ),\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 /api/chat — Ollama Chat API\n if (pathname === OLLAMA_CHAT_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => 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 // POST /api/generate — Ollama Generate API\n if (pathname === OLLAMA_GENERATE_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) =>\n handleOllamaGenerate(req, res, raw, fixtures, journal, defaults, 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 // GET /api/tags — Ollama Models listing\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 // POST /search — Web Search API (Tavily-compatible)\n if (pathname === SEARCH_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) =>\n handleSearch(\n req,\n res,\n raw,\n serviceFixtures?.search ?? [],\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleRerank(\n req,\n res,\n raw,\n serviceFixtures?.rerank ?? [],\n journal,\n defaults,\n setCorsHeaders,\n ),\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 readBody(req)\n .then((raw) =>\n handleModeration(\n req,\n res,\n raw,\n serviceFixtures?.moderation ?? [],\n journal,\n defaults,\n setCorsHeaders,\n ),\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/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 const completionsProvider: RecordProviderKey = azureDeploymentId ? \"azure\" : \"openai\";\n handleCompletions(\n req,\n res,\n fixtures,\n journal,\n defaults,\n azureDeploymentId,\n completionsProvider,\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({\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: ${JSON.stringify({ error: { message: msg, type: \"server_error\" } })}\\n\\n`,\n );\n } catch (writeErr) {\n logger.debug(\"Failed to write error recovery response:\", writeErr);\n }\n res.end();\n }\n });\n }\n\n // ─── WebSocket upgrade handling ──────────────────────────────────────────\n\n const activeConnections = new Set<WebSocketConnection>();\n\n server.on(\n \"upgrade\",\n (req: http.IncomingMessage, socket: import(\"node:net\").Socket, head: Buffer) => {\n handleUpgradeRequest(req, socket, head).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n defaults.logger.warn(`Unhandled upgrade error: ${msg}`);\n if (!socket.destroyed) socket.destroy();\n });\n },\n );\n\n async function handleUpgradeRequest(\n req: http.IncomingMessage,\n socket: import(\"node:net\").Socket,\n head: Buffer,\n ): Promise<void> {\n const parsedUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const pathname = parsedUrl.pathname;\n\n // Dispatch to mounted services\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 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 });\n } else if (pathname === REALTIME_PATH) {\n const model = parsedUrl.searchParams.get(\"model\") ?? \"gpt-4o-realtime\";\n handleWebSocketRealtime(ws, fixtures, journal, {\n ...defaults,\n model,\n testId: wsTestId,\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 });\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 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({ server, journal, url, defaults });\n });\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AACvB,MAAM,gBAAgB;AACtB,MAAM,mBACJ;AACF,MAAM,gBAAgB;AACtB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,cAAc;AACpB,MAAM,cAAc;AACpB,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAE3B,MAAM,iBAAiB;AACvB,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,mBAAmB;AAEzB,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,eAAe,SAAS,KAA4C;CAClE,MAAM,UAAoB,EAAE;AAC5B,YAAW,MAAM,SAAS,IAAK,SAAQ,KAAK,MAAgB;AAC5D,QAAO,OAAO,OAAO,QAAQ,CAAC,UAAU;;AAG1C,SAAS,cAAc,KAAgC;AACrD,gBAAe,IAAI;AACnB,KAAI,UAAU,IAAI;AAClB,KAAI,KAAK;;AAGX,SAAS,eAAe,KAA0B,SAAuB;AACvE,gBAAe,IAAI;AACnB,uCAAmB,KAAK,KAAK,KAAK,UAAU,EAAE,OAAO;EAAE;EAAS,MAAM;EAAa,EAAE,CAAC,CAAC;;AASzF,MAAM,iBAAiB;;;;;AAMvB,eAAe,iBACb,KACA,KACA,UACA,UACA,SACkB;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,QAAQ;EACpD,IAAI;AACJ,MAAI;AACF,SAAM,MAAM,SAAS,IAAI;UACnB;AACN,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,+BAA+B,CAAC,CAAC;AACjE,UAAO;;EAGT,IAAI;AACJ,MAAI;AACF,YAAS,KAAK,MAAM,IAAI;UAClB;AACN,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,gBAAgB,CAAC,CAAC;AAClD,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,IAAIA,sCAAe;EAErD,MAAM,SADSC,wCAAiB,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,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,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,SAAS,MAAM,CAAC,CAAC;AAC1C,SAAO;;AAIT,KAAI,YAAY,YAAY,IAAI,WAAW,QAAQ;AACjD,WAAS,SAAS;AAClB,UAAQ,OAAO;AACf,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,EAAE,OAAO,MAAM,CAAC,CAAC;AACxC,SAAO;;AAIT,KAAI,YAAY,YAAY,IAAI,WAAW,QAAQ;EACjD,IAAI;AACJ,MAAI;AACF,SAAM,MAAM,SAAS,IAAI;UACnB;AACN,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,+BAA+B,CAAC,CAAC;AACjE,UAAO;;EAGT,IAAI;AACJ,MAAI;AACF,YAAS,KAAK,MAAM,IAAI;UAClB;AACN,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAO,gBAAgB,CAAC,CAAC;AAClD,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;EAE9B,MAAM,WAAW,aAAa,MAAM;AACpC,eAAa,MAAM,aAAa,QAAQ;GACtC,MAAM,SAAS,SAAS,IAAI;AAC5B,OAAI,OACF,sBAAqB;IACnB,MAAM,MAAM,SAAS,QAAQ,aAAa;AAC1C,QAAI,QAAQ,GAAI,UAAS,OAAO,KAAK,EAAE;KACvC;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,aACe;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,SAASC,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS,6BAA6B;GACtC,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,IAAI;AACJ,KAAI;AACF,SAAO,KAAK,MAAM,IAAI;AAEtB,MAAI,iBAAiB,CAAC,KAAK,MACzB,MAAK,QAAQ;SAET;AACN,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,MAAM,SAASC,0BAAU,IAAI;CAC7B,MAAM,UAAUC,4BACd,UACA,MACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,iBACV;AAED,KAAI,QACF,SAAQ,2BAA2B,SAAS,UAAU,OAAO;CAG/D,MAAM,SAAS,IAAI,UAAU;CAC7B,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,cAAcF,+BAAe,IAAI,QAAQ;AAG/C,KACEG,yBACE,KACA,SACA,SAAS,OACT,IAAI,SACJ,SACA;EACE;EACA;EACA,SAAS;EACT;EACD,EACD,SAAS,UACT,SAAS,OACV,CAED;AAEF,KAAI,CAAC,SAAS;AAEZ,MAAI,SAAS,UAAU,aAWrB;OAVgB,MAAMC,gCACpB,KACA,KACA,MACA,aACA,IAAI,OAAO,kBACX,UACA,UACA,IACD,EACY;AACX,YAAQ,IAAI;KACV,QAAQ,IAAI,UAAU;KACtB,MAAM,IAAI,OAAO;KACjB,SAASJ,+BAAe,IAAI,QAAQ;KACpC;KACA,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM;KAC3D,CAAC;AACF;;;EAIJ,MAAM,eAAe,SAAS,SAAS,MAAM;EAC7C,MAAM,gBAAgB,SAAS,SAC3B,oCACA;AACJ,MAAI,SAAS,OACX,UAAS,OAAO,MACd,kCAAkC,IAAI,UAAU,OAAO,GAAG,IAAI,OAAO,mBACtE;AAGH,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAASA,+BAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAc,SAAS;IAAM;GAClD,CAAC;AACF,wCACE,KACA,cACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAGF,MAAM,WAAW,QAAQ;CACzB,MAAM,UAAU,QAAQ,WAAW,SAAS;CAC5C,MAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,aAAa,SAAS,UAAU;AAGtE,KAAIK,gCAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAASL,+BAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,wCAAmB,KAAK,QAAQ,KAAK,UAAU,SAAS,CAAC;AACzD;;AAIF,KAAIM,+CAA+B,SAAS,EAAE;EAC5C,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAASN,+BAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,KAAK,WAAW,MAAM;GACxB,MAAM,aAAaO,oDACjB,SAAS,SACT,SAAS,WACT,KAAK,MACN;AACD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,WAAW,CAAC;SAC9B;GACL,MAAM,SAASC,gDACb,SAAS,SACT,SAAS,WACT,KAAK,OACL,UACD;GACD,MAAM,eAAeC,8CAAyB,QAAQ;AAOtD,OAAI,CANc,MAAMC,kCAAe,KAAK,QAAQ;IAClD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAIC,+BAAe,SAAS,EAAE;EAC5B,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAASX,+BAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,KAAK,WAAW,MAAM;GACxB,MAAM,aAAaY,oCAAoB,SAAS,SAAS,KAAK,OAAO,SAAS,UAAU;AACxF,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,WAAW,CAAC;SAC9B;GACL,MAAM,SAASC,gCAAgB,SAAS,SAAS,KAAK,OAAO,WAAW,SAAS,UAAU;GAC3F,MAAM,eAAeJ,8CAAyB,QAAQ;AAOtD,OAAI,CANc,MAAMC,kCAAe,KAAK,QAAQ;IAClD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,CAAC,EACc;AACd,QAAI,CAAC,IAAI,cAAe,KAAI,SAAS;AACrC,iBAAa,SAAS,cAAc;AACpC,iBAAa,SAAS,kBAAkB,cAAc,QAAQ;;AAEhE,iBAAc,SAAS;;AAEzB;;AAIF,KAAII,mCAAmB,SAAS,EAAE;EAChC,MAAM,eAAe,QAAQ,IAAI;GAC/B,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI,OAAO;GACjB,SAASd,+BAAe,IAAI,QAAQ;GACpC;GACA,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,KAAK,WAAW,MAAM;GACxB,MAAM,aAAae,wCAAwB,SAAS,WAAW,KAAK,MAAM;AAC1E,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,WAAW,CAAC;SAC9B;GACL,MAAM,SAASC,oCAAoB,SAAS,WAAW,KAAK,OAAO,UAAU;GAC7E,MAAM,eAAeP,8CAAyB,QAAQ;AAOtD,OAAI,CANc,MAAMC,kCAAe,KAAK,QAAQ;IAClD;IACA,kBAAkB,QAAQ;IAC1B,QAAQ,cAAc;IACtB,aAAa,cAAc;IAC5B,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,SAASV,+BAAe,IAAI,QAAQ;EACpC;EACA,UAAU;GAAE,QAAQ;GAAK;GAAS;EACnC,CAAC;AACF,uCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;EACL,SAAS;EACT,MAAM;EACP,EACF,CAAC,CACH;;AAYH,eAAsB,aACpB,UACA,SACA,QACA,iBACyB;CACzB,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,IAAIiB,sBAAO,SAAS,YAAY,SAAS;CACxD,MAAM,WAAW,SAAS,UAAUC,uCAAuB,GAAG;CAC9D,MAAM,gBAAgB,WAAW,EAAE;CACnC,MAAM,WAAW;EACf,SAAS,cAAc,WAAW;EAClC,WAAW,KAAK,IAAI,GAAG,cAAc,aAAa,mBAAmB;EACrE;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;;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;;CAK/F,MAAM,UAAU,IAAIC,yBAAS;AAG7B,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,SAASC,UAAK,cAAc,KAA2B,QAA6B;AAExF,oBAAkB,KAAK,IAAI,CAAC,OAAO,QAAiB;GAClD,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,YAAS,OAAO,KAAK,4BAA4B,MAAM;AACvD,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;;IAE5E;GACF;CAEF,eAAe,kBACb,KACA,KACe;AAEf,MAAI,IAAI,WAAW,WAAW;AAC5B,iBAAc,IAAI;AAClB;;EAIF,MAAM,YAAY,WAAW,QAAQ,OAAO,QAAQ,GAAG;EAGvD,MAAM,YAAY,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,QAAQ,cAAc;EACtF,IAAI,WAAW,UAAU;AAGzB,MAAI,UAAU;GACZ,MAAM,cAAc;AACpB,OAAI,GAAG,gBAAgB;AACrB,QAAI;KACF,MAAM,iBAAiBC,mCAAmB,YAAY;KACtD,MAAM,SAAS,IAAI,UAAU;KAC7B,MAAM,SAAS,OAAO,IAAI,WAAW;AACrC,cAAS,iBAAiB,yBAAyB;MACjD;MACA,MAAM;MACN;MACD,CAAC;KACF,MAAM,UAAU,OAAO,QAAQ,OAAO,QAAQ,GAAG,UAAU,GAAG;AAC9D,cAAS,iBACP,mCACA;MAAE;MAAQ,MAAM;MAAgB,EAChC,QACD;aACM,KAAK;AACZ,cAAS,OAAO,KAAK,iCAAiC,IAAI;;KAE5D;;AAIJ,MAAI,SAAS,WAAW,eAAe,EAAE;AACvC,SAAM,iBAAiB,KAAK,KAAK,UAAU,UAAU,QAAQ;AAC7D;;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;;;EAOnB,IAAI;EACJ,MAAM,aAAa,SAAS,MAAM,oBAAoB;AACtD,MAAI,cAAc,IAAI,WAAW,QAAQ;AACvC,uBAAoB,WAAW;AAE/B,cAAW,OADO,WAAW;;AAM/B,MAAI,CAAC,qBAAqB,SAAS,WAAW,WAAW,CACvD,YAAW,SAAS,MAAM,EAAE;AAI9B,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,4CACE,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;AAC3B,YAAQ,OAAO;AACf,QAAI,UAAU,IAAI;AAClB,QAAI,KAAK;AACT;;AAEF,kBAAe,KAAK,YAAY;AAChC;;AAIF,MAAI,aAAa,kBAAkB,IAAI,WAAW,QAAQ;AACxD,YAAS,IAAI,CACV,MAAM,QAAQC,kCAAgB,KAAK,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe,CAAC,CAC1F,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,eAAe;AAC7B,SAAI;AACF,UAAI,MAAM,uBAAuB,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;cAC5E,UAAU;AACjB,aAAO,MAAM,4CAA4C,SAAS;;AAEpE,SAAI,KAAK;;KAEX;AACJ;;AAIF,MAAI,aAAa,iBAAiB,IAAI,WAAW,QAAQ;AACvD,YAAS,IAAI,CACV,MAAM,QAAQC,gCAAe,KAAK,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe,CAAC,CACzF,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,eAAe;AAC7B,SAAI;AACF,UAAI,MAAM,uBAAuB,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;cAC5E,UAAU;AACjB,aAAO,MAAM,4CAA4C,SAAS;;AAEpE,SAAI,KAAK;;KAEX;AACJ;;AAIF,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,YAAS,IAAI,CACV,MAAM,QAAQC,4BAAa,KAAK,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe,CAAC,CACvF,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,eAAe;AAC7B,SAAI;AACF,UAAI,MAAM,uBAAuB,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;cAC5E,UAAU;AACjB,aAAO,MAAM,4CAA4C,SAAS;;AAEpE,SAAI,KAAK;;KAEX;AACJ;;AAIF,MAAI,aAAa,mBAAmB,IAAI,WAAW,QAAQ;GACzD,MAAM,eAAe;AACrB,YAAS,IAAI,CACV,MAAM,QAAQ;AAEb,QAAI,aACF,KAAI;KACF,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAI,CAAC,OAAO,OAAO;AACjB,aAAO,QAAQ;AACf,aAAOC,oCACL,KACA,KACA,KAAK,UAAU,OAAO,EACtB,UACA,SACA,UACA,eACD;;YAEG;AAIV,WAAOA,oCAAiB,KAAK,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe;KACnF,CACD,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;EAIF,MAAM,cAAc,SAAS,MAAM,eAAe;AAClD,MAAI,eAAe,IAAI,WAAW,QAAQ;GACxC,MAAM,cAAc,YAAY;GAChC,MAAM,YAAY,YAAY,OAAO;AACrC,YAAS,IAAI,CACV,MAAM,QACLC,4BACE,KACA,KACA,KACA,aACA,WACA,UACA,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,eAAe;AAC7B,SAAI;AACF,UAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;cAC9D,UAAU;AACjB,aAAO,MAAM,4CAA4C,SAAS;;AAEpE,SAAI,KAAK;;KAEX;AACJ;;EAIF,MAAM,cAAc,SAAS,MAAM,aAAa;AAChD,MAAI,eAAe,IAAI,WAAW,QAAQ;GACxC,MAAM,cAAc,YAAY;GAChC,MAAM,YAAY,YAAY,OAAO;AACrC,YAAS,IAAI,CACV,MAAM,QACLA,4BACE,KACA,KACA,KACA,aACA,WACA,UACA,SACA,UACA,gBACA,WACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,eAAe;AAC7B,SAAI;AACF,UAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,MAAM;cAC9D,UAAU;AACjB,aAAO,MAAM,4CAA4C,SAAS;;AAEpE,SAAI,KAAK;;KAEX;AACJ;;EAIF,MAAM,eAAe,SAAS,MAAM,kBAAkB;AACtD,MAAI,gBAAgB,IAAI,WAAW,QAAQ;GACzC,MAAM,iBAAiB,aAAa;AACpC,YAAS,IAAI,CACV,MAAM,QACLC,8BAAc,KAAK,KAAK,KAAK,gBAAgB,UAAU,SAAS,UAAU,eAAe,CAC1F,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;EAIF,MAAM,qBAAqB,SAAS,MAAM,kBAAkB;AAC5D,MAAI,sBAAsB,IAAI,WAAW,QAAQ;GAC/C,MAAM,iBAAiB,mBAAmB;AAC1C,YAAS,IAAI,CACV,MAAM,QACLC,oCACE,KACA,KACA,KACA,gBACA,UACA,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;EAIF,MAAM,gBAAgB,SAAS,MAAM,oBAAoB;AACzD,MAAI,iBAAiB,IAAI,WAAW,QAAQ;GAC1C,MAAM,kBAAkB,cAAc;AACtC,YAAS,IAAI,CACV,MAAM,QACLC,wCACE,KACA,KACA,KACA,iBACA,UACA,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;EAIF,MAAM,sBAAsB,SAAS,MAAM,2BAA2B;AACtE,MAAI,uBAAuB,IAAI,WAAW,QAAQ;GAChD,MAAM,wBAAwB,oBAAoB;AAClD,YAAS,IAAI,CACV,MAAM,QACLC,8CACE,KACA,KACA,KACA,uBACA,UACA,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;AAIF,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,YAAS,IAAI,CACV,MAAM,QAAQC,4BAAa,KAAK,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe,CAAC,CACvF,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;AAIF,MAAI,aAAa,wBAAwB,IAAI,WAAW,QAAQ;AAC9D,YAAS,IAAI,CACV,MAAM,QACLC,oCAAqB,KAAK,KAAK,KAAK,UAAU,SAAS,UAAU,eAAe,CACjF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;AAIF,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;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,YAAS,IAAI,CACV,MAAM,QACLC,4BACE,KACA,KACA,KACA,iBAAiB,UAAU,EAAE,EAC7B,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;AAIF,MAAI,aAAa,eAAe,IAAI,WAAW,QAAQ;AACrD,YAAS,IAAI,CACV,MAAM,QACLC,4BACE,KACA,KACA,KACA,iBAAiB,UAAU,EAAE,EAC7B,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;AAIF,MAAI,aAAa,oBAAoB,IAAI,WAAW,QAAQ;AAC1D,YAAS,IAAI,CACV,MAAM,QACLC,oCACE,KACA,KACA,KACA,iBAAiB,cAAc,EAAE,EACjC,SACA,UACA,eACD,CACF,CACA,OAAO,QAAiB;IACvB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,QAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;KAAE,SAAS;KAAK,MAAM;KAAgB,EAAE,CAAC,CAClE;aACQ,CAAC,IAAI,cACd,KAAI,SAAS;KAEf;AACJ;;AAIF,MAAI,aAAa,kBAAkB;AACjC,kBAAe,KAAK,YAAY;AAChC;;AAEF,MAAI,IAAI,WAAW,QAAQ;AACzB,kBAAe,KAAK,YAAY;AAChC;;AAIF,oBACE,KACA,KACA,UACA,SACA,UACA,mBAP6C,oBAAoB,UAAU,SAS5E,CAAC,OAAO,QAAiB;GACxB,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU;AACjD,OAAI,CAAC,IAAI,YACP,uCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACP,EACF,CAAC,CACH;YACQ,CAAC,IAAI,eAAe;AAE7B,QAAI;AACF,SAAI,MACF,SAAS,KAAK,UAAU,EAAE,OAAO;MAAE,SAAS;MAAK,MAAM;MAAgB,EAAE,CAAC,CAAC,MAC5E;aACM,UAAU;AACjB,YAAO,MAAM,4CAA4C,SAAS;;AAEpE,QAAI,KAAK;;IAEX;;CAKJ,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;CAED,eAAe,qBACb,KACA,QACA,MACe;EACf,MAAM,YAAY,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,QAAQ,cAAc;EACtF,MAAM,WAAW,UAAU;AAG3B,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;;;AAK9D,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,QAAKC,sCAAmB,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,WAAWnC,0BAAU,IAAI;AAC/B,MAAI,aAAa,eACf,+CAAyB,IAAI,UAAU,SAAS;GAC9C,GAAG;GACH,OAAO;GACP,QAAQ;GACT,CAAC;WACO,aAAa,eAAe;GACrC,MAAM,QAAQ,UAAU,aAAa,IAAI,QAAQ,IAAI;AACrD,+CAAwB,IAAI,UAAU,SAAS;IAC7C,GAAG;IACH;IACA,QAAQ;IACT,CAAC;aACO,aAAa,iBACtB,kDAA0B,IAAI,UAAU,SAAS;GAC/C,GAAG;GACH,OAAO;GACP,QAAQ;GACT,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,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;IAAE;IAAQ;IAAS;IAAK;IAAU,CAAC;IAC3C;GACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.cts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;UA6CiB,cAAA;UACP,IAAA,CAAK;EADE,OAAA,EAEN,OAFM;EAAc,GAAA,EAAA,MAAA;UAChB,EAGH,eAHG;;AAGH,UAseK,eAAA,CAteL;EAAe,MAAA,EAuejB,aAveiB,EAAA;EAseV,MAAA,EAEP,aAFsB,EAAA;EAAA,UAAA,EAGlB,iBAHkB,EAAA;;AAEtB,iBAOY,YAAA,CAPZ,QAAA,EAQE,OARF,EAAA,EAAA,OAAA,CAAA,EASE,iBATF,EAAA,MAOV,CAPU,EAUC,KAVD,CAAA;MACI,EAAA,MAAA;EAAiB,OAAA,EASW,SATX;AAM/B,CAAA,CAAA,EAAsB,eAAY,CAAA,EAId,eAJc,CAAA,EAK/B,OAL+B,CAKvB,cALuB,CAAA"}
1
+ {"version":3,"file":"server.d.cts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAiDiB,cAAA;UACP,IAAA,CAAK;EADE,OAAA,EAEN,OAFM;EAAc,GAAA,EAAA,MAAA;UAChB,EAGH,eAHG;;AAGH,UAghBK,eAAA,CAhhBL;EAAe,MAAA,EAihBjB,aAjhBiB,EAAA;EAghBV,MAAA,EAEP,aAFsB,EAAA;EAAA,UAAA,EAGlB,iBAHkB,EAAA;;AAEtB,iBAOY,YAAA,CAPZ,QAAA,EAQE,OARF,EAAA,EAAA,OAAA,CAAA,EASE,iBATF,EAAA,MAOV,CAPU,EAUC,KAVD,CAAA;MACI,EAAA,MAAA;EAAiB,OAAA,EASW,SATX;AAM/B,CAAA,CAAA,EAAsB,eAAY,CAAA,EAId,eAJc,CAAA,EAK/B,OAL+B,CAKvB,cALuB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;UA6CiB,cAAA;UACP,IAAA,CAAK;EADE,OAAA,EAEN,OAFM;EAAc,GAAA,EAAA,MAAA;UAChB,EAGH,eAHG;;AAGH,UAseK,eAAA,CAteL;EAAe,MAAA,EAuejB,aAveiB,EAAA;EAseV,MAAA,EAEP,aAFsB,EAAA;EAAA,UAAA,EAGlB,iBAHkB,EAAA;;AAEtB,iBAOY,YAAA,CAPZ,QAAA,EAQE,OARF,EAAA,EAAA,OAAA,CAAA,EASE,iBATF,EAAA,MAOV,CAPU,EAUC,KAVD,CAAA;MACI,EAAA,MAAA;EAAiB,OAAA,EASW,SATX;AAM/B,CAAA,CAAA,EAAsB,eAAY,CAAA,EAId,eAJc,CAAA,EAK/B,OAL+B,CAKvB,cALuB,CAAA"}
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAiDiB,cAAA;UACP,IAAA,CAAK;EADE,OAAA,EAEN,OAFM;EAAc,GAAA,EAAA,MAAA;UAChB,EAGH,eAHG;;AAGH,UAghBK,eAAA,CAhhBL;EAAe,MAAA,EAihBjB,aAjhBiB,EAAA;EAghBV,MAAA,EAEP,aAFsB,EAAA;EAAA,UAAA,EAGlB,iBAHkB,EAAA;;AAEtB,iBAOY,YAAA,CAPZ,QAAA,EAQE,OARF,EAAA,EAAA,OAAA,CAAA,EASE,iBATF,EAAA,MAOV,CAPU,EAUC,KAVD,CAAA;MACI,EAAA,MAAA;EAAiB,OAAA,EASW,SATX;AAM/B,CAAA,CAAA,EAAsB,eAAY,CAAA,EAId,eAJc,CAAA,EAK/B,OAL+B,CAKvB,cALuB,CAAA"}
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import { buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, flattenHeaders, isErrorResponse, isTextResponse, isToolCallResponse } from "./helpers.js";
1
+ import { buildContentWithToolCallsChunks, buildContentWithToolCallsCompletion, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, flattenHeaders, getTestId, isContentWithToolCallsResponse, isErrorResponse, isTextResponse, isToolCallResponse } from "./helpers.js";
2
2
  import { Journal } from "./journal.js";
3
3
  import { matchFixture } from "./router.js";
4
4
  import { entryToFixture, validateFixtures } from "./fixture-loader.js";
@@ -244,8 +244,9 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
244
244
  } }));
245
245
  return;
246
246
  }
247
- const fixture = matchFixture(fixtures, body, journal.fixtureMatchCounts, defaults.requestTransform);
248
- if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures);
247
+ const testId = getTestId(req);
248
+ const fixture = matchFixture(fixtures, body, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
249
+ if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
249
250
  const method = req.method ?? "POST";
250
251
  const path = req.url ?? COMPLETIONS_PATH;
251
252
  const flatHeaders = flattenHeaders(req.headers);
@@ -309,6 +310,38 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
309
310
  writeErrorResponse(res, status, JSON.stringify(response));
310
311
  return;
311
312
  }
313
+ if (isContentWithToolCallsResponse(response)) {
314
+ const journalEntry = journal.add({
315
+ method: req.method ?? "POST",
316
+ path: req.url ?? COMPLETIONS_PATH,
317
+ headers: flattenHeaders(req.headers),
318
+ body,
319
+ response: {
320
+ status: 200,
321
+ fixture
322
+ }
323
+ });
324
+ if (body.stream !== true) {
325
+ const completion = buildContentWithToolCallsCompletion(response.content, response.toolCalls, body.model);
326
+ res.writeHead(200, { "Content-Type": "application/json" });
327
+ res.end(JSON.stringify(completion));
328
+ } else {
329
+ const chunks = buildContentWithToolCallsChunks(response.content, response.toolCalls, body.model, chunkSize);
330
+ const interruption = createInterruptionSignal(fixture);
331
+ if (!await writeSSEStream(res, chunks, {
332
+ latency,
333
+ streamingProfile: fixture.streamingProfile,
334
+ signal: interruption?.signal,
335
+ onChunkSent: interruption?.tick
336
+ })) {
337
+ if (!res.writableEnded) res.destroy();
338
+ journalEntry.response.interrupted = true;
339
+ journalEntry.response.interruptReason = interruption?.reason();
340
+ }
341
+ interruption?.cleanup();
342
+ }
343
+ return;
344
+ }
312
345
  if (isTextResponse(response)) {
313
346
  const journalEntry = journal.add({
314
347
  method: req.method ?? "POST",
@@ -887,19 +920,23 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
887
920
  ws.on("close", () => {
888
921
  activeConnections.delete(ws);
889
922
  });
923
+ const wsTestId = getTestId(req);
890
924
  if (pathname === RESPONSES_PATH) handleWebSocketResponses(ws, fixtures, journal, {
891
925
  ...defaults,
892
- model: "gpt-4"
926
+ model: "gpt-4",
927
+ testId: wsTestId
893
928
  });
894
929
  else if (pathname === REALTIME_PATH) {
895
930
  const model = parsedUrl.searchParams.get("model") ?? "gpt-4o-realtime";
896
931
  handleWebSocketRealtime(ws, fixtures, journal, {
897
932
  ...defaults,
898
- model
933
+ model,
934
+ testId: wsTestId
899
935
  });
900
936
  } else if (pathname === GEMINI_LIVE_PATH) handleWebSocketGeminiLive(ws, fixtures, journal, {
901
937
  ...defaults,
902
- model: "gemini-2.0-flash"
938
+ model: "gemini-2.0-flash",
939
+ testId: wsTestId
903
940
  });
904
941
  }
905
942
  const originalClose = server.close.bind(server);