@copilotkit/aimock 1.11.0 → 1.12.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 (117) hide show
  1. package/README.md +4 -2
  2. package/dist/a2a-types.d.cts.map +1 -1
  3. package/dist/a2a-types.d.ts.map +1 -1
  4. package/dist/agui-types.d.cts.map +1 -1
  5. package/dist/bedrock-converse.cjs +2 -0
  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 +2 -0
  10. package/dist/bedrock-converse.js.map +1 -1
  11. package/dist/bedrock.cjs +2 -0
  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 +2 -0
  16. package/dist/bedrock.js.map +1 -1
  17. package/dist/cohere.cjs +1 -0
  18. package/dist/cohere.cjs.map +1 -1
  19. package/dist/cohere.js +1 -0
  20. package/dist/cohere.js.map +1 -1
  21. package/dist/embeddings.cjs +2 -1
  22. package/dist/embeddings.cjs.map +1 -1
  23. package/dist/embeddings.js +2 -1
  24. package/dist/embeddings.js.map +1 -1
  25. package/dist/gemini.cjs +1 -0
  26. package/dist/gemini.cjs.map +1 -1
  27. package/dist/gemini.js +1 -0
  28. package/dist/gemini.js.map +1 -1
  29. package/dist/helpers.cjs +16 -0
  30. package/dist/helpers.cjs.map +1 -1
  31. package/dist/helpers.d.cts +6 -2
  32. package/dist/helpers.d.cts.map +1 -1
  33. package/dist/helpers.d.ts +6 -2
  34. package/dist/helpers.d.ts.map +1 -1
  35. package/dist/helpers.js +13 -1
  36. package/dist/helpers.js.map +1 -1
  37. package/dist/images.cjs +166 -0
  38. package/dist/images.cjs.map +1 -0
  39. package/dist/images.d.cts +11 -0
  40. package/dist/images.d.cts.map +1 -0
  41. package/dist/images.d.ts +11 -0
  42. package/dist/images.d.ts.map +1 -0
  43. package/dist/images.js +166 -0
  44. package/dist/images.js.map +1 -0
  45. package/dist/index.cjs +13 -0
  46. package/dist/index.d.cts +7 -3
  47. package/dist/index.d.ts +7 -3
  48. package/dist/index.js +6 -2
  49. package/dist/llmock.cjs +37 -1
  50. package/dist/llmock.cjs.map +1 -1
  51. package/dist/llmock.d.cts +5 -1
  52. package/dist/llmock.d.cts.map +1 -1
  53. package/dist/llmock.d.ts +5 -1
  54. package/dist/llmock.d.ts.map +1 -1
  55. package/dist/llmock.js +37 -1
  56. package/dist/llmock.js.map +1 -1
  57. package/dist/messages.cjs +1 -0
  58. package/dist/messages.cjs.map +1 -1
  59. package/dist/messages.js +1 -0
  60. package/dist/messages.js.map +1 -1
  61. package/dist/ollama.cjs +2 -0
  62. package/dist/ollama.cjs.map +1 -1
  63. package/dist/ollama.d.cts.map +1 -1
  64. package/dist/ollama.d.ts.map +1 -1
  65. package/dist/ollama.js +2 -0
  66. package/dist/ollama.js.map +1 -1
  67. package/dist/recorder.cjs +50 -7
  68. package/dist/recorder.cjs.map +1 -1
  69. package/dist/recorder.js +50 -7
  70. package/dist/recorder.js.map +1 -1
  71. package/dist/responses.cjs +1 -0
  72. package/dist/responses.cjs.map +1 -1
  73. package/dist/responses.js +1 -0
  74. package/dist/responses.js.map +1 -1
  75. package/dist/router.cjs +8 -0
  76. package/dist/router.cjs.map +1 -1
  77. package/dist/router.d.cts.map +1 -1
  78. package/dist/router.d.ts.map +1 -1
  79. package/dist/router.js +9 -0
  80. package/dist/router.js.map +1 -1
  81. package/dist/server.cjs +80 -3
  82. package/dist/server.cjs.map +1 -1
  83. package/dist/server.d.cts +2 -0
  84. package/dist/server.d.cts.map +1 -1
  85. package/dist/server.d.ts +2 -0
  86. package/dist/server.d.ts.map +1 -1
  87. package/dist/server.js +80 -3
  88. package/dist/server.js.map +1 -1
  89. package/dist/speech.cjs +144 -0
  90. package/dist/speech.cjs.map +1 -0
  91. package/dist/speech.d.cts +11 -0
  92. package/dist/speech.d.cts.map +1 -0
  93. package/dist/speech.d.ts +11 -0
  94. package/dist/speech.d.ts.map +1 -0
  95. package/dist/speech.js +144 -0
  96. package/dist/speech.js.map +1 -0
  97. package/dist/transcription.cjs +134 -0
  98. package/dist/transcription.cjs.map +1 -0
  99. package/dist/transcription.d.cts +11 -0
  100. package/dist/transcription.d.cts.map +1 -0
  101. package/dist/transcription.d.ts +11 -0
  102. package/dist/transcription.d.ts.map +1 -0
  103. package/dist/transcription.js +134 -0
  104. package/dist/transcription.js.map +1 -0
  105. package/dist/types.d.cts +44 -2
  106. package/dist/types.d.cts.map +1 -1
  107. package/dist/types.d.ts +44 -2
  108. package/dist/types.d.ts.map +1 -1
  109. package/dist/video.cjs +196 -0
  110. package/dist/video.cjs.map +1 -0
  111. package/dist/video.d.cts +14 -0
  112. package/dist/video.d.cts.map +1 -0
  113. package/dist/video.d.ts +14 -0
  114. package/dist/video.d.ts.map +1 -0
  115. package/dist/video.js +195 -0
  116. package/dist/video.js.map +1 -0
  117. package/package.json +2 -2
package/dist/server.js CHANGED
@@ -12,6 +12,10 @@ import { handleGemini } from "./gemini.js";
12
12
  import { handleBedrock, handleBedrockStream } from "./bedrock.js";
13
13
  import { handleConverse, handleConverseStream } from "./bedrock-converse.js";
14
14
  import { handleEmbeddings } from "./embeddings.js";
15
+ import { handleImages } from "./images.js";
16
+ import { handleSpeech } from "./speech.js";
17
+ import { handleTranscription } from "./transcription.js";
18
+ import { handleVideoCreate, handleVideoStatus } from "./video.js";
15
19
  import { handleOllama, handleOllamaGenerate } from "./ollama.js";
16
20
  import { handleCohere } from "./cohere.js";
17
21
  import { handleSearch } from "./search.js";
@@ -36,6 +40,12 @@ const COHERE_CHAT_PATH = "/v2/chat";
36
40
  const SEARCH_PATH = "/search";
37
41
  const RERANK_PATH = "/v2/rerank";
38
42
  const MODERATIONS_PATH = "/v1/moderations";
43
+ const IMAGES_PATH = "/v1/images/generations";
44
+ const SPEECH_PATH = "/v1/audio/speech";
45
+ const TRANSCRIPTIONS_PATH = "/v1/audio/transcriptions";
46
+ const VIDEOS_PATH = "/v1/videos";
47
+ const VIDEOS_STATUS_RE = /^\/v1\/videos\/([^/]+)$/;
48
+ const GEMINI_PREDICT_RE = /^\/v1beta\/models\/([^:]+):predict$/;
39
49
  const DEFAULT_CHUNK_SIZE = 20;
40
50
  const GEMINI_PATH_RE = /^\/v1beta\/models\/([^:]+):(generateContent|streamGenerateContent)$/;
41
51
  const AZURE_DEPLOYMENT_RE = /^\/openai\/deployments\/([^/]+)\/(chat\/completions|embeddings)$/;
@@ -88,7 +98,7 @@ const CONTROL_PREFIX = "/__aimock";
88
98
  * Handle requests under `/__aimock/`. Returns `true` if the request was
89
99
  * handled, `false` if the path doesn't match the control prefix.
90
100
  */
91
- async function handleControlAPI(req, res, pathname, fixtures, journal) {
101
+ async function handleControlAPI(req, res, pathname, fixtures, journal, videoStates) {
92
102
  if (!pathname.startsWith(CONTROL_PREFIX)) return false;
93
103
  const subPath = pathname.slice(9);
94
104
  setCorsHeaders(res);
@@ -148,6 +158,7 @@ async function handleControlAPI(req, res, pathname, fixtures, journal) {
148
158
  if (subPath === "/reset" && req.method === "POST") {
149
159
  fixtures.length = 0;
150
160
  journal.clear();
161
+ videoStates.clear();
151
162
  res.writeHead(200, { "Content-Type": "application/json" });
152
163
  res.end(JSON.stringify({ reset: true }));
153
164
  return true;
@@ -244,6 +255,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
244
255
  } }));
245
256
  return;
246
257
  }
258
+ body._endpointType = "chat";
247
259
  const testId = getTestId(req);
248
260
  const fixture = matchFixture(fixtures, body, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
249
261
  if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
@@ -463,6 +475,7 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
463
475
  for (const { name, value } of chaosRates) if (value !== void 0 && (value < 0 || value > 1)) logger.warn(`Chaos ${name} (${value}) is outside 0-1 range — will be clamped at runtime`);
464
476
  }
465
477
  const journal = new Journal();
478
+ const videoStates = /* @__PURE__ */ new Map();
466
479
  if (mounts) for (const { handler } of mounts) {
467
480
  if (handler.setJournal) handler.setJournal(journal);
468
481
  if (registry && handler.setRegistry) handler.setRegistry(registry);
@@ -512,7 +525,7 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
512
525
  });
513
526
  }
514
527
  if (pathname.startsWith(CONTROL_PREFIX)) {
515
- await handleControlAPI(req, res, pathname, fixtures, journal);
528
+ await handleControlAPI(req, res, pathname, fixtures, journal, videoStates);
516
529
  return;
517
530
  }
518
531
  if (mounts) {
@@ -688,6 +701,69 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
688
701
  });
689
702
  return;
690
703
  }
704
+ if (pathname === IMAGES_PATH && req.method === "POST") {
705
+ readBody(req).then((raw) => handleImages(req, res, raw, fixtures, journal, defaults, setCorsHeaders)).catch((err) => {
706
+ const msg = err instanceof Error ? err.message : "Internal error";
707
+ if (!res.headersSent) writeErrorResponse(res, 500, JSON.stringify({ error: {
708
+ message: msg,
709
+ type: "server_error"
710
+ } }));
711
+ else if (!res.writableEnded) res.destroy();
712
+ });
713
+ return;
714
+ }
715
+ if (pathname === SPEECH_PATH && req.method === "POST") {
716
+ readBody(req).then((raw) => handleSpeech(req, res, raw, fixtures, journal, defaults, setCorsHeaders)).catch((err) => {
717
+ const msg = err instanceof Error ? err.message : "Internal error";
718
+ if (!res.headersSent) writeErrorResponse(res, 500, JSON.stringify({ error: {
719
+ message: msg,
720
+ type: "server_error"
721
+ } }));
722
+ else if (!res.writableEnded) res.destroy();
723
+ });
724
+ return;
725
+ }
726
+ if (pathname === TRANSCRIPTIONS_PATH && req.method === "POST") {
727
+ readBody(req).then((raw) => handleTranscription(req, res, raw, fixtures, journal, defaults, setCorsHeaders)).catch((err) => {
728
+ const msg = err instanceof Error ? err.message : "Internal error";
729
+ if (!res.headersSent) writeErrorResponse(res, 500, JSON.stringify({ error: {
730
+ message: msg,
731
+ type: "server_error"
732
+ } }));
733
+ else if (!res.writableEnded) res.destroy();
734
+ });
735
+ return;
736
+ }
737
+ if (pathname === VIDEOS_PATH && req.method === "POST") {
738
+ readBody(req).then((raw) => handleVideoCreate(req, res, raw, fixtures, journal, defaults, setCorsHeaders, videoStates)).catch((err) => {
739
+ const msg = err instanceof Error ? err.message : "Internal error";
740
+ if (!res.headersSent) writeErrorResponse(res, 500, JSON.stringify({ error: {
741
+ message: msg,
742
+ type: "server_error"
743
+ } }));
744
+ else if (!res.writableEnded) res.destroy();
745
+ });
746
+ return;
747
+ }
748
+ const videoStatusMatch = pathname.match(VIDEOS_STATUS_RE);
749
+ if (videoStatusMatch && req.method === "GET") {
750
+ const videoId = videoStatusMatch[1];
751
+ handleVideoStatus(req, res, videoId, journal, setCorsHeaders, videoStates);
752
+ return;
753
+ }
754
+ const geminiPredictMatch = pathname.match(GEMINI_PREDICT_RE);
755
+ if (geminiPredictMatch && req.method === "POST") {
756
+ const predictModel = geminiPredictMatch[1];
757
+ readBody(req).then((raw) => handleImages(req, res, raw, fixtures, journal, defaults, setCorsHeaders, "gemini", predictModel)).catch((err) => {
758
+ const msg = err instanceof Error ? err.message : "Internal error";
759
+ if (!res.headersSent) writeErrorResponse(res, 500, JSON.stringify({ error: {
760
+ message: msg,
761
+ type: "server_error"
762
+ } }));
763
+ else if (!res.writableEnded) res.destroy();
764
+ });
765
+ return;
766
+ }
691
767
  const geminiMatch = pathname.match(GEMINI_PATH_RE);
692
768
  if (geminiMatch && req.method === "POST") {
693
769
  const geminiModel = geminiMatch[1];
@@ -962,7 +1038,8 @@ async function createServer(fixtures, options, mounts, serviceFixtures) {
962
1038
  server,
963
1039
  journal,
964
1040
  url,
965
- defaults
1041
+ defaults,
1042
+ videoStates
966
1043
  });
967
1044
  });
968
1045
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"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":"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"}
1
+ {"version":3,"file":"server.js","names":[],"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 { handleImages } from \"./images.js\";\nimport { handleSpeech } from \"./speech.js\";\nimport { handleTranscription } from \"./transcription.js\";\nimport { handleVideoCreate, handleVideoStatus, type VideoStateMap } from \"./video.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 videoStates: VideoStateMap;\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 IMAGES_PATH = \"/v1/images/generations\";\nconst SPEECH_PATH = \"/v1/audio/speech\";\nconst TRANSCRIPTIONS_PATH = \"/v1/audio/transcriptions\";\nconst VIDEOS_PATH = \"/v1/videos\";\nconst VIDEOS_STATUS_RE = /^\\/v1\\/videos\\/([^/]+)$/;\nconst GEMINI_PREDICT_RE = /^\\/v1beta\\/models\\/([^:]+):predict$/;\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 videoStates: VideoStateMap,\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 videoStates.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 body._endpointType = \"chat\";\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 const videoStates: VideoStateMap = new Map();\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, videoStates);\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 /v1/images/generations — OpenAI Image Generation API\n if (pathname === IMAGES_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => handleImages(req, res, raw, fixtures, journal, defaults, setCorsHeaders))\n .catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\n });\n return;\n }\n\n // POST /v1/audio/speech — OpenAI TTS API\n if (pathname === SPEECH_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) => handleSpeech(req, res, raw, fixtures, journal, defaults, setCorsHeaders))\n .catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n if (!res.headersSent) {\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({ error: { message: msg, type: \"server_error\" } }),\n );\n } else if (!res.writableEnded) {\n res.destroy();\n }\n });\n return;\n }\n\n // POST /v1/audio/transcriptions — OpenAI Transcription API\n if (pathname === TRANSCRIPTIONS_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) =>\n handleTranscription(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 /v1/videos — Video Generation API\n if (pathname === VIDEOS_PATH && req.method === \"POST\") {\n readBody(req)\n .then((raw) =>\n handleVideoCreate(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n videoStates,\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 // GET /v1/videos/{id} — Video Status Check\n const videoStatusMatch = pathname.match(VIDEOS_STATUS_RE);\n if (videoStatusMatch && req.method === \"GET\") {\n const videoId = videoStatusMatch[1];\n handleVideoStatus(req, res, videoId, journal, setCorsHeaders, videoStates);\n return;\n }\n\n // POST /v1beta/models/{model}:predict — Gemini Imagen API\n const geminiPredictMatch = pathname.match(GEMINI_PREDICT_RE);\n if (geminiPredictMatch && req.method === \"POST\") {\n const predictModel = geminiPredictMatch[1];\n readBody(req)\n .then((raw) =>\n handleImages(\n req,\n res,\n raw,\n fixtures,\n journal,\n defaults,\n setCorsHeaders,\n \"gemini\",\n predictModel,\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 /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, videoStates });\n });\n });\n}\n"],"mappings":"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"}