@copilotkit/aimock 1.22.0 → 1.22.1
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 +15 -0
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +0 -0
- package/dist/aimock-cli.js +0 -0
- package/dist/bedrock-converse.cjs +62 -22
- 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 +62 -22
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +59 -20
- 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 +59 -20
- package/dist/bedrock.js.map +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +29 -9
- 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 +30 -10
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/constants.cjs +8 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +8 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +7 -0
- package/dist/constants.js.map +1 -0
- package/dist/elevenlabs-audio.cjs +41 -18
- package/dist/elevenlabs-audio.cjs.map +1 -1
- package/dist/elevenlabs-audio.d.cts.map +1 -1
- package/dist/elevenlabs-audio.d.ts.map +1 -1
- package/dist/elevenlabs-audio.js +42 -19
- package/dist/elevenlabs-audio.js.map +1 -1
- package/dist/embeddings.cjs +19 -17
- 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 +20 -18
- package/dist/embeddings.js.map +1 -1
- package/dist/fal-audio.cjs +128 -39
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.d.cts.map +1 -1
- package/dist/fal-audio.d.ts.map +1 -1
- package/dist/fal-audio.js +129 -40
- package/dist/fal-audio.js.map +1 -1
- package/dist/fal.cjs +25 -8
- package/dist/fal.cjs.map +1 -1
- package/dist/fal.d.cts.map +1 -1
- package/dist/fal.d.ts.map +1 -1
- package/dist/fal.js +26 -9
- package/dist/fal.js.map +1 -1
- package/dist/fixture-loader.cjs +9 -1
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.js +9 -1
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-interactions.cjs +29 -7
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.js +28 -8
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +45 -19
- 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 +45 -19
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +51 -8
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +6 -0
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +6 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +51 -9
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +26 -8
- 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 +27 -9
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/journal.cjs +17 -7
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +2 -3
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +2 -3
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +15 -4
- package/dist/journal.js.map +1 -1
- package/dist/messages.cjs +33 -12
- 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 +33 -12
- package/dist/messages.js.map +1 -1
- package/dist/ollama.cjs +59 -18
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +60 -19
- package/dist/ollama.js.map +1 -1
- package/dist/recorder.cjs +11 -7
- 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 +11 -7
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +61 -52
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +62 -53
- package/dist/responses.js.map +1 -1
- package/dist/server.cjs +63 -179
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +39 -155
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +26 -8
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.d.cts.map +1 -1
- package/dist/speech.d.ts.map +1 -1
- package/dist/speech.js +27 -9
- package/dist/speech.js.map +1 -1
- package/dist/transcription.cjs +57 -19
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +58 -20
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +2 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/video.cjs +50 -14
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts +8 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts +8 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +51 -15
- package/dist/video.js.map +1 -1
- package/dist/ws-gemini-live.cjs +34 -27
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +34 -27
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +251 -12
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +251 -12
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +48 -12
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.d.cts.map +1 -1
- package/dist/ws-responses.d.ts.map +1 -1
- package/dist/ws-responses.js +49 -13
- package/dist/ws-responses.js.map +1 -1
- package/package.json +2 -2
package/dist/embeddings.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embeddings.js","names":[],"sources":["../src/embeddings.ts"],"sourcesContent":["/**\n * OpenAI Embeddings API support for aimock.\n *\n * Handles POST /v1/embeddings requests. Matches fixtures using the `inputText`\n * field, and falls back to generating a deterministic embedding from the input\n * text hash when no fixture matches.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n Fixture,\n HandlerDefaults,\n RecordProviderKey,\n} from \"./types.js\";\nimport {\n isEmbeddingResponse,\n isErrorResponse,\n generateDeterministicEmbedding,\n buildEmbeddingResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Embeddings API request types ──────────────────────────────────────────\n\ninterface EmbeddingRequest {\n input: string | string[];\n model: string;\n encoding_format?: \"float\" | \"base64\";\n dimensions?: number;\n [key: string]: unknown;\n}\n\n// ─── Request handler ───────────────────────────────────────────────────────\n\nexport async function handleEmbeddings(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n providerKey: RecordProviderKey = \"openai\",\n): Promise<void> {\n const { logger } = defaults;\n setCorsHeaders(res);\n\n let embeddingReq: EmbeddingRequest;\n try {\n embeddingReq = JSON.parse(raw) as EmbeddingRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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 body: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Validate required input parameter\n if (embeddingReq.input === undefined || embeddingReq.input === null) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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: \"Missing required parameter: 'input'\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Normalize input to array of strings\n const inputs: string[] = Array.isArray(embeddingReq.input)\n ? embeddingReq.input\n : [embeddingReq.input];\n\n // Concatenate all inputs for matching purposes\n const combinedInput = inputs.join(\" \");\n\n // Build a synthetic ChatCompletionRequest for the fixture router.\n // We attach `embeddingInput` so the router's inputText matching can use it.\n const syntheticReq: ChatCompletionRequest = {\n model: embeddingReq.model,\n messages: [],\n embeddingInput: combinedInput,\n _endpointType: \"embedding\",\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (fixture) {\n const response = await resolveResponse(fixture, syntheticReq);\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 ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n // Embedding response — use the fixture's embedding for each input\n if (isEmbeddingResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n const embeddings = inputs.map(() => [...response.embedding]);\n const body = buildEmbeddingResponse(embeddings, embeddingReq.model);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return;\n }\n\n // Fixture matched but response type is not compatible with embeddings\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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:\n \"Fixture response did not match any known embedding type (must have embedding or error)\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n // No fixture match — try record-and-replay proxy if configured\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n providerKey,\n req.url ?? \"/v1/embeddings\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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 if (resolveStrictMode(defaults.strict, req.headers)) {\n logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/embeddings\"}`,\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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: \"Strict mode: no fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n // No fixture match — generate deterministic embeddings from input text\n logger.warn(\n `No embedding fixture matched for \"${combinedInput.slice(0, 80)}\" — returning deterministic fallback`,\n );\n const dimensions = embeddingReq.dimensions ?? 1536;\n const embeddings = inputs.map((input) => generateDeterministicEmbedding(input, dimensions));\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture: null },\n });\n\n const body = buildEmbeddingResponse(embeddings, embeddingReq.model);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"embeddings.js","names":[],"sources":["../src/embeddings.ts"],"sourcesContent":["/**\n * OpenAI Embeddings API support for aimock.\n *\n * Handles POST /v1/embeddings requests. Matches fixtures using the `inputText`\n * field, and falls back to generating a deterministic embedding from the input\n * text hash when no fixture matches.\n */\n\nimport type * as http from \"node:http\";\nimport type {\n ChatCompletionRequest,\n Fixture,\n HandlerDefaults,\n RecordProviderKey,\n} from \"./types.js\";\nimport {\n isEmbeddingResponse,\n isErrorResponse,\n serializeErrorResponse,\n generateDeterministicEmbedding,\n buildEmbeddingResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n// ─── Embeddings API request types ──────────────────────────────────────────\n\ninterface EmbeddingRequest {\n input: string | string[];\n model: string;\n encoding_format?: \"float\" | \"base64\";\n dimensions?: number;\n [key: string]: unknown;\n}\n\n// ─── Request handler ───────────────────────────────────────────────────────\n\nexport async function handleEmbeddings(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n providerKey: RecordProviderKey = \"openai\",\n): Promise<void> {\n const { logger } = defaults;\n setCorsHeaders(res);\n\n let embeddingReq: EmbeddingRequest;\n try {\n embeddingReq = JSON.parse(raw) as EmbeddingRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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 body: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n // Validate required input parameter\n if (embeddingReq.input === undefined || embeddingReq.input === null) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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: \"Missing required parameter: 'input'\",\n type: \"invalid_request_error\",\n },\n }),\n );\n return;\n }\n\n // Normalize input to array of strings\n const inputs: string[] = Array.isArray(embeddingReq.input)\n ? embeddingReq.input\n : [embeddingReq.input];\n\n // Concatenate all inputs for matching purposes\n const combinedInput = inputs.join(\" \");\n\n // Build a synthetic ChatCompletionRequest for the fixture router.\n // We attach `embeddingInput` so the router's inputText matching can use it.\n const syntheticReq: ChatCompletionRequest = {\n model: embeddingReq.model,\n messages: [],\n embeddingInput: combinedInput,\n _endpointType: \"embedding\",\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (fixture) {\n const response = await resolveResponse(fixture, syntheticReq);\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 ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response));\n return;\n }\n\n // Embedding response — use the fixture's embedding for each input\n if (isEmbeddingResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n const embeddings = inputs.map(() => [...response.embedding]);\n const body = buildEmbeddingResponse(embeddings, embeddingReq.model);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n return;\n }\n\n // Fixture matched but response type is not compatible with embeddings\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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:\n \"Fixture response did not match any known embedding type (must have embedding or error)\",\n type: \"server_error\",\n },\n }),\n );\n return;\n }\n\n // No fixture match — check strict mode first, then try proxy\n if (resolveStrictMode(defaults.strict, req.headers)) {\n logger.error(\n `STRICT: No fixture matched for ${req.method ?? \"POST\"} ${req.url ?? \"/v1/embeddings\"}`,\n );\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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: \"Strict mode: no fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n providerKey,\n req.url ?? \"/v1/embeddings\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\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 // No fixture match — generate deterministic embeddings from input text\n logger.warn(\n `No embedding fixture matched for \"${combinedInput.slice(0, 80)}\" — returning deterministic fallback`,\n );\n const dimensions = embeddingReq.dimensions ?? 1536;\n const embeddings = inputs.map((input) => generateDeterministicEmbedding(input, dimensions));\n\n journal.add({\n method: req.method ?? \"POST\",\n path: req.url ?? \"/v1/embeddings\",\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture: null },\n });\n\n const body = buildEmbeddingResponse(embeddings, embeddingReq.model);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
|
package/dist/fal-audio.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
2
|
const require_helpers = require('./helpers.cjs');
|
|
3
3
|
const require_router = require('./router.cjs');
|
|
4
|
+
const require_sse_writer = require('./sse-writer.cjs');
|
|
5
|
+
const require_chaos = require('./chaos.cjs');
|
|
4
6
|
const require_recorder = require('./recorder.cjs');
|
|
5
7
|
let node_crypto = require("node:crypto");
|
|
6
8
|
node_crypto = require_runtime.__toESM(node_crypto);
|
|
@@ -13,9 +15,30 @@ const FAL_JOB_TTL_MS = 36e5;
|
|
|
13
15
|
* Entries older than FAL_JOB_TTL_MS are lazily evicted on `get`.
|
|
14
16
|
* When the map exceeds FAL_JOB_MAX_ENTRIES on `set`, the oldest entries
|
|
15
17
|
* are removed to stay within bounds.
|
|
18
|
+
* A background sweep runs every 60 s to proactively evict expired entries.
|
|
16
19
|
*/
|
|
17
20
|
var FalJobMap = class {
|
|
18
21
|
entries = /* @__PURE__ */ new Map();
|
|
22
|
+
sweepTimer = null;
|
|
23
|
+
constructor() {
|
|
24
|
+
this.startSweep();
|
|
25
|
+
}
|
|
26
|
+
/** Start the proactive TTL sweep (every 60 s). */
|
|
27
|
+
startSweep() {
|
|
28
|
+
if (this.sweepTimer) return;
|
|
29
|
+
this.sweepTimer = setInterval(() => {
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
for (const [key, entry] of this.entries) if (now - entry.createdAt > FAL_JOB_TTL_MS) this.entries.delete(key);
|
|
32
|
+
}, 6e4);
|
|
33
|
+
if (this.sweepTimer && typeof this.sweepTimer === "object" && "unref" in this.sweepTimer) this.sweepTimer.unref();
|
|
34
|
+
}
|
|
35
|
+
/** Stop the proactive TTL sweep. */
|
|
36
|
+
stopSweep() {
|
|
37
|
+
if (this.sweepTimer) {
|
|
38
|
+
clearInterval(this.sweepTimer);
|
|
39
|
+
this.sweepTimer = null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
19
42
|
get(key) {
|
|
20
43
|
const entry = this.entries.get(key);
|
|
21
44
|
if (!entry) return void 0;
|
|
@@ -45,6 +68,10 @@ var FalJobMap = class {
|
|
|
45
68
|
clear() {
|
|
46
69
|
this.entries.clear();
|
|
47
70
|
}
|
|
71
|
+
destroy() {
|
|
72
|
+
this.stopSweep();
|
|
73
|
+
this.entries.clear();
|
|
74
|
+
}
|
|
48
75
|
get size() {
|
|
49
76
|
return this.entries.size;
|
|
50
77
|
}
|
|
@@ -109,7 +136,7 @@ async function handleFalQueue(req, res, body, pathname, fixtures, defaults, jour
|
|
|
109
136
|
journal.add({
|
|
110
137
|
method: req.method ?? "GET",
|
|
111
138
|
path: pathname,
|
|
112
|
-
headers:
|
|
139
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
113
140
|
body: null,
|
|
114
141
|
response: {
|
|
115
142
|
status: 404,
|
|
@@ -128,7 +155,7 @@ async function handleQueueSubmit(req, res, body, pathname, modelId, testId, fixt
|
|
|
128
155
|
journal.add({
|
|
129
156
|
method: req.method ?? "POST",
|
|
130
157
|
path: pathname,
|
|
131
|
-
headers:
|
|
158
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
132
159
|
body: null,
|
|
133
160
|
response: {
|
|
134
161
|
status: 400,
|
|
@@ -151,15 +178,42 @@ async function handleQueueSubmit(req, res, body, pathname, modelId, testId, fixt
|
|
|
151
178
|
_endpointType: "fal-audio"
|
|
152
179
|
};
|
|
153
180
|
const fixture = require_router.matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);
|
|
181
|
+
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
182
|
+
if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
|
|
183
|
+
method: req.method ?? "POST",
|
|
184
|
+
path: pathname,
|
|
185
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
186
|
+
body: syntheticReq
|
|
187
|
+
}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
|
|
154
188
|
if (!fixture) {
|
|
189
|
+
if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
|
|
190
|
+
journal.add({
|
|
191
|
+
method: req.method ?? "POST",
|
|
192
|
+
path: pathname,
|
|
193
|
+
headers: {},
|
|
194
|
+
body: syntheticReq,
|
|
195
|
+
response: {
|
|
196
|
+
status: 503,
|
|
197
|
+
fixture: null,
|
|
198
|
+
...require_helpers.strictOverrideField(defaults.strict, req.headers)
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
202
|
+
res.end(JSON.stringify({ error: {
|
|
203
|
+
message: "Strict mode: no fixture matched",
|
|
204
|
+
type: "invalid_request_error",
|
|
205
|
+
code: "no_fixture_match"
|
|
206
|
+
} }));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
155
209
|
if (defaults.record) {
|
|
156
210
|
const outcome = await require_recorder.proxyAndRecord(req, res, syntheticReq, "fal", pathname, fixtures, defaults, body);
|
|
157
211
|
if (outcome === "handled_by_hook") return;
|
|
158
|
-
if (outcome
|
|
212
|
+
if (outcome !== "not_configured") {
|
|
159
213
|
journal.add({
|
|
160
214
|
method: req.method ?? "POST",
|
|
161
215
|
path: pathname,
|
|
162
|
-
headers:
|
|
216
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
163
217
|
body: syntheticReq,
|
|
164
218
|
response: {
|
|
165
219
|
status: res.statusCode ?? 200,
|
|
@@ -170,36 +224,32 @@ async function handleQueueSubmit(req, res, body, pathname, modelId, testId, fixt
|
|
|
170
224
|
return;
|
|
171
225
|
}
|
|
172
226
|
}
|
|
173
|
-
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
174
|
-
const strictStatus = effectiveStrict ? 503 : 404;
|
|
175
|
-
const strictMessage = effectiveStrict ? "Strict mode: no fixture matched" : "No fixture matched";
|
|
176
227
|
journal.add({
|
|
177
228
|
method: req.method ?? "POST",
|
|
178
229
|
path: pathname,
|
|
179
|
-
headers:
|
|
230
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
180
231
|
body: syntheticReq,
|
|
181
232
|
response: {
|
|
182
|
-
status:
|
|
233
|
+
status: 404,
|
|
183
234
|
fixture: null,
|
|
184
235
|
...require_helpers.strictOverrideField(defaults.strict, req.headers)
|
|
185
236
|
}
|
|
186
237
|
});
|
|
187
|
-
res.writeHead(
|
|
238
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
188
239
|
res.end(JSON.stringify({ error: {
|
|
189
|
-
message:
|
|
240
|
+
message: "No fixture matched",
|
|
190
241
|
type: "invalid_request_error",
|
|
191
242
|
code: "no_fixture_match"
|
|
192
243
|
} }));
|
|
193
244
|
return;
|
|
194
245
|
}
|
|
195
|
-
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
196
246
|
const response = await require_helpers.resolveResponse(fixture, syntheticReq);
|
|
197
247
|
if (require_helpers.isErrorResponse(response)) {
|
|
198
248
|
const status = response.status ?? 500;
|
|
199
249
|
journal.add({
|
|
200
250
|
method: req.method ?? "POST",
|
|
201
251
|
path: pathname,
|
|
202
|
-
headers:
|
|
252
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
203
253
|
body: syntheticReq,
|
|
204
254
|
response: {
|
|
205
255
|
status,
|
|
@@ -207,14 +257,14 @@ async function handleQueueSubmit(req, res, body, pathname, modelId, testId, fixt
|
|
|
207
257
|
}
|
|
208
258
|
});
|
|
209
259
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
210
|
-
res.end(
|
|
260
|
+
res.end(require_helpers.serializeErrorResponse(response));
|
|
211
261
|
return;
|
|
212
262
|
}
|
|
213
263
|
if (!require_helpers.isAudioResponse(response)) {
|
|
214
264
|
journal.add({
|
|
215
265
|
method: req.method ?? "POST",
|
|
216
266
|
path: pathname,
|
|
217
|
-
headers:
|
|
267
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
218
268
|
body: syntheticReq,
|
|
219
269
|
response: {
|
|
220
270
|
status: 500,
|
|
@@ -233,15 +283,14 @@ async function handleQueueSubmit(req, res, body, pathname, modelId, testId, fixt
|
|
|
233
283
|
requestId,
|
|
234
284
|
modelId,
|
|
235
285
|
status: "COMPLETED",
|
|
236
|
-
result: audioToFalFile(response)
|
|
237
|
-
createdAt: Date.now()
|
|
286
|
+
result: audioToFalFile(response)
|
|
238
287
|
};
|
|
239
288
|
const stateKey = `${testId}:${requestId}`;
|
|
240
289
|
falJobs.set(stateKey, job);
|
|
241
290
|
journal.add({
|
|
242
291
|
method: req.method ?? "POST",
|
|
243
292
|
path: pathname,
|
|
244
|
-
headers:
|
|
293
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
245
294
|
body: syntheticReq,
|
|
246
295
|
response: {
|
|
247
296
|
status: 200,
|
|
@@ -264,7 +313,7 @@ function handleQueueStatus(req, res, pathname, requestId, testId, journal) {
|
|
|
264
313
|
journal.add({
|
|
265
314
|
method: req.method ?? "GET",
|
|
266
315
|
path: pathname,
|
|
267
|
-
headers:
|
|
316
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
268
317
|
body: null,
|
|
269
318
|
response: {
|
|
270
319
|
status: 404,
|
|
@@ -281,7 +330,7 @@ function handleQueueStatus(req, res, pathname, requestId, testId, journal) {
|
|
|
281
330
|
journal.add({
|
|
282
331
|
method: req.method ?? "GET",
|
|
283
332
|
path: pathname,
|
|
284
|
-
headers:
|
|
333
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
285
334
|
body: null,
|
|
286
335
|
response: {
|
|
287
336
|
status: 200,
|
|
@@ -302,7 +351,7 @@ function handleQueueResult(req, res, pathname, requestId, testId, journal) {
|
|
|
302
351
|
journal.add({
|
|
303
352
|
method: req.method ?? "GET",
|
|
304
353
|
path: pathname,
|
|
305
|
-
headers:
|
|
354
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
306
355
|
body: null,
|
|
307
356
|
response: {
|
|
308
357
|
status: 404,
|
|
@@ -316,10 +365,27 @@ function handleQueueResult(req, res, pathname, requestId, testId, journal) {
|
|
|
316
365
|
} }));
|
|
317
366
|
return;
|
|
318
367
|
}
|
|
368
|
+
if (job.result === null) {
|
|
369
|
+
journal.add({
|
|
370
|
+
method: req.method ?? "GET",
|
|
371
|
+
path: pathname,
|
|
372
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
373
|
+
body: null,
|
|
374
|
+
response: {
|
|
375
|
+
status: 409,
|
|
376
|
+
fixture: null
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
require_sse_writer.writeErrorResponse(res, 409, JSON.stringify({ error: {
|
|
380
|
+
message: "Job result not yet available",
|
|
381
|
+
type: "not_ready"
|
|
382
|
+
} }));
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
319
385
|
journal.add({
|
|
320
386
|
method: req.method ?? "GET",
|
|
321
387
|
path: pathname,
|
|
322
|
-
headers:
|
|
388
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
323
389
|
body: null,
|
|
324
390
|
response: {
|
|
325
391
|
status: 200,
|
|
@@ -335,7 +401,7 @@ function handleQueueCancel(req, res, pathname, requestId, testId, journal) {
|
|
|
335
401
|
journal.add({
|
|
336
402
|
method: req.method ?? "DELETE",
|
|
337
403
|
path: pathname,
|
|
338
|
-
headers:
|
|
404
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
339
405
|
body: null,
|
|
340
406
|
response: {
|
|
341
407
|
status: 404,
|
|
@@ -349,7 +415,7 @@ function handleQueueCancel(req, res, pathname, requestId, testId, journal) {
|
|
|
349
415
|
journal.add({
|
|
350
416
|
method: req.method ?? "DELETE",
|
|
351
417
|
path: pathname,
|
|
352
|
-
headers:
|
|
418
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
353
419
|
body: null,
|
|
354
420
|
response: {
|
|
355
421
|
status: 400,
|
|
@@ -368,7 +434,7 @@ async function handleSyncRun(req, res, body, pathname, modelId, fixtures, defaul
|
|
|
368
434
|
journal.add({
|
|
369
435
|
method: req.method ?? "POST",
|
|
370
436
|
path: pathname,
|
|
371
|
-
headers:
|
|
437
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
372
438
|
body: null,
|
|
373
439
|
response: {
|
|
374
440
|
status: 400,
|
|
@@ -391,15 +457,42 @@ async function handleSyncRun(req, res, body, pathname, modelId, fixtures, defaul
|
|
|
391
457
|
_endpointType: "fal-audio"
|
|
392
458
|
};
|
|
393
459
|
const fixture = require_router.matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);
|
|
460
|
+
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, require_helpers.getTestId(req));
|
|
461
|
+
if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
|
|
462
|
+
method: req.method ?? "POST",
|
|
463
|
+
path: pathname,
|
|
464
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
465
|
+
body: syntheticReq
|
|
466
|
+
}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
|
|
394
467
|
if (!fixture) {
|
|
468
|
+
if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
|
|
469
|
+
journal.add({
|
|
470
|
+
method: req.method ?? "POST",
|
|
471
|
+
path: pathname,
|
|
472
|
+
headers: {},
|
|
473
|
+
body: syntheticReq,
|
|
474
|
+
response: {
|
|
475
|
+
status: 503,
|
|
476
|
+
fixture: null,
|
|
477
|
+
...require_helpers.strictOverrideField(defaults.strict, req.headers)
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
481
|
+
res.end(JSON.stringify({ error: {
|
|
482
|
+
message: "Strict mode: no fixture matched",
|
|
483
|
+
type: "invalid_request_error",
|
|
484
|
+
code: "no_fixture_match"
|
|
485
|
+
} }));
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
395
488
|
if (defaults.record) {
|
|
396
489
|
const outcome = await require_recorder.proxyAndRecord(req, res, syntheticReq, "fal", pathname, fixtures, defaults, body);
|
|
397
490
|
if (outcome === "handled_by_hook") return;
|
|
398
|
-
if (outcome
|
|
491
|
+
if (outcome !== "not_configured") {
|
|
399
492
|
journal.add({
|
|
400
493
|
method: req.method ?? "POST",
|
|
401
494
|
path: pathname,
|
|
402
|
-
headers:
|
|
495
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
403
496
|
body: syntheticReq,
|
|
404
497
|
response: {
|
|
405
498
|
status: res.statusCode ?? 200,
|
|
@@ -410,36 +503,32 @@ async function handleSyncRun(req, res, body, pathname, modelId, fixtures, defaul
|
|
|
410
503
|
return;
|
|
411
504
|
}
|
|
412
505
|
}
|
|
413
|
-
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
414
|
-
const strictStatus = effectiveStrict ? 503 : 404;
|
|
415
|
-
const strictMessage = effectiveStrict ? "Strict mode: no fixture matched" : "No fixture matched";
|
|
416
506
|
journal.add({
|
|
417
507
|
method: req.method ?? "POST",
|
|
418
508
|
path: pathname,
|
|
419
|
-
headers:
|
|
509
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
420
510
|
body: syntheticReq,
|
|
421
511
|
response: {
|
|
422
|
-
status:
|
|
512
|
+
status: 404,
|
|
423
513
|
fixture: null,
|
|
424
514
|
...require_helpers.strictOverrideField(defaults.strict, req.headers)
|
|
425
515
|
}
|
|
426
516
|
});
|
|
427
|
-
res.writeHead(
|
|
517
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
428
518
|
res.end(JSON.stringify({ error: {
|
|
429
|
-
message:
|
|
519
|
+
message: "No fixture matched",
|
|
430
520
|
type: "invalid_request_error",
|
|
431
521
|
code: "no_fixture_match"
|
|
432
522
|
} }));
|
|
433
523
|
return;
|
|
434
524
|
}
|
|
435
|
-
journal.incrementFixtureMatchCount(fixture, fixtures, require_helpers.getTestId(req));
|
|
436
525
|
const response = await require_helpers.resolveResponse(fixture, syntheticReq);
|
|
437
526
|
if (require_helpers.isErrorResponse(response)) {
|
|
438
527
|
const status = response.status ?? 500;
|
|
439
528
|
journal.add({
|
|
440
529
|
method: req.method ?? "POST",
|
|
441
530
|
path: pathname,
|
|
442
|
-
headers:
|
|
531
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
443
532
|
body: syntheticReq,
|
|
444
533
|
response: {
|
|
445
534
|
status,
|
|
@@ -447,14 +536,14 @@ async function handleSyncRun(req, res, body, pathname, modelId, fixtures, defaul
|
|
|
447
536
|
}
|
|
448
537
|
});
|
|
449
538
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
450
|
-
res.end(
|
|
539
|
+
res.end(require_helpers.serializeErrorResponse(response));
|
|
451
540
|
return;
|
|
452
541
|
}
|
|
453
542
|
if (!require_helpers.isAudioResponse(response)) {
|
|
454
543
|
journal.add({
|
|
455
544
|
method: req.method ?? "POST",
|
|
456
545
|
path: pathname,
|
|
457
|
-
headers:
|
|
546
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
458
547
|
body: syntheticReq,
|
|
459
548
|
response: {
|
|
460
549
|
status: 500,
|
|
@@ -472,7 +561,7 @@ async function handleSyncRun(req, res, body, pathname, modelId, fixtures, defaul
|
|
|
472
561
|
journal.add({
|
|
473
562
|
method: req.method ?? "POST",
|
|
474
563
|
path: pathname,
|
|
475
|
-
headers:
|
|
564
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
476
565
|
body: syntheticReq,
|
|
477
566
|
response: {
|
|
478
567
|
status: 200,
|
package/dist/fal-audio.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fal-audio.cjs","names":["FORMAT_TO_CONTENT_TYPE","getTestId","matchFixture","proxyAndRecord","resolveStrictMode","strictOverrideField","resolveResponse","isErrorResponse","isAudioResponse","crypto"],"sources":["../src/fal-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport type { AudioResponse, ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isAudioResponse,\n isErrorResponse,\n FORMAT_TO_CONTENT_TYPE,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\n\n// ─── FalJobMap with TTL and size bound ───────────────────────────────────\n\nconst FAL_JOB_MAX_ENTRIES = 10_000;\nconst FAL_JOB_TTL_MS = 3_600_000; // 1 hour\n\ninterface FalJob {\n requestId: string;\n modelId: string;\n status: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\";\n result: Record<string, unknown> | null;\n createdAt: number;\n}\n\ninterface FalJobEntry {\n job: FalJob;\n createdAt: number;\n}\n\n/**\n * A Map wrapper for fal.ai queue jobs that enforces a maximum size and per-entry TTL.\n * Entries older than FAL_JOB_TTL_MS are lazily evicted on `get`.\n * When the map exceeds FAL_JOB_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class FalJobMap {\n private readonly entries = new Map<string, FalJobEntry>();\n\n get(key: string): FalJob | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > FAL_JOB_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.job;\n }\n\n set(key: string, job: FalJob): void {\n this.entries.set(key, { job, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > FAL_JOB_MAX_ENTRIES) {\n const excess = this.entries.size - FAL_JOB_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\n// Module-level singleton — exported so server.ts can clear it during reset\nexport const falJobs = new FalJobMap();\n\n// ─── Audio response translation ──────────────────────────────────────────\n\nexport function audioToFalFile(response: AudioResponse): Record<string, unknown> {\n let contentType: string;\n let data: string;\n\n if (typeof response.audio === \"string\") {\n data = response.audio;\n contentType = FORMAT_TO_CONTENT_TYPE[response.format ?? \"mp3\"] ?? \"audio/mpeg\";\n } else {\n data = response.audio.b64Json;\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n const ext =\n response.format ??\n (contentType !== \"audio/mpeg\"\n ? (Object.entries(FORMAT_TO_CONTENT_TYPE).find(([, v]) => v === contentType)?.[0] ?? \"mp3\")\n : \"mp3\");\n\n const fileSize =\n Math.ceil((data.length * 3) / 4) - (data.endsWith(\"==\") ? 2 : data.endsWith(\"=\") ? 1 : 0);\n\n return {\n audio: {\n url: `https://mock.fal.media/files/generated_audio.${ext}`,\n content_type: contentType,\n file_name: `generated_audio.${ext}`,\n file_size: fileSize,\n },\n };\n}\n\n// ─── Route patterns ──────────────────────────────────────────────────────\n\nconst QUEUE_SUBMIT_RE = /^\\/fal\\/queue\\/submit\\/(.+)$/;\nconst QUEUE_STATUS_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)\\/status$/;\nconst QUEUE_RESULT_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)$/;\nconst QUEUE_CANCEL_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)\\/cancel$/;\nconst SYNC_RUN_RE = /^\\/fal\\/run\\/(.+)$/;\n\n// ─── Handler ─────────────────────────────────────────────────────────────\n\nexport async function handleFalQueue(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n pathname: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n): Promise<void> {\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n\n // ── Queue Submit ───────────────────────────────────────────────────\n const submitMatch = QUEUE_SUBMIT_RE.exec(pathname);\n if (submitMatch && req.method === \"POST\") {\n const modelId = submitMatch[1];\n return handleQueueSubmit(\n req,\n res,\n body,\n pathname,\n modelId,\n testId,\n fixtures,\n defaults,\n matchCounts,\n journal,\n );\n }\n\n // ── Queue Status ───────────────────────────────────────────────────\n const statusMatch = QUEUE_STATUS_RE.exec(pathname);\n if (statusMatch) {\n const requestId = statusMatch[1];\n return handleQueueStatus(req, res, pathname, requestId, testId, journal);\n }\n\n // ── Queue Cancel ───────────────────────────────────────────────────\n const cancelMatch = QUEUE_CANCEL_RE.exec(pathname);\n if (cancelMatch) {\n const requestId = cancelMatch[1];\n return handleQueueCancel(req, res, pathname, requestId, testId, journal);\n }\n\n // ── Queue Result ───────────────────────────────────────────────────\n const resultMatch = QUEUE_RESULT_RE.exec(pathname);\n if (resultMatch) {\n const requestId = resultMatch[1];\n return handleQueueResult(req, res, pathname, requestId, testId, journal);\n }\n\n // ── Synchronous Run ────────────────────────────────────────────────\n const runMatch = SYNC_RUN_RE.exec(pathname);\n if (runMatch && req.method === \"POST\") {\n const modelId = runMatch[1];\n return handleSyncRun(\n req,\n res,\n body,\n pathname,\n modelId,\n fixtures,\n defaults,\n matchCounts,\n journal,\n );\n }\n\n // Unknown fal path\n const errorBody = { error: { message: \"Unknown fal.ai endpoint\", type: \"not_found\" } };\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(errorBody));\n}\n\n// ─── Sub-handlers ────────────────────────────────────────────────────────\n\nasync function handleQueueSubmit(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n pathname: string,\n modelId: string,\n testId: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n matchCounts: Map<Fixture, number>,\n journal: Journal,\n): Promise<void> {\n let parsed: Record<string, unknown> = {};\n if (body.trim()) {\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: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 400, fixture: null },\n });\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Malformed JSON: ${detail}`, type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n }\n\n const prompt =\n (typeof parsed.prompt === \"string\" ? parsed.prompt : null) ??\n (typeof parsed.text === \"string\" ? parsed.text : null) ??\n \"\";\n\n const syntheticReq: ChatCompletionRequest = {\n model: modelId,\n messages: [{ role: \"user\", content: prompt }],\n _endpointType: \"fal-audio\",\n };\n\n const fixture = matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);\n\n if (!fixture) {\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"fal\",\n pathname,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome === \"relayed\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const strictStatus = effectiveStrict ? 503 : 404;\n const strictMessage = effectiveStrict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n res.writeHead(strictStatus, { \"Content-Type\": \"application/json\" });\n res.end(\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 journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status, fixture },\n });\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n if (!isAudioResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n const requestId = crypto.randomUUID();\n const result = audioToFalFile(response);\n\n const job: FalJob = {\n requestId,\n modelId,\n status: \"COMPLETED\",\n result,\n createdAt: Date.now(),\n };\n\n const stateKey = `${testId}:${requestId}`;\n falJobs.set(stateKey, job);\n\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n request_id: requestId,\n response_url: `https://queue.fal.run/${modelId}/requests/${requestId}/response`,\n status_url: `https://queue.fal.run/${modelId}/requests/${requestId}/status`,\n cancel_url: `https://queue.fal.run/${modelId}/requests/${requestId}/cancel`,\n queue_position: 0,\n }),\n );\n}\n\nfunction handleQueueStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n requestId: string,\n testId: string,\n journal: Journal,\n): void {\n const stateKey = `${testId}:${requestId}`;\n const job = falJobs.get(stateKey);\n\n if (!job) {\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Request ${requestId} not found`, type: \"not_found\" },\n }),\n );\n return;\n }\n\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 200, fixture: null },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n status: job.status,\n request_id: job.requestId,\n response_url: `https://queue.fal.run/${job.modelId}/requests/${requestId}/response`,\n }),\n );\n}\n\nfunction handleQueueResult(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n requestId: string,\n testId: string,\n journal: Journal,\n): void {\n const stateKey = `${testId}:${requestId}`;\n const job = falJobs.get(stateKey);\n\n if (!job) {\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Request ${requestId} not found`, type: \"not_found\" },\n }),\n );\n return;\n }\n\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 200, fixture: null },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(job.result));\n}\n\nfunction handleQueueCancel(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n requestId: string,\n testId: string,\n journal: Journal,\n): void {\n const stateKey = `${testId}:${requestId}`;\n const job = falJobs.get(stateKey);\n\n if (!job) {\n journal.add({\n method: req.method ?? \"DELETE\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"NOT_FOUND\" }));\n return;\n }\n\n // Since we complete immediately, cancellation always returns ALREADY_COMPLETED\n journal.add({\n method: req.method ?? \"DELETE\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 400, fixture: null },\n });\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ALREADY_COMPLETED\" }));\n}\n\nasync function handleSyncRun(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n pathname: string,\n modelId: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n matchCounts: Map<Fixture, number>,\n journal: Journal,\n): Promise<void> {\n let parsed: Record<string, unknown> = {};\n if (body.trim()) {\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: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: null,\n response: { status: 400, fixture: null },\n });\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Malformed JSON: ${detail}`, type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n }\n\n const prompt =\n (typeof parsed.prompt === \"string\" ? parsed.prompt : null) ??\n (typeof parsed.text === \"string\" ? parsed.text : null) ??\n \"\";\n\n const syntheticReq: ChatCompletionRequest = {\n model: modelId,\n messages: [{ role: \"user\", content: prompt }],\n _endpointType: \"fal-audio\",\n };\n\n const fixture = matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);\n\n if (!fixture) {\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"fal\",\n pathname,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome === \"relayed\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const strictStatus = effectiveStrict ? 503 : 404;\n const strictMessage = effectiveStrict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n res.writeHead(strictStatus, { \"Content-Type\": \"application/json\" });\n res.end(\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 journal.incrementFixtureMatchCount(fixture, fixtures, getTestId(req));\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status, fixture },\n });\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(response));\n return;\n }\n\n if (!isAudioResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n const result = audioToFalFile(response);\n\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fal-audio.cjs","names":["FORMAT_TO_CONTENT_TYPE","getTestId","flattenHeaders","matchFixture","applyChaos","resolveStrictMode","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isAudioResponse","crypto"],"sources":["../src/fal-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport type { AudioResponse, ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport {\n isAudioResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n FORMAT_TO_CONTENT_TYPE,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport { matchFixture } from \"./router.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\n\n// ─── FalJobMap with TTL and size bound ───────────────────────────────────\n\nconst FAL_JOB_MAX_ENTRIES = 10_000;\nconst FAL_JOB_TTL_MS = 3_600_000; // 1 hour\n\ninterface FalJob {\n requestId: string;\n modelId: string;\n status: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\";\n result: Record<string, unknown> | null;\n}\n\ninterface FalJobEntry {\n job: FalJob;\n createdAt: number;\n}\n\n/**\n * A Map wrapper for fal.ai queue jobs that enforces a maximum size and per-entry TTL.\n * Entries older than FAL_JOB_TTL_MS are lazily evicted on `get`.\n * When the map exceeds FAL_JOB_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n * A background sweep runs every 60 s to proactively evict expired entries.\n */\nexport class FalJobMap {\n private readonly entries = new Map<string, FalJobEntry>();\n private sweepTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor() {\n this.startSweep();\n }\n\n /** Start the proactive TTL sweep (every 60 s). */\n startSweep(): void {\n if (this.sweepTimer) return;\n this.sweepTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of this.entries) {\n if (now - entry.createdAt > FAL_JOB_TTL_MS) {\n this.entries.delete(key);\n }\n }\n }, 60_000);\n // Allow the process to exit even if the timer is still active\n if (this.sweepTimer && typeof this.sweepTimer === \"object\" && \"unref\" in this.sweepTimer) {\n this.sweepTimer.unref();\n }\n }\n\n /** Stop the proactive TTL sweep. */\n stopSweep(): void {\n if (this.sweepTimer) {\n clearInterval(this.sweepTimer);\n this.sweepTimer = null;\n }\n }\n\n get(key: string): FalJob | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > FAL_JOB_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.job;\n }\n\n set(key: string, job: FalJob): void {\n this.entries.set(key, { job, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > FAL_JOB_MAX_ENTRIES) {\n const excess = this.entries.size - FAL_JOB_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n destroy(): void {\n this.stopSweep();\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\n// Module-level singleton — exported so server.ts can clear it during reset\nexport const falJobs = new FalJobMap();\n\n// ─── Audio response translation ──────────────────────────────────────────\n\nexport function audioToFalFile(response: AudioResponse): Record<string, unknown> {\n let contentType: string;\n let data: string;\n\n if (typeof response.audio === \"string\") {\n data = response.audio;\n contentType = FORMAT_TO_CONTENT_TYPE[response.format ?? \"mp3\"] ?? \"audio/mpeg\";\n } else {\n data = response.audio.b64Json;\n contentType = response.audio.contentType ?? \"audio/mpeg\";\n }\n\n const ext =\n response.format ??\n (contentType !== \"audio/mpeg\"\n ? (Object.entries(FORMAT_TO_CONTENT_TYPE).find(([, v]) => v === contentType)?.[0] ?? \"mp3\")\n : \"mp3\");\n\n const fileSize =\n Math.ceil((data.length * 3) / 4) - (data.endsWith(\"==\") ? 2 : data.endsWith(\"=\") ? 1 : 0);\n\n return {\n audio: {\n url: `https://mock.fal.media/files/generated_audio.${ext}`,\n content_type: contentType,\n file_name: `generated_audio.${ext}`,\n file_size: fileSize,\n },\n };\n}\n\n// ─── Route patterns ──────────────────────────────────────────────────────\n\nconst QUEUE_SUBMIT_RE = /^\\/fal\\/queue\\/submit\\/(.+)$/;\nconst QUEUE_STATUS_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)\\/status$/;\nconst QUEUE_RESULT_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)$/;\nconst QUEUE_CANCEL_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)\\/cancel$/;\nconst SYNC_RUN_RE = /^\\/fal\\/run\\/(.+)$/;\n\n// ─── Handler ─────────────────────────────────────────────────────────────\n\nexport async function handleFalQueue(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n pathname: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n journal: Journal,\n): Promise<void> {\n const testId = getTestId(req);\n const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n\n // ── Queue Submit ───────────────────────────────────────────────────\n const submitMatch = QUEUE_SUBMIT_RE.exec(pathname);\n if (submitMatch && req.method === \"POST\") {\n const modelId = submitMatch[1];\n return handleQueueSubmit(\n req,\n res,\n body,\n pathname,\n modelId,\n testId,\n fixtures,\n defaults,\n matchCounts,\n journal,\n );\n }\n\n // ── Queue Status ───────────────────────────────────────────────────\n const statusMatch = QUEUE_STATUS_RE.exec(pathname);\n if (statusMatch) {\n const requestId = statusMatch[1];\n return handleQueueStatus(req, res, pathname, requestId, testId, journal);\n }\n\n // ── Queue Cancel ───────────────────────────────────────────────────\n const cancelMatch = QUEUE_CANCEL_RE.exec(pathname);\n if (cancelMatch) {\n const requestId = cancelMatch[1];\n return handleQueueCancel(req, res, pathname, requestId, testId, journal);\n }\n\n // ── Queue Result ───────────────────────────────────────────────────\n const resultMatch = QUEUE_RESULT_RE.exec(pathname);\n if (resultMatch) {\n const requestId = resultMatch[1];\n return handleQueueResult(req, res, pathname, requestId, testId, journal);\n }\n\n // ── Synchronous Run ────────────────────────────────────────────────\n const runMatch = SYNC_RUN_RE.exec(pathname);\n if (runMatch && req.method === \"POST\") {\n const modelId = runMatch[1];\n return handleSyncRun(\n req,\n res,\n body,\n pathname,\n modelId,\n fixtures,\n defaults,\n matchCounts,\n journal,\n );\n }\n\n // Unknown fal path\n const errorBody = { error: { message: \"Unknown fal.ai endpoint\", type: \"not_found\" } };\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(errorBody));\n}\n\n// ─── Sub-handlers ────────────────────────────────────────────────────────\n\nasync function handleQueueSubmit(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n pathname: string,\n modelId: string,\n testId: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n matchCounts: Map<Fixture, number>,\n journal: Journal,\n): Promise<void> {\n let parsed: Record<string, unknown> = {};\n if (body.trim()) {\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: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Malformed JSON: ${detail}`, type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n }\n\n const prompt =\n (typeof parsed.prompt === \"string\" ? parsed.prompt : null) ??\n (typeof parsed.text === \"string\" ? parsed.text : null) ??\n \"\";\n\n const syntheticReq: ChatCompletionRequest = {\n model: modelId,\n messages: [{ role: \"user\", content: prompt }],\n _endpointType: \"fal-audio\",\n };\n\n const fixture = matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);\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 journal,\n {\n method: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: {\n message: \"Strict mode: no fixture matched\",\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 \"fal\",\n pathname,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\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: req.method ?? \"POST\",\n path: pathname,\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 res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\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 if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(serializeErrorResponse(response));\n return;\n }\n\n if (!isAudioResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n const requestId = crypto.randomUUID();\n const result = audioToFalFile(response);\n\n const job: FalJob = {\n requestId,\n modelId,\n status: \"COMPLETED\",\n result,\n };\n\n const stateKey = `${testId}:${requestId}`;\n falJobs.set(stateKey, job);\n\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\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(\n JSON.stringify({\n request_id: requestId,\n response_url: `https://queue.fal.run/${modelId}/requests/${requestId}/response`,\n status_url: `https://queue.fal.run/${modelId}/requests/${requestId}/status`,\n cancel_url: `https://queue.fal.run/${modelId}/requests/${requestId}/cancel`,\n queue_position: 0,\n }),\n );\n}\n\nfunction handleQueueStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n requestId: string,\n testId: string,\n journal: Journal,\n): void {\n const stateKey = `${testId}:${requestId}`;\n const job = falJobs.get(stateKey);\n\n if (!job) {\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Request ${requestId} not found`, type: \"not_found\" },\n }),\n );\n return;\n }\n\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n status: job.status,\n request_id: job.requestId,\n response_url: `https://queue.fal.run/${job.modelId}/requests/${requestId}/response`,\n }),\n );\n}\n\nfunction handleQueueResult(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n requestId: string,\n testId: string,\n journal: Journal,\n): void {\n const stateKey = `${testId}:${requestId}`;\n const job = falJobs.get(stateKey);\n\n if (!job) {\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Request ${requestId} not found`, type: \"not_found\" },\n }),\n );\n return;\n }\n\n if (job.result === null) {\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 409, fixture: null },\n });\n writeErrorResponse(\n res,\n 409,\n JSON.stringify({\n error: { message: \"Job result not yet available\", type: \"not_ready\" },\n }),\n );\n return;\n }\n\n journal.add({\n method: req.method ?? \"GET\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(job.result));\n}\n\nfunction handleQueueCancel(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n requestId: string,\n testId: string,\n journal: Journal,\n): void {\n const stateKey = `${testId}:${requestId}`;\n const job = falJobs.get(stateKey);\n\n if (!job) {\n journal.add({\n method: req.method ?? \"DELETE\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"NOT_FOUND\" }));\n return;\n }\n\n // Since we complete immediately, cancellation always returns ALREADY_COMPLETED\n journal.add({\n method: req.method ?? \"DELETE\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ALREADY_COMPLETED\" }));\n}\n\nasync function handleSyncRun(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n body: string,\n pathname: string,\n modelId: string,\n fixtures: Fixture[],\n defaults: HandlerDefaults,\n matchCounts: Map<Fixture, number>,\n journal: Journal,\n): Promise<void> {\n let parsed: Record<string, unknown> = {};\n if (body.trim()) {\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: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: `Malformed JSON: ${detail}`, type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n }\n\n const prompt =\n (typeof parsed.prompt === \"string\" ? parsed.prompt : null) ??\n (typeof parsed.text === \"string\" ? parsed.text : null) ??\n \"\";\n\n const syntheticReq: ChatCompletionRequest = {\n model: modelId,\n messages: [{ role: \"user\", content: prompt }],\n _endpointType: \"fal-audio\",\n };\n\n const fixture = matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, getTestId(req));\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n {\n method: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: {},\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: {\n message: \"Strict mode: no fixture matched\",\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 \"fal\",\n pathname,\n fixtures,\n defaults,\n body,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\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: req.method ?? \"POST\",\n path: pathname,\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 res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\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 if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(serializeErrorResponse(response));\n return;\n }\n\n if (!isAudioResponse(response)) {\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n const result = audioToFalFile(response);\n\n journal.add({\n method: req.method ?? \"POST\",\n path: pathname,\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(JSON.stringify(result));\n}\n"],"mappings":"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"}
|
package/dist/fal-audio.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fal-audio.d.cts","names":[],"sources":["../src/fal-audio.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"fal-audio.d.cts","names":[],"sources":["../src/fal-audio.ts"],"sourcesContent":[],"mappings":";;;;;;iBAoKsB,cAAA,MACf,IAAA,CAAK,sBACL,IAAA,CAAK,0DAGA,qBACA,0BACD,UACR"}
|
package/dist/fal-audio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fal-audio.d.ts","names":[],"sources":["../src/fal-audio.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"fal-audio.d.ts","names":[],"sources":["../src/fal-audio.ts"],"sourcesContent":[],"mappings":";;;;;;iBAoKsB,cAAA,MACf,IAAA,CAAK,sBACL,IAAA,CAAK,0DAGA,qBACA,0BACD,UACR"}
|