@copilotkit/aimock 1.42.0 → 1.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +56 -0
- package/README.md +102 -16
- package/dist/agui-mock.cjs +1 -1
- package/dist/agui-mock.cjs.map +1 -1
- package/dist/agui-mock.d.cts.map +1 -1
- package/dist/agui-mock.d.ts.map +1 -1
- package/dist/agui-mock.js +1 -1
- package/dist/agui-mock.js.map +1 -1
- package/dist/agui-recorder.cjs +33 -11
- package/dist/agui-recorder.cjs.map +1 -1
- package/dist/agui-recorder.d.cts +10 -1
- package/dist/agui-recorder.d.cts.map +1 -1
- package/dist/agui-recorder.d.ts +10 -1
- package/dist/agui-recorder.d.ts.map +1 -1
- package/dist/agui-recorder.js +33 -11
- package/dist/agui-recorder.js.map +1 -1
- package/dist/agui-types.d.cts +1 -0
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts +1 -0
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +38 -10
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.d.cts +5 -0
- package/dist/aimock-cli.d.cts.map +1 -1
- package/dist/aimock-cli.d.ts +5 -0
- package/dist/aimock-cli.d.ts.map +1 -1
- package/dist/aimock-cli.js +38 -10
- package/dist/aimock-cli.js.map +1 -1
- package/dist/batches.cjs +458 -0
- package/dist/batches.cjs.map +1 -0
- package/dist/batches.d.cts +57 -0
- package/dist/batches.d.cts.map +1 -0
- package/dist/batches.d.ts +57 -0
- package/dist/batches.d.ts.map +1 -0
- package/dist/batches.js +453 -0
- package/dist/batches.js.map +1 -0
- package/dist/bedrock-converse.cjs +12 -8
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +14 -10
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +10 -8
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +12 -10
- package/dist/bedrock.js.map +1 -1
- package/dist/byteplus-video.cjs +3 -3
- package/dist/byteplus-video.cjs.map +1 -1
- package/dist/byteplus-video.js +4 -4
- package/dist/byteplus-video.js.map +1 -1
- package/dist/chaos.cjs +622 -72
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts +164 -7
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts +164 -7
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +613 -74
- package/dist/chaos.js.map +1 -1
- package/dist/cli.cjs +42 -23
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +42 -23
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +10 -8
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +12 -10
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/convert.cjs +1 -1
- package/dist/convert.cjs.map +1 -1
- package/dist/convert.js +1 -1
- package/dist/convert.js.map +1 -1
- package/dist/elevenlabs-audio.cjs +3 -3
- package/dist/elevenlabs-audio.cjs.map +1 -1
- package/dist/elevenlabs-audio.js +4 -4
- package/dist/elevenlabs-audio.js.map +1 -1
- package/dist/elevenlabs-voice.cjs +1053 -0
- package/dist/elevenlabs-voice.cjs.map +1 -0
- package/dist/elevenlabs-voice.d.cts +72 -0
- package/dist/elevenlabs-voice.d.cts.map +1 -0
- package/dist/elevenlabs-voice.d.ts +72 -0
- package/dist/elevenlabs-voice.d.ts.map +1 -0
- package/dist/elevenlabs-voice.js +1048 -0
- package/dist/elevenlabs-voice.js.map +1 -0
- package/dist/embeddings.cjs +8 -4
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +9 -5
- package/dist/embeddings.js.map +1 -1
- package/dist/fal-audio.cjs +3 -3
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.js +4 -4
- package/dist/fal-audio.js.map +1 -1
- package/dist/fal.cjs +28 -4
- package/dist/fal.cjs.map +1 -1
- package/dist/fal.d.cts +16 -1
- package/dist/fal.d.cts.map +1 -1
- package/dist/fal.d.ts +16 -1
- package/dist/fal.d.ts.map +1 -1
- package/dist/fal.js +28 -5
- package/dist/fal.js.map +1 -1
- package/dist/files.cjs +1071 -0
- package/dist/files.cjs.map +1 -0
- package/dist/files.d.cts +68 -0
- package/dist/files.d.cts.map +1 -0
- package/dist/files.d.ts +68 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +1059 -0
- package/dist/files.js.map +1 -0
- package/dist/fine-tuning.cjs +1051 -0
- package/dist/fine-tuning.cjs.map +1 -0
- package/dist/fine-tuning.d.cts +96 -0
- package/dist/fine-tuning.d.cts.map +1 -0
- package/dist/fine-tuning.d.ts +96 -0
- package/dist/fine-tuning.d.ts.map +1 -0
- package/dist/fine-tuning.js +1044 -0
- package/dist/fine-tuning.js.map +1 -0
- package/dist/fixture-loader.cjs +0 -0
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +37 -5
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +37 -5
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +0 -0
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-embeddings.cjs +2 -2
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +3 -3
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +13 -7
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +15 -9
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +11 -7
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +13 -9
- package/dist/gemini.js.map +1 -1
- package/dist/grok-video.cjs +14 -14
- package/dist/grok-video.cjs.map +1 -1
- package/dist/grok-video.js +15 -15
- package/dist/grok-video.js.map +1 -1
- package/dist/helpers.cjs +229 -7
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +38 -2
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +38 -2
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +221 -8
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +54 -123
- package/dist/images.cjs.map +1 -1
- package/dist/images.d.cts.map +1 -1
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js +55 -124
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +41 -8
- package/dist/index.d.cts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +14 -10
- package/dist/jest.cjs +14 -7
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +3 -2
- package/dist/jest.d.cts.map +1 -1
- package/dist/jest.d.ts +3 -2
- package/dist/jest.d.ts.map +1 -1
- package/dist/jest.js +14 -7
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +41 -4
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +44 -3
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +44 -3
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +41 -5
- package/dist/journal.js.map +1 -1
- package/dist/live-fixture.cjs +1192 -0
- package/dist/live-fixture.cjs.map +1 -0
- package/dist/live-fixture.js +1187 -0
- package/dist/live-fixture.js.map +1 -0
- package/dist/live-recorder.cjs +256 -0
- package/dist/live-recorder.cjs.map +1 -0
- package/dist/live-recorder.js +254 -0
- package/dist/live-recorder.js.map +1 -0
- package/dist/live-replay.cjs +286 -0
- package/dist/live-replay.cjs.map +1 -0
- package/dist/live-replay.js +285 -0
- package/dist/live-replay.js.map +1 -0
- package/dist/live-sanitize.cjs +196 -0
- package/dist/live-sanitize.cjs.map +1 -0
- package/dist/live-sanitize.js +196 -0
- package/dist/live-sanitize.js.map +1 -0
- package/dist/live-types.d.cts +71 -0
- package/dist/live-types.d.cts.map +1 -0
- package/dist/live-types.d.ts +71 -0
- package/dist/live-types.d.ts.map +1 -0
- package/dist/llmock.cjs +52 -41
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +16 -5
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +16 -5
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +53 -42
- package/dist/llmock.js.map +1 -1
- package/dist/messages.cjs +11 -7
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +13 -9
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +258 -5
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts +3 -1
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts +3 -1
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +255 -6
- package/dist/metrics.js.map +1 -1
- package/dist/moderation.cjs +10 -1
- package/dist/moderation.cjs.map +1 -1
- package/dist/moderation.d.cts.map +1 -1
- package/dist/moderation.d.ts.map +1 -1
- package/dist/moderation.js +10 -1
- package/dist/moderation.js.map +1 -1
- package/dist/ollama.cjs +5 -5
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.js +6 -6
- package/dist/ollama.js.map +1 -1
- package/dist/openrouter-video.cjs +5 -5
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.js +6 -6
- package/dist/openrouter-video.js.map +1 -1
- package/dist/recorder.cjs +45 -9
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +43 -11
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +4 -3
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.js +5 -5
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +20 -33
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +4 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts +4 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +20 -34
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +701 -625
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -0
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +704 -628
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +2 -2
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +3 -3
- package/dist/speech.js.map +1 -1
- package/dist/transcription.cjs +4 -4
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.js +5 -5
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +119 -16
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +119 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-cli.cjs +925 -0
- package/dist/validate-cli.cjs.map +1 -0
- package/dist/validate-cli.js +924 -0
- package/dist/validate-cli.js.map +1 -0
- package/dist/vector-types.d.cts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/veo-video.cjs +13 -13
- package/dist/veo-video.cjs.map +1 -1
- package/dist/veo-video.js +14 -14
- package/dist/veo-video.js.map +1 -1
- package/dist/video.cjs +4 -4
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +5 -5
- package/dist/video.js.map +1 -1
- package/dist/vitest.cjs +13 -6
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +2 -1
- package/dist/vitest.d.cts.map +1 -1
- package/dist/vitest.d.ts +2 -1
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +14 -7
- package/dist/vitest.js.map +1 -1
- package/dist/watcher.cjs +2 -1
- package/dist/watcher.cjs.map +1 -1
- package/dist/watcher.js +2 -1
- package/dist/watcher.js.map +1 -1
- package/dist/ws-framing.cjs +150 -35
- package/dist/ws-framing.cjs.map +1 -1
- package/dist/ws-framing.d.cts +18 -3
- package/dist/ws-framing.d.cts.map +1 -1
- package/dist/ws-framing.d.ts +18 -3
- package/dist/ws-framing.d.ts.map +1 -1
- package/dist/ws-framing.js +151 -36
- package/dist/ws-framing.js.map +1 -1
- package/dist/ws-gemini-live.cjs +2 -2
- package/dist/ws-gemini-live.d.ts +2 -2
- package/dist/ws-gemini-live.js +2 -2
- package/dist/ws-live.cjs +401 -0
- package/dist/ws-live.cjs.map +1 -0
- package/dist/ws-live.js +400 -0
- package/dist/ws-live.js.map +1 -0
- package/dist/ws-realtime.cjs +46 -2
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts +2 -2
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +46 -2
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +2 -2
- package/dist/ws-responses.js +2 -2
- package/dist/ws-upstream.cjs +118 -0
- package/dist/ws-upstream.cjs.map +1 -0
- package/dist/ws-upstream.js +115 -0
- package/dist/ws-upstream.js.map +1 -0
- package/fixtures/openai-live-client.json +390 -0
- package/fixtures/openai-live-managed.json +709 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elevenlabs-audio.cjs","names":["flattenHeaders","isJsonObject","getContext","getTestId","matchFixtureDiagnostic","applyChaos","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isAudioResponse","FORMAT_TO_CONTENT_TYPE","isTextResponse"],"sources":["../src/elevenlabs-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isAudioResponse,\n isTextResponse,\n isErrorResponse,\n isJsonObject,\n serializeErrorResponse,\n flattenHeaders,\n FORMAT_TO_CONTENT_TYPE,\n getContext,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\n\nexport async function handleElevenLabsTTS(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n voiceId: string,\n): Promise<void> {\n const path = req.url ?? `/v1/text-to-speech/${voiceId}`;\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract text from request body\n const promptText = typeof parsed.text === \"string\" && parsed.text ? parsed.text : undefined;\n\n // Build synthetic ChatCompletionRequest for fixture matching\n const syntheticReq: ChatCompletionRequest = {\n model: (parsed.model_id as string) ?? \"eleven_multilingual_v2\",\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"elevenlabs-tts\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Missing required parameter: 'text'\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? `/v1/text-to-speech/${voiceId}`,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Expect audio response\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Standard binary response\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n\nexport async function handleElevenLabsAudio(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n subType: string, // \"sound-generation\" | \"music\" | \"stream\" | \"plan\"\n): Promise<void> {\n const path = req.url ?? \"/v1/sound-generation\";\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract prompt text based on subType\n let promptText: string | undefined;\n if (subType === \"sound-generation\") {\n if (typeof parsed.text === \"string\" && parsed.text) {\n promptText = parsed.text;\n }\n } else {\n // music, music-stream, music-plan all use \"prompt\" (or composition_plan fallback)\n if (typeof parsed.prompt === \"string\" && parsed.prompt) {\n promptText = parsed.prompt;\n } else if (parsed.composition_plan != null) {\n promptText =\n typeof parsed.composition_plan === \"string\"\n ? parsed.composition_plan\n : JSON.stringify(parsed.composition_plan);\n }\n }\n\n // Build synthetic ChatCompletionRequest for fixture matching (needed for journal even on validation failure)\n const syntheticReq: ChatCompletionRequest = {\n model:\n (parsed.model_id as string) ??\n (subType === \"sound-generation\" ? \"eleven_text_to_sound_v2\" : \"music_v1\"),\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"audio-gen\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n const field = subType === \"sound-generation\" ? \"text\" : \"prompt\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Missing required parameter: '${field}'`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? \"/v1/sound-generation\",\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // plan returns JSON text, not audio\n if (subType === \"plan\") {\n if (!isTextResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a text type for plan endpoint\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(response.content);\n return;\n }\n\n // All other subTypes expect audio\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Music endpoints get a song-id header\n if (subType === \"music\" || subType === \"stream\") {\n res.setHeader(\"song-id\", \"mock-song-\" + Date.now());\n }\n\n // Stream uses chunked transfer encoding\n if (subType === \"stream\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Transfer-Encoding\": \"chunked\",\n });\n res.end(audioBytes);\n return;\n }\n\n // Standard binary response for sound-generation and music\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n"],"mappings":";;;;;;;AAwBA,eAAsB,oBACpB,KACA,KACA,MACA,UACA,UACA,SACA,SACe;CACf,MAAM,OAAO,IAAI,OAAO,sBAAsB;CAC9C,MAAM,SAAS,IAAI,UAAU;CAG7B,IAAI;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,KAAK;UAClB,UAAU;EACjB,MAAM,SAAS,oBAAoB,QAAQ,SAAS,UAAU;AAC9D,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS,mBAAmB;GAC5B,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;AAMF,KAAI,CAACC,6BAAa,OAAO,EAAE;AACzB,UAAQ,IAAI;GACV;GACA;GACA,SAASD,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,MAAM,aAAa,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,OAAO,OAAO;CAGlF,MAAM,eAAsC;EAC1C,OAAQ,OAAO,YAAuB;EACtC,UAAU,CAAC;GAAE,MAAM;GAAQ,SAAS,cAAc;GAAI,CAAC;EACvD,eAAe;EACf,UAAUE,2BAAW,IAAI;EAC1B;AAGD,KAAI,CAAC,YAAY;AACf,UAAQ,IAAI;GACV;GACA;GACA,SAASF,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,MAAM,SAASG,0BAAU,IAAI;CAE7B,MAAM,EAAE,SAAS,4BAA4BC,sCAC3C,UACA,cAHkB,QAAQ,6BAA6B,OAAO,EAK9D,SAAS,iBACV;AAED,KAAI,QACF,SAAQ,2BAA2B,SAAS,UAAU,OAAO;AAG/D,KACEC,yBACE,KACA,SACA,SAAS,OACT,IAAI,SACJ,IAAI,KACJ,SACA;EAAE;EAAQ;EAAM,SAASL,+BAAe,IAAI,QAAQ;EAAE,MAAM;EAAc,EAC1E,UAAU,YAAY,SACtB,SAAS,UACT,SAAS,OACV,CAED;AAGF,KAAI,CAAC,SAAS;AAEZ,MADwBM,kCAAkB,SAAS,QAAQ,IAAI,QAAQ,EAClD;GACnB,MAAM,gBAAgBC,qCAAqB,wBAAwB;AACnE,YAAS,OAAO,MAAMC,qCAAqB,QAAQ,MAAM,wBAAwB,CAAC;AAClF,WAAQ,IAAI;IACV;IACA;IACA,SAASR,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KACR,QAAQ;KACR,SAAS;KACT,GAAGS,oCAAoB,SAAS,QAAQ,IAAI,QAAQ;KACrD;IACF,CAAC;AACF,yCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACN,MAAM;IACP,EACF,CAAC,CACH;AACD;;AAEF,MAAI,SAAS,QAAQ;GACnB,MAAM,UAAU,MAAMC,gCACpB,KACA,KACA,cACA,cACA,IAAI,OAAO,sBAAsB,WACjC,UACA,UACA,KACD;AACD,OAAI,YAAY,kBAAmB;AACnC,OAAI,YAAY,kBAAkB;AAChC,YAAQ,IAAI;KACV;KACA;KACA,SAASV,+BAAe,IAAI,QAAQ;KACpC,MAAM;KACN,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM,QAAQ;MAAS;KAC5E,CAAC;AACF;;;AAIJ,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IACR,QAAQ;IACR,SAAS;IACT,GAAGS,oCAAoB,SAAS,QAAQ,IAAI,QAAQ;IACrD;GACF,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAGF,MAAM,WAAW,MAAME,gCAAgB,SAAS,aAAa;AAG7D,KAAIC,gCAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV;GACA;GACA,SAASZ,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,wCAAmB,KAAK,QAAQa,uCAAuB,SAAS,EAAE,EAChE,YAAY,SAAS,YACtB,CAAC;AACF;;AAIF,KAAI,CAACC,gCAAgB,SAAS,EAAE;AAC9B,UAAQ,IAAI;GACV;GACA;GACA,SAASd,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GAAE,SAAS;GAAyC,MAAM;GAAgB,EAClF,CAAC,CACH;AACD;;CAIF,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO,SAAS,UAAU,UAAU;AACtC,eAAa,OAAO,KAAK,SAAS,OAAO,SAAS;AAElD,gBAAce,uCADC,SAAS,UAAU,UACc;QAC3C;AACL,eAAa,OAAO,KAAK,SAAS,MAAM,SAAS,SAAS;AAC1D,gBAAc,SAAS,MAAM,eAAe;;AAI9C,SAAQ,IAAI;EACV;EACA;EACA,SAASf,+BAAe,IAAI,QAAQ;EACpC,MAAM;EACN,UAAU;GAAE,QAAQ;GAAK;GAAS;EACnC,CAAC;AACF,KAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,CAAC;AACnD,KAAI,IAAI,WAAW;;AAGrB,eAAsB,sBACpB,KACA,KACA,MACA,UACA,UACA,SACA,SACe;CACf,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,SAAS,IAAI,UAAU;CAG7B,IAAI;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,KAAK;UAClB,UAAU;EACjB,MAAM,SAAS,oBAAoB,QAAQ,SAAS,UAAU;AAC9D,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS,mBAAmB;GAC5B,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;AAMF,KAAI,CAACC,6BAAa,OAAO,EAAE;AACzB,UAAQ,IAAI;GACV;GACA;GACA,SAASD,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,IAAI;AACJ,KAAI,YAAY,oBACd;MAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAC5C,cAAa,OAAO;YAIlB,OAAO,OAAO,WAAW,YAAY,OAAO,OAC9C,cAAa,OAAO;UACX,OAAO,oBAAoB,KACpC,cACE,OAAO,OAAO,qBAAqB,WAC/B,OAAO,mBACP,KAAK,UAAU,OAAO,iBAAiB;CAKjD,MAAM,eAAsC;EAC1C,OACG,OAAO,aACP,YAAY,qBAAqB,4BAA4B;EAChE,UAAU,CAAC;GAAE,MAAM;GAAQ,SAAS,cAAc;GAAI,CAAC;EACvD,eAAe;EACf,UAAUE,2BAAW,IAAI;EAC1B;AAGD,KAAI,CAAC,YAAY;EACf,MAAM,QAAQ,YAAY,qBAAqB,SAAS;AACxD,UAAQ,IAAI;GACV;GACA;GACA,SAASF,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS,gCAAgC,MAAM;GAC/C,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAIF,MAAM,SAASG,0BAAU,IAAI;CAE7B,MAAM,EAAE,SAAS,4BAA4BC,sCAC3C,UACA,cAHkB,QAAQ,6BAA6B,OAAO,EAK9D,SAAS,iBACV;AAED,KAAI,QACF,SAAQ,2BAA2B,SAAS,UAAU,OAAO;AAG/D,KACEC,yBACE,KACA,SACA,SAAS,OACT,IAAI,SACJ,IAAI,KACJ,SACA;EAAE;EAAQ;EAAM,SAASL,+BAAe,IAAI,QAAQ;EAAE,MAAM;EAAc,EAC1E,UAAU,YAAY,SACtB,SAAS,UACT,SAAS,OACV,CAED;AAGF,KAAI,CAAC,SAAS;AAEZ,MADwBM,kCAAkB,SAAS,QAAQ,IAAI,QAAQ,EAClD;GACnB,MAAM,gBAAgBC,qCAAqB,wBAAwB;AACnE,YAAS,OAAO,MAAMC,qCAAqB,QAAQ,MAAM,wBAAwB,CAAC;AAClF,WAAQ,IAAI;IACV;IACA;IACA,SAASR,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KACR,QAAQ;KACR,SAAS;KACT,GAAGS,oCAAoB,SAAS,QAAQ,IAAI,QAAQ;KACrD;IACF,CAAC;AACF,yCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACN,MAAM;IACP,EACF,CAAC,CACH;AACD;;AAEF,MAAI,SAAS,QAAQ;GACnB,MAAM,UAAU,MAAMC,gCACpB,KACA,KACA,cACA,cACA,IAAI,OAAO,wBACX,UACA,UACA,KACD;AACD,OAAI,YAAY,kBAAmB;AACnC,OAAI,YAAY,kBAAkB;AAChC,YAAQ,IAAI;KACV;KACA;KACA,SAASV,+BAAe,IAAI,QAAQ;KACpC,MAAM;KACN,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM,QAAQ;MAAS;KAC5E,CAAC;AACF;;;AAIJ,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IACR,QAAQ;IACR,SAAS;IACT,GAAGS,oCAAoB,SAAS,QAAQ,IAAI,QAAQ;IACrD;GACF,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAGF,MAAM,WAAW,MAAME,gCAAgB,SAAS,aAAa;AAG7D,KAAIC,gCAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV;GACA;GACA,SAASZ,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,wCAAmB,KAAK,QAAQa,uCAAuB,SAAS,EAAE,EAChE,YAAY,SAAS,YACtB,CAAC;AACF;;AAIF,KAAI,YAAY,QAAQ;AACtB,MAAI,CAACG,+BAAe,SAAS,EAAE;AAC7B,WAAQ,IAAI;IACV;IACA;IACA,SAAShB,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KAAE,QAAQ;KAAK;KAAS;IACnC,CAAC;AACF,yCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACP,EACF,CAAC,CACH;AACD;;AAEF,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,SAAS,QAAQ;AACzB;;AAIF,KAAI,CAACc,gCAAgB,SAAS,EAAE;AAC9B,UAAQ,IAAI;GACV;GACA;GACA,SAASd,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GAAE,SAAS;GAAyC,MAAM;GAAgB,EAClF,CAAC,CACH;AACD;;CAIF,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO,SAAS,UAAU,UAAU;AACtC,eAAa,OAAO,KAAK,SAAS,OAAO,SAAS;AAElD,gBAAce,uCADC,SAAS,UAAU,UACc;QAC3C;AACL,eAAa,OAAO,KAAK,SAAS,MAAM,SAAS,SAAS;AAC1D,gBAAc,SAAS,MAAM,eAAe;;AAI9C,KAAI,YAAY,WAAW,YAAY,SACrC,KAAI,UAAU,WAAW,eAAe,KAAK,KAAK,CAAC;AAIrD,KAAI,YAAY,UAAU;AACxB,UAAQ,IAAI;GACV;GACA;GACA,SAASf,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,MAAI,UAAU,KAAK;GACjB,gBAAgB;GAChB,qBAAqB;GACtB,CAAC;AACF,MAAI,IAAI,WAAW;AACnB;;AAIF,SAAQ,IAAI;EACV;EACA;EACA,SAASA,+BAAe,IAAI,QAAQ;EACpC,MAAM;EACN,UAAU;GAAE,QAAQ;GAAK;GAAS;EACnC,CAAC;AACF,KAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,CAAC;AACnD,KAAI,IAAI,WAAW"}
|
|
1
|
+
{"version":3,"file":"elevenlabs-audio.cjs","names":["flattenHeaders","isJsonObject","getContext","getTestId","matchFixtureDiagnostic","applyChaosAsync","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isAudioResponse","FORMAT_TO_CONTENT_TYPE","isTextResponse"],"sources":["../src/elevenlabs-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isAudioResponse,\n isTextResponse,\n isErrorResponse,\n isJsonObject,\n serializeErrorResponse,\n flattenHeaders,\n FORMAT_TO_CONTENT_TYPE,\n getContext,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\n\nexport async function handleElevenLabsTTS(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n voiceId: string,\n): Promise<void> {\n const path = req.url ?? `/v1/text-to-speech/${voiceId}`;\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract text from request body\n const promptText = typeof parsed.text === \"string\" && parsed.text ? parsed.text : undefined;\n\n // Build synthetic ChatCompletionRequest for fixture matching\n const syntheticReq: ChatCompletionRequest = {\n model: (parsed.model_id as string) ?? \"eleven_multilingual_v2\",\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"elevenlabs-tts\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Missing required parameter: 'text'\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? `/v1/text-to-speech/${voiceId}`,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Expect audio response\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Standard binary response\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n\nexport async function handleElevenLabsAudio(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n subType: string, // \"sound-generation\" | \"music\" | \"stream\" | \"plan\"\n): Promise<void> {\n const path = req.url ?? \"/v1/sound-generation\";\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract prompt text based on subType\n let promptText: string | undefined;\n if (subType === \"sound-generation\") {\n if (typeof parsed.text === \"string\" && parsed.text) {\n promptText = parsed.text;\n }\n } else {\n // music, music-stream, music-plan all use \"prompt\" (or composition_plan fallback)\n if (typeof parsed.prompt === \"string\" && parsed.prompt) {\n promptText = parsed.prompt;\n } else if (parsed.composition_plan != null) {\n promptText =\n typeof parsed.composition_plan === \"string\"\n ? parsed.composition_plan\n : JSON.stringify(parsed.composition_plan);\n }\n }\n\n // Build synthetic ChatCompletionRequest for fixture matching (needed for journal even on validation failure)\n const syntheticReq: ChatCompletionRequest = {\n model:\n (parsed.model_id as string) ??\n (subType === \"sound-generation\" ? \"eleven_text_to_sound_v2\" : \"music_v1\"),\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"audio-gen\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n const field = subType === \"sound-generation\" ? \"text\" : \"prompt\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Missing required parameter: '${field}'`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? \"/v1/sound-generation\",\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // plan returns JSON text, not audio\n if (subType === \"plan\") {\n if (!isTextResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a text type for plan endpoint\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(response.content);\n return;\n }\n\n // All other subTypes expect audio\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Music endpoints get a song-id header\n if (subType === \"music\" || subType === \"stream\") {\n res.setHeader(\"song-id\", \"mock-song-\" + Date.now());\n }\n\n // Stream uses chunked transfer encoding\n if (subType === \"stream\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Transfer-Encoding\": \"chunked\",\n });\n res.end(audioBytes);\n return;\n }\n\n // Standard binary response for sound-generation and music\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n"],"mappings":"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"}
|
package/dist/elevenlabs-audio.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FORMAT_TO_CONTENT_TYPE, flattenHeaders, getContext, getTestId, isAudioResponse, isErrorResponse, isJsonObject, isTextResponse, resolveResponse, resolveStrictMode, serializeErrorResponse, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
|
|
2
|
-
import { matchFixtureDiagnostic } from "./router.js";
|
|
3
2
|
import { writeErrorResponse } from "./sse-writer.js";
|
|
4
|
-
import {
|
|
3
|
+
import { applyChaosAsync } from "./chaos.js";
|
|
4
|
+
import { matchFixtureDiagnostic } from "./router.js";
|
|
5
5
|
import { proxyAndRecord } from "./recorder.js";
|
|
6
6
|
|
|
7
7
|
//#region src/elevenlabs-audio.ts
|
|
@@ -77,7 +77,7 @@ async function handleElevenLabsTTS(req, res, body, fixtures, defaults, journal,
|
|
|
77
77
|
const testId = getTestId(req);
|
|
78
78
|
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
79
79
|
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
80
|
-
if (
|
|
80
|
+
if (await applyChaosAsync(res, fixture, defaults.chaos, req.headers, req.url, journal, {
|
|
81
81
|
method,
|
|
82
82
|
path,
|
|
83
83
|
headers: flattenHeaders(req.headers),
|
|
@@ -273,7 +273,7 @@ async function handleElevenLabsAudio(req, res, body, fixtures, defaults, journal
|
|
|
273
273
|
const testId = getTestId(req);
|
|
274
274
|
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
275
275
|
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
276
|
-
if (
|
|
276
|
+
if (await applyChaosAsync(res, fixture, defaults.chaos, req.headers, req.url, journal, {
|
|
277
277
|
method,
|
|
278
278
|
path,
|
|
279
279
|
headers: flattenHeaders(req.headers),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elevenlabs-audio.js","names":[],"sources":["../src/elevenlabs-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isAudioResponse,\n isTextResponse,\n isErrorResponse,\n isJsonObject,\n serializeErrorResponse,\n flattenHeaders,\n FORMAT_TO_CONTENT_TYPE,\n getContext,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\n\nexport async function handleElevenLabsTTS(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n voiceId: string,\n): Promise<void> {\n const path = req.url ?? `/v1/text-to-speech/${voiceId}`;\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract text from request body\n const promptText = typeof parsed.text === \"string\" && parsed.text ? parsed.text : undefined;\n\n // Build synthetic ChatCompletionRequest for fixture matching\n const syntheticReq: ChatCompletionRequest = {\n model: (parsed.model_id as string) ?? \"eleven_multilingual_v2\",\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"elevenlabs-tts\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Missing required parameter: 'text'\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? `/v1/text-to-speech/${voiceId}`,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Expect audio response\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Standard binary response\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n\nexport async function handleElevenLabsAudio(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n subType: string, // \"sound-generation\" | \"music\" | \"stream\" | \"plan\"\n): Promise<void> {\n const path = req.url ?? \"/v1/sound-generation\";\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract prompt text based on subType\n let promptText: string | undefined;\n if (subType === \"sound-generation\") {\n if (typeof parsed.text === \"string\" && parsed.text) {\n promptText = parsed.text;\n }\n } else {\n // music, music-stream, music-plan all use \"prompt\" (or composition_plan fallback)\n if (typeof parsed.prompt === \"string\" && parsed.prompt) {\n promptText = parsed.prompt;\n } else if (parsed.composition_plan != null) {\n promptText =\n typeof parsed.composition_plan === \"string\"\n ? parsed.composition_plan\n : JSON.stringify(parsed.composition_plan);\n }\n }\n\n // Build synthetic ChatCompletionRequest for fixture matching (needed for journal even on validation failure)\n const syntheticReq: ChatCompletionRequest = {\n model:\n (parsed.model_id as string) ??\n (subType === \"sound-generation\" ? \"eleven_text_to_sound_v2\" : \"music_v1\"),\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"audio-gen\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n const field = subType === \"sound-generation\" ? \"text\" : \"prompt\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Missing required parameter: '${field}'`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? \"/v1/sound-generation\",\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // plan returns JSON text, not audio\n if (subType === \"plan\") {\n if (!isTextResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a text type for plan endpoint\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(response.content);\n return;\n }\n\n // All other subTypes expect audio\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Music endpoints get a song-id header\n if (subType === \"music\" || subType === \"stream\") {\n res.setHeader(\"song-id\", \"mock-song-\" + Date.now());\n }\n\n // Stream uses chunked transfer encoding\n if (subType === \"stream\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Transfer-Encoding\": \"chunked\",\n });\n res.end(audioBytes);\n return;\n }\n\n // Standard binary response for sound-generation and music\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"elevenlabs-audio.js","names":[],"sources":["../src/elevenlabs-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isAudioResponse,\n isTextResponse,\n isErrorResponse,\n isJsonObject,\n serializeErrorResponse,\n flattenHeaders,\n FORMAT_TO_CONTENT_TYPE,\n getContext,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaosAsync } from \"./chaos.js\";\n\nexport async function handleElevenLabsTTS(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n voiceId: string,\n): Promise<void> {\n const path = req.url ?? `/v1/text-to-speech/${voiceId}`;\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract text from request body\n const promptText = typeof parsed.text === \"string\" && parsed.text ? parsed.text : undefined;\n\n // Build synthetic ChatCompletionRequest for fixture matching\n const syntheticReq: ChatCompletionRequest = {\n model: (parsed.model_id as string) ?? \"eleven_multilingual_v2\",\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"elevenlabs-tts\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: \"Missing required parameter: 'text'\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? `/v1/text-to-speech/${voiceId}`,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // Expect audio response\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Standard binary response\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n\nexport async function handleElevenLabsAudio(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n subType: string, // \"sound-generation\" | \"music\" | \"stream\" | \"plan\"\n): Promise<void> {\n const path = req.url ?? \"/v1/sound-generation\";\n const method = req.method ?? \"POST\";\n\n // Parse JSON body\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n 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: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object (e.g. `null`) before\n // touching fields — otherwise `parsed.text` throws a TypeError that surfaces\n // as a 500 instead of a 400.\n if (!isJsonObject(parsed)) {\n journal.add({\n method,\n 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: \"Request body must be a JSON object\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Extract prompt text based on subType\n let promptText: string | undefined;\n if (subType === \"sound-generation\") {\n if (typeof parsed.text === \"string\" && parsed.text) {\n promptText = parsed.text;\n }\n } else {\n // music, music-stream, music-plan all use \"prompt\" (or composition_plan fallback)\n if (typeof parsed.prompt === \"string\" && parsed.prompt) {\n promptText = parsed.prompt;\n } else if (parsed.composition_plan != null) {\n promptText =\n typeof parsed.composition_plan === \"string\"\n ? parsed.composition_plan\n : JSON.stringify(parsed.composition_plan);\n }\n }\n\n // Build synthetic ChatCompletionRequest for fixture matching (needed for journal even on validation failure)\n const syntheticReq: ChatCompletionRequest = {\n model:\n (parsed.model_id as string) ??\n (subType === \"sound-generation\" ? \"eleven_text_to_sound_v2\" : \"music_v1\"),\n messages: [{ role: \"user\", content: promptText ?? \"\" }],\n _endpointType: \"audio-gen\",\n _context: getContext(req),\n };\n\n // Validate required field\n if (!promptText) {\n const field = subType === \"sound-generation\" ? \"text\" : \"prompt\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Missing required parameter: '${field}'`,\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Match fixture\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n matchCounts,\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (\n await applyChaosAsync(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n // No fixture match\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\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 if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"elevenlabs\",\n req.url ?? \"/v1/sound-generation\",\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n // Error fixture\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response), {\n retryAfter: response.retryAfter,\n });\n return;\n }\n\n // plan returns JSON text, not audio\n if (subType === \"plan\") {\n if (!isTextResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: {\n message: \"Fixture response is not a text type for plan endpoint\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(response.content);\n return;\n }\n\n // All other subTypes expect audio\n if (!isAudioResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n // Decode audio bytes and determine content type\n let audioBytes: Buffer;\n let contentType: string;\n\n if (typeof response.audio === \"string\") {\n audioBytes = Buffer.from(response.audio, \"base64\");\n const format = response.format ?? \"mp3\";\n contentType = FORMAT_TO_CONTENT_TYPE[format] ?? \"audio/mpeg\";\n } else {\n audioBytes = Buffer.from(response.audio.b64Json, \"base64\");\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n // Music endpoints get a song-id header\n if (subType === \"music\" || subType === \"stream\") {\n res.setHeader(\"song-id\", \"mock-song-\" + Date.now());\n }\n\n // Stream uses chunked transfer encoding\n if (subType === \"stream\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Transfer-Encoding\": \"chunked\",\n });\n res.end(audioBytes);\n return;\n }\n\n // Standard binary response for sound-generation and music\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(audioBytes);\n}\n"],"mappings":"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"}
|