@copilotkit/aimock 1.42.1 → 1.44.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 +65 -0
- package/README.md +108 -16
- package/dist/agui-handler.d.ts.map +1 -1
- 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 +44 -12
- 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 +46 -14
- 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 +625 -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 +616 -74
- package/dist/chaos.js.map +1 -1
- package/dist/cli.cjs +131 -30
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +132 -31
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +37 -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 +39 -11
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.cjs +1 -1
- package/dist/config-loader.js +1 -1
- package/dist/constants.cjs +8 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +6 -2
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +8 -1
- package/dist/constants.js.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/echo-text.cjs +65 -0
- package/dist/echo-text.cjs.map +1 -0
- package/dist/echo-text.d.cts +22 -0
- package/dist/echo-text.d.cts.map +1 -0
- package/dist/echo-text.d.ts +22 -0
- package/dist/echo-text.d.ts.map +1 -0
- package/dist/echo-text.js +65 -0
- package/dist/echo-text.js.map +1 -0
- 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 +26 -5
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +27 -6
- 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 +1069 -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 +1056 -0
- package/dist/files.js.map +1 -0
- package/dist/fine-tuning.cjs +1033 -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 +1026 -0
- package/dist/fine-tuning.js.map +1 -0
- package/dist/fixture-loader-services.cjs +116 -0
- package/dist/fixture-loader-services.cjs.map +1 -0
- package/dist/fixture-loader-services.d.cts +48 -0
- package/dist/fixture-loader-services.d.cts.map +1 -0
- package/dist/fixture-loader-services.d.ts +48 -0
- package/dist/fixture-loader-services.d.ts.map +1 -0
- package/dist/fixture-loader-services.js +114 -0
- package/dist/fixture-loader-services.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 +131 -5
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +131 -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 +44 -4
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +46 -6
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +51 -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 +53 -9
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +19 -8
- 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 +21 -10
- 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 +497 -10
- 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 +487 -12
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +57 -125
- 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 +58 -126
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +71 -9
- package/dist/index.d.cts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +21 -11
- package/dist/jest.cjs +24 -12
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +6 -3
- package/dist/jest.d.cts.map +1 -1
- package/dist/jest.d.ts +6 -3
- package/dist/jest.d.ts.map +1 -1
- package/dist/jest.js +25 -13
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +61 -4
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +60 -3
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +60 -3
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +61 -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 +132 -49
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +51 -5
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +51 -5
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +133 -50
- package/dist/llmock.js.map +1 -1
- package/dist/mcp-fakes-mount.cjs +216 -0
- package/dist/mcp-fakes-mount.cjs.map +1 -0
- package/dist/mcp-fakes-mount.js +210 -0
- package/dist/mcp-fakes-mount.js.map +1 -0
- package/dist/mcp-fakes.cjs +1619 -0
- package/dist/mcp-fakes.cjs.map +1 -0
- package/dist/mcp-fakes.d.cts +101 -0
- package/dist/mcp-fakes.d.cts.map +1 -0
- package/dist/mcp-fakes.d.ts +101 -0
- package/dist/mcp-fakes.d.ts.map +1 -0
- package/dist/mcp-fakes.js +1614 -0
- package/dist/mcp-fakes.js.map +1 -0
- package/dist/mcp-handler.cjs +331 -17
- package/dist/mcp-handler.cjs.map +1 -1
- package/dist/mcp-handler.js +330 -18
- package/dist/mcp-handler.js.map +1 -1
- package/dist/mcp-mock.cjs +217 -49
- package/dist/mcp-mock.cjs.map +1 -1
- package/dist/mcp-mock.d.cts +66 -1
- package/dist/mcp-mock.d.cts.map +1 -1
- package/dist/mcp-mock.d.ts +66 -1
- package/dist/mcp-mock.d.ts.map +1 -1
- package/dist/mcp-mock.js +218 -50
- package/dist/mcp-mock.js.map +1 -1
- package/dist/mcp-stub.cjs +5 -1
- package/dist/mcp-stub.d.cts +3 -1
- package/dist/mcp-stub.d.ts +3 -1
- package/dist/mcp-stub.js +3 -1
- package/dist/mcp-types.d.cts +6 -0
- package/dist/mcp-types.d.ts +6 -0
- package/dist/message-text.cjs +192 -0
- package/dist/message-text.cjs.map +1 -0
- package/dist/message-text.d.cts +31 -0
- package/dist/message-text.d.cts.map +1 -0
- package/dist/message-text.d.ts +31 -0
- package/dist/message-text.d.ts.map +1 -0
- package/dist/message-text.js +184 -0
- package/dist/message-text.js.map +1 -0
- package/dist/messages.cjs +49 -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 +51 -9
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +278 -45
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts +17 -7
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts +17 -7
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +270 -29
- 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 +10 -6
- 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 +11 -7
- package/dist/ollama.js.map +1 -1
- package/dist/openapi.cjs +3405 -0
- package/dist/openapi.cjs.map +1 -0
- package/dist/openapi.d.cts +30 -0
- package/dist/openapi.d.cts.map +1 -0
- package/dist/openapi.d.ts +30 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +3404 -0
- package/dist/openapi.js.map +1 -0
- package/dist/openrouter-video.cjs +9 -9
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +10 -10
- package/dist/openrouter-video.js.map +1 -1
- package/dist/recorder.cjs +54 -10
- 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 +52 -12
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +47 -7
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +48 -9
- package/dist/responses.js.map +1 -1
- package/dist/route-registry.cjs +951 -0
- package/dist/route-registry.cjs.map +1 -0
- package/dist/route-registry.d.cts +33 -0
- package/dist/route-registry.d.cts.map +1 -0
- package/dist/route-registry.d.ts +33 -0
- package/dist/route-registry.d.ts.map +1 -0
- package/dist/route-registry.js +866 -0
- package/dist/route-registry.js.map +1 -0
- package/dist/router.cjs +21 -34
- 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 +21 -35
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +1252 -777
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +5 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +5 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1185 -710
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +6 -4
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +7 -5
- package/dist/speech.js.map +1 -1
- package/dist/suite.cjs +1 -1
- package/dist/suite.js +1 -1
- package/dist/transcription.cjs +6 -6
- 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 +7 -7
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs +18 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +320 -17
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +320 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/validate-cli.cjs +983 -0
- package/dist/validate-cli.cjs.map +1 -0
- package/dist/validate-cli.js +982 -0
- package/dist/validate-cli.js.map +1 -0
- package/dist/vector-stores.cjs +1180 -0
- package/dist/vector-stores.cjs.map +1 -0
- package/dist/vector-stores.d.cts +106 -0
- package/dist/vector-stores.d.cts.map +1 -0
- package/dist/vector-stores.d.ts +106 -0
- package/dist/vector-stores.d.ts.map +1 -0
- package/dist/vector-stores.js +1164 -0
- package/dist/vector-stores.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 +23 -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 +24 -5
- package/dist/video.js.map +1 -1
- package/dist/vitest.cjs +23 -11
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +5 -2
- package/dist/vitest.d.cts.map +1 -1
- package/dist/vitest.d.ts +5 -2
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +25 -13
- 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.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.map +1 -1
- package/dist/ws-realtime.js +46 -2
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +16 -4
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.js +16 -4
- package/dist/ws-responses.js.map +1 -1
- 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 +4 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-stores.js","names":[],"sources":["../src/vector-stores.ts"],"sourcesContent":["/**\n * OpenAI Vector Stores API mock.\n *\n * Covers vector-store lifecycle and direct search for uploaded `Files`:\n *\n * - `POST /v1/vector_stores` (create)\n * - `GET /v1/vector_stores` (list)\n * - `GET /v1/vector_stores/{id}` (retrieve)\n * - `POST /v1/vector_stores/{id}` (modify)\n * - `DELETE /v1/vector_stores/{id}` (delete)\n * - `POST /v1/vector_stores/{id}/files` (attach a file)\n * - `GET /v1/vector_stores/{id}/files` (list attached files)\n * - `GET /v1/vector_stores/{id}/files/{file_id}` (retrieve an attached file)\n * - `DELETE /v1/vector_stores/{id}/files/{file_id}` (detach a file)\n * - `POST /v1/vector_stores/{id}/file_batches` (create a file batch)\n * - `GET /v1/vector_stores/{id}/file_batches/{batch_id}` (retrieve a batch)\n * - `POST /v1/vector_stores/{id}/file_batches/{batch_id}/cancel` (cancel)\n * - `GET /v1/vector_stores/{id}/file_batches/{batch_id}/files` (batch files)\n * - `POST /v1/vector_stores/{id}/search` (deterministic file search)\n *\n * Supports offline upload → vector-store → direct search tests. Attach a\n * `file-…` id, poll it to `completed`, then call the search endpoint.\n * This mock does not execute hosted `file_search` tools in Responses or\n * Assistants. Responses requests need separate matching fixtures; vector-store\n * contents do not automatically produce model responses.\n *\n * Lifecycle (deterministic poll progression, like the batches mock):\n *\n * store: in_progress → completed (completed at once when no file is\n * pending; `expired` once `expires_at` passes)\n * file: in_progress → completed | failed | cancelled (first retrieve after\n * attach shows `in_progress`, the second lands the outcome)\n * batch: in_progress → completed | failed | cancelled (same two-poll rule;\n * `cancel` on a live batch answers `cancelling`, next retrieve is\n * `cancelled`)\n *\n * Outcome control: send `X-AIMock-Vector-Outcome: completed | failed |\n * cancelled` on `POST …/files` or `POST …/file_batches` (default\n * `completed`, unknown values 400). Same header family as\n * `X-AIMock-Batch-Outcome`.\n *\n * Files must exist in the Files store (`GET /v1/files/{id}` would 200 for\n * them): attaching an unknown `file_id` is a 404 naming the file, so a suite\n * that forgets the upload step fails loudly instead of indexing a ghost.\n * `usage_bytes` is the real byte length from the Files store; a file the\n * store has no bytes for reports `0`.\n *\n * Search is deterministic, not semantic: only `completed` files are searched,\n * results are ordered by a stable hash of `query + file_id` so the same query\n * always ranks the same way, and every result carries its file's name plus a\n * canned text snippet quoting the query. Direct search supports tests of top-k,\n * score thresholds, and empty-store behaviour. It does not measure semantic\n * relevance.\n *\n * State is in-memory per process and cleared by the full reset path.\n * Every branch journals with `service: \"vector-stores\"` and runs through the\n * chaos gate so fault-injection suites can target this surface.\n *\n * Wire shapes follow the vendored `openai` SDK 4.x\n * (`resources/vector-stores/…`) and the `openai/openai-openapi` spec where\n * they agree (`id`, `object`, `created_at`, `name`, `usage_bytes`,\n * `file_counts`, `status`, `metadata`, `expires_after`/`expires_at`,\n * `last_active_at`, list envelopes with `object: \"list\"`, `data`,\n * `first_id`, `last_id`, `has_more`). Timestamps are Unix seconds. Anything\n * the sources leave unspecified (poll counts, the exact 400 texts, the\n * `cancelled` landing without a cancel call, search scoring) is this mock's\n * own contract and documented as such.\n */\n\nimport type * as http from \"node:http\";\nimport { randomBytes } from \"node:crypto\";\nimport { flattenHeaders, isJsonObject, parseStrictIntegerText } from \"./helpers.js\";\nimport { applyChaosAsync, type ChaosAsyncOutcome } from \"./chaos.js\";\nimport { readMetadata } from \"./fine-tuning.js\";\nimport { getStoredFileBytes, getStoredFileName } from \"./files.js\";\nimport type { ChaosDefaults } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\n\nexport type VectorStoreStatus = \"expired\" | \"in_progress\" | \"completed\";\nexport type VectorStoreFileStatus = \"in_progress\" | \"completed\" | \"failed\" | \"cancelled\";\nexport type VectorFileBatchStatus =\n | \"in_progress\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\"\n | \"cancelling\";\n\nexport interface VectorStoreObject {\n id: string;\n object: \"vector_store\";\n created_at: number;\n name: string;\n usage_bytes: number;\n file_counts: {\n in_progress: number;\n completed: number;\n failed: number;\n cancelled: number;\n total: number;\n };\n status: VectorStoreStatus;\n metadata: Record<string, string> | null;\n expires_after?: { anchor: \"last_active_at\"; days: number };\n expires_at?: number | null;\n last_active_at?: number | null;\n chunking_strategy?: { type: \"auto\" } | { type: \"static\"; static: Record<string, number> };\n}\n\ntype FileAttributes = Record<string, string | number | boolean>;\n\ntype AttributeFilter =\n | {\n type: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\";\n key: string;\n value: string | number | boolean;\n }\n | { type: \"and\" | \"or\"; filters: AttributeFilter[] };\n\nexport interface VectorStoreFileObject {\n id: string;\n object: \"vector_store.file\";\n attributes: FileAttributes | null;\n created_at: number;\n vector_store_id: string;\n status: VectorStoreFileStatus;\n usage_bytes: number;\n chunking_strategy?: { type: \"static\"; static: Record<string, number> };\n last_error?: { code: string; message: string } | null;\n}\n\nexport interface VectorFileBatchObject {\n id: string;\n object: \"vector_store.file_batch\";\n created_at: number;\n vector_store_id: string;\n status: VectorFileBatchStatus;\n file_counts: {\n in_progress: number;\n completed: number;\n failed: number;\n cancelled: number;\n total: number;\n };\n}\n\nexport interface VectorSearchResult {\n attributes: FileAttributes | null;\n file_id: string;\n filename: string;\n score: number;\n content: { type: \"text\"; text: string }[];\n}\n\nconst stores = new Map<string, VectorStoreObject>();\nconst storeFiles = new Map<string, VectorStoreFileObject>();\nconst storePolls = new Map<string, number>();\nconst fileOutcomes = new Map<string, VectorStoreFileStatus>();\nconst fileBatches = new Map<string, VectorFileBatchObject>();\nconst batchPolls = new Map<string, number>();\nconst batchOutcomes = new Map<string, VectorStoreFileStatus>();\n// Keep attachment identity: a detached file ID may later be attached again.\nconst batchMembers = new Map<string, VectorStoreFileObject[]>();\nlet lastStamp = 0;\n\nexport function clearVectorStoreStore(): void {\n stores.clear();\n storeFiles.clear();\n storePolls.clear();\n fileOutcomes.clear();\n fileBatches.clear();\n batchPolls.clear();\n batchOutcomes.clear();\n batchMembers.clear();\n lastStamp = 0;\n}\n\n/** Remove every vector attachment when its underlying uploaded File is deleted. */\nexport function removeVectorStoreFile(fileId: string): void {\n const affectedStores = new Set<string>();\n for (const [key, entry] of storeFiles) {\n if (entry.id !== fileId) continue;\n storeFiles.delete(key);\n storePolls.delete(key);\n fileOutcomes.delete(key);\n affectedStores.add(entry.vector_store_id);\n }\n for (const [batchId, members] of batchMembers) {\n const remaining = members.filter((entry) => entry.id !== fileId);\n if (remaining.length === members.length) continue;\n batchMembers.set(batchId, remaining);\n const batch = fileBatches.get(batchId);\n if (!batch) continue;\n batch.file_counts = batchCounts(batchId);\n if (remaining.length === 0 && !TERMINAL_BATCH_STATUSES.has(batch.status)) {\n batch.status = batch.status === \"cancelling\" ? \"cancelled\" : \"completed\";\n batchPolls.delete(batchId);\n batchOutcomes.delete(batchId);\n }\n affectedStores.add(batch.vector_store_id);\n }\n for (const storeId of affectedStores) {\n const store = stores.get(storeId);\n if (store) refreshStoreStatus(store);\n }\n}\n\nconst TERMINAL_FILE_STATUSES = new Set<VectorStoreFileStatus>([\"completed\", \"failed\", \"cancelled\"]);\nconst TERMINAL_BATCH_STATUSES = new Set<VectorFileBatchStatus>([\n \"completed\",\n \"failed\",\n \"cancelled\",\n]);\nconst OUTCOMES = new Set([\"completed\", \"failed\", \"cancelled\"]);\nconst OUTCOME_HEADER = \"x-aimock-vector-outcome\";\nconst DEFAULT_PAGE_LIMIT = 20;\nconst MAX_PAGE_LIMIT = 100;\n\nfunction stamp(): number {\n lastStamp = Math.max(Math.floor(Date.now() / 1000), lastStamp);\n return lastStamp;\n}\n\nfunction underscoreId(prefix: string): string {\n return `${prefix}_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nfunction invalid(message: string): { error: { message: string; type: string } } {\n return { error: { message, type: \"invalid_request_error\" } };\n}\n\nfunction writeJson(\n res: http.ServerResponse,\n status: number,\n payload: unknown,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): void {\n setCorsHeaders(res);\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(payload));\n}\n\ntype Defaults = { logger: Logger; chaos?: ChaosDefaults; registry?: MetricsRegistry };\n\nfunction journalVs(\n journal: Journal,\n method: string,\n path: string,\n headers: Record<string, string>,\n status: number,\n): void {\n journal.add({\n method,\n path,\n headers,\n body: null,\n service: \"vector-stores\",\n response: { status, fixture: null, source: \"internal\" },\n });\n}\n\nasync function chaosHit(\n req: http.IncomingMessage,\n journal: Journal,\n defaults: Defaults,\n method: string,\n path: string,\n res: http.ServerResponse,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<ChaosAsyncOutcome> {\n setCorsHeaders(res);\n return await applyChaosAsync(\n res,\n null,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n {\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"vector-stores\",\n },\n \"internal\",\n defaults.registry,\n defaults.logger,\n );\n}\n\nfunction fileKey(storeId: string, fileId: string): string {\n return `${storeId}:${fileId}`;\n}\n\nfunction touch(store: VectorStoreObject): void {\n refreshStoreStatus(store);\n if (store.status === \"expired\") return;\n const now = stamp();\n store.last_active_at = now;\n if (store.expires_after) {\n store.expires_at = now + store.expires_after.days * 86400;\n }\n refreshStoreStatus(store);\n}\n\nfunction refreshStoreStatus(store: VectorStoreObject): void {\n const now = Math.floor(Date.now() / 1000);\n const expired =\n store.expires_at !== undefined && store.expires_at !== null && now >= store.expires_at;\n const files = [...storeFiles.values()].filter((f) => f.vector_store_id === store.id);\n const pending = files.filter((f) => f.status === \"in_progress\").length;\n const batchesLive = [...fileBatches.values()].filter(\n (b) =>\n b.vector_store_id === store.id && (b.status === \"in_progress\" || b.status === \"cancelling\"),\n ).length;\n store.status = expired ? \"expired\" : pending + batchesLive > 0 ? \"in_progress\" : \"completed\";\n let usage = 0;\n let inProgress = 0;\n let completed = 0;\n let failed = 0;\n let cancelled = 0;\n for (const f of files) {\n if (f.status === \"completed\") usage += f.usage_bytes;\n if (f.status === \"in_progress\") inProgress += 1;\n else if (f.status === \"completed\") completed += 1;\n else if (f.status === \"failed\") failed += 1;\n else cancelled += 1;\n }\n store.usage_bytes = usage;\n store.file_counts = {\n in_progress: inProgress,\n completed,\n failed,\n cancelled,\n total: files.length,\n };\n}\n\nfunction readExpiresAfter(\n value: unknown,\n):\n | { ok: true; value: { anchor: \"last_active_at\"; days: number } | null }\n | { ok: false; message: string } {\n if (value === undefined) return { ok: true, value: null };\n if (!isJsonObject(value)) {\n return { ok: false, message: \"Invalid parameter: 'expires_after' must be an object\" };\n }\n if (value[\"anchor\"] !== \"last_active_at\") {\n return {\n ok: false,\n message: \"Invalid parameter: 'expires_after.anchor' must be 'last_active_at'\",\n };\n }\n const days = value[\"days\"];\n if (typeof days !== \"number\" || !Number.isInteger(days) || days < 1 || days > 365) {\n return {\n ok: false,\n message: \"Invalid parameter: 'expires_after.days' must be an integer between 1 and 365\",\n };\n }\n return { ok: true, value: { anchor: \"last_active_at\", days } };\n}\n\nfunction readChunkingStrategy(\n value: unknown,\n):\n | { ok: true; value: VectorStoreObject[\"chunking_strategy\"] | null }\n | { ok: false; message: string } {\n if (value === undefined) return { ok: true, value: null };\n if (!isJsonObject(value)) {\n return { ok: false, message: \"Invalid parameter: 'chunking_strategy' must be an object\" };\n }\n if (value[\"type\"] === \"auto\") return { ok: true, value: { type: \"auto\" } };\n if (value[\"type\"] === \"static\") {\n const inner = value[\"static\"];\n if (!isJsonObject(inner)) {\n return {\n ok: false,\n message: \"Invalid parameter: 'chunking_strategy.static' must be an object\",\n };\n }\n const maxTokens = inner[\"max_chunk_size_tokens\"];\n const overlap = inner[\"chunk_overlap_tokens\"];\n if (\n typeof maxTokens !== \"number\" ||\n !Number.isInteger(maxTokens) ||\n maxTokens < 100 ||\n maxTokens > 4096\n ) {\n return {\n ok: false,\n message:\n \"Invalid parameter: 'chunking_strategy.static.max_chunk_size_tokens' must be an integer between 100 and 4096\",\n };\n }\n if (\n typeof overlap !== \"number\" ||\n !Number.isInteger(overlap) ||\n overlap < 0 ||\n overlap > 2048 ||\n overlap * 2 > maxTokens\n ) {\n return {\n ok: false,\n message:\n \"Invalid parameter: 'chunking_strategy.static.chunk_overlap_tokens' must be an integer between 0 and 2048 and at most half of max_chunk_size_tokens\",\n };\n }\n return {\n ok: true,\n value: {\n type: \"static\",\n static: { max_chunk_size_tokens: maxTokens, chunk_overlap_tokens: overlap },\n },\n };\n }\n return {\n ok: false,\n message: \"Invalid parameter: 'chunking_strategy.type' must be 'auto' or 'static'\",\n };\n}\n\nfunction isAttributeValue(value: unknown): value is string | number | boolean {\n return (\n typeof value === \"string\" ||\n typeof value === \"boolean\" ||\n (typeof value === \"number\" && Number.isFinite(value))\n );\n}\n\nfunction readAttributes(\n value: unknown,\n): { ok: true; value: FileAttributes | null } | { ok: false; message: string } {\n if (value === undefined || value === null) return { ok: true, value: null };\n if (!isJsonObject(value) || Object.keys(value).length > 16) {\n return {\n ok: false,\n message: \"Invalid parameter: 'attributes' must be an object with at most 16 pairs or null\",\n };\n }\n const entries: [string, string | number | boolean][] = [];\n for (const [key, entry] of Object.entries(value)) {\n if (\n [...key].length > 64 ||\n !isAttributeValue(entry) ||\n (typeof entry === \"string\" && [...entry].length > 512)\n ) {\n return {\n ok: false,\n message:\n \"Invalid parameter: 'attributes' keys must be at most 64 characters and values must be strings of at most 512 characters, finite numbers or booleans\",\n };\n }\n entries.push([key, entry]);\n }\n return { ok: true, value: Object.fromEntries(entries) };\n}\n\n// Bound parsing and the later matching traversal of the validated filter tree.\nconst MAX_ATTRIBUTE_FILTER_DEPTH = 64;\n\nfunction readAttributeFilter(\n value: unknown,\n depth = 0,\n): { ok: true; value: AttributeFilter | null } | { ok: false; message: string } {\n if (depth > MAX_ATTRIBUTE_FILTER_DEPTH) {\n return {\n ok: false,\n message: `Invalid parameter: 'filters' nesting must not exceed ${MAX_ATTRIBUTE_FILTER_DEPTH} levels`,\n };\n }\n if (value === undefined) return { ok: true, value: null };\n const error = {\n ok: false,\n message:\n \"Invalid parameter: 'filters' must be a comparison (eq, ne, gt, gte, lt, lte) with key and scalar value, or an and/or filter with an array of filters\",\n } as const;\n if (!isJsonObject(value)) return error;\n const type = value[\"type\"];\n if (type === \"and\" || type === \"or\") {\n if (!Array.isArray(value[\"filters\"])) return error;\n const filters: AttributeFilter[] = [];\n for (const item of value[\"filters\"]) {\n const child = readAttributeFilter(item, depth + 1);\n if (!child.ok) return child;\n if (child.value === null) return error;\n filters.push(child.value);\n }\n return { ok: true, value: { type, filters } };\n }\n const key = value[\"key\"];\n const operand = value[\"value\"];\n if (\n (type === \"eq\" ||\n type === \"ne\" ||\n type === \"gt\" ||\n type === \"gte\" ||\n type === \"lt\" ||\n type === \"lte\") &&\n typeof key === \"string\" &&\n isAttributeValue(operand)\n ) {\n return { ok: true, value: { type, key, value: operand } };\n }\n return error;\n}\n\nfunction matchesAttributeFilter(\n attributes: FileAttributes | null,\n filter: AttributeFilter,\n): boolean {\n if (filter.type === \"and\")\n return filter.filters.every((child) => matchesAttributeFilter(attributes, child));\n if (filter.type === \"or\")\n return filter.filters.some((child) => matchesAttributeFilter(attributes, child));\n if (!(\"key\" in filter) || attributes === null || !Object.hasOwn(attributes, filter.key))\n return false;\n const actual = attributes[filter.key];\n if (typeof actual !== typeof filter.value) return false;\n switch (filter.type) {\n case \"eq\":\n return actual === filter.value;\n case \"ne\":\n return actual !== filter.value;\n case \"gt\":\n return actual > filter.value;\n case \"gte\":\n return actual >= filter.value;\n case \"lt\":\n return actual < filter.value;\n case \"lte\":\n return actual <= filter.value;\n }\n}\n\nfunction readFileIds(\n value: unknown,\n): { ok: true; value: string[] } | { ok: false; message: string } {\n if (value === undefined) return { ok: true, value: [] };\n if (!Array.isArray(value)) {\n return { ok: false, message: \"Invalid parameter: 'file_ids' must be an array of strings\" };\n }\n if (value.length > 2000) {\n return { ok: false, message: \"Invalid parameter: 'file_ids' must contain at most 2000 files\" };\n }\n for (const entry of value) {\n if (typeof entry !== \"string\" || entry.length === 0) {\n return { ok: false, message: \"Invalid parameter: 'file_ids' must be an array of strings\" };\n }\n }\n return { ok: true, value: value as string[] };\n}\n\nfunction readOutcome(\n req: http.IncomingMessage,\n): { ok: true; value: VectorStoreFileStatus } | { ok: false; message: string } {\n const raw = req.headers[OUTCOME_HEADER];\n const text = (Array.isArray(raw) ? raw[0] : raw)?.trim().toLowerCase();\n if (text === undefined || text === \"\") return { ok: true, value: \"completed\" };\n if (!OUTCOMES.has(text)) {\n return {\n ok: false,\n message: `Invalid ${OUTCOME_HEADER} '${text}'. Expected one of: ${[...OUTCOMES].join(\", \")}`,\n };\n }\n return { ok: true, value: text as VectorStoreFileStatus };\n}\n\nfunction queryParams(url: string | undefined): URLSearchParams {\n const target = url ?? \"/\";\n const start = target.indexOf(\"?\");\n return new URLSearchParams(start === -1 ? \"\" : target.slice(start + 1));\n}\n\nfunction singleParam(\n params: URLSearchParams,\n name: string,\n): { ok: true; value: string | null } | { ok: false; message: string } {\n const all = params.getAll(name);\n if (all.length > 1) {\n return {\n ok: false,\n message: `Invalid parameter: '${name}' was given ${all.length} times; it takes a single value`,\n };\n }\n return { ok: true, value: all.length === 0 ? null : all[0] };\n}\n\nexport interface PageResult<T> {\n ok: boolean;\n page?: {\n object: \"list\";\n data: T[];\n first_id: string | null;\n last_id: string | null;\n has_more: boolean;\n };\n message?: string;\n}\n\nfunction paginateOrdered<T extends { id: string; created_at: number }>(\n itemsNewestFirst: T[],\n url: string | undefined,\n): PageResult<T> {\n const params = queryParams(url);\n const readLimit = singleParam(params, \"limit\");\n if (!readLimit.ok) return { ok: false, message: readLimit.message };\n const readOrder = singleParam(params, \"order\");\n if (!readOrder.ok) return { ok: false, message: readOrder.message };\n const readAfter = singleParam(params, \"after\");\n if (!readAfter.ok) return { ok: false, message: readAfter.message };\n const readBefore = singleParam(params, \"before\");\n if (!readBefore.ok) return { ok: false, message: readBefore.message };\n let limit = DEFAULT_PAGE_LIMIT;\n if (readLimit.value !== null) {\n const n = parseStrictIntegerText(readLimit.value);\n if (n === null || n < 1 || n > MAX_PAGE_LIMIT) {\n return {\n ok: false,\n message: `Invalid parameter: 'limit' must be an integer between 1 and ${MAX_PAGE_LIMIT}, got '${readLimit.value}'`,\n };\n }\n limit = n;\n }\n const order = readOrder.value ?? \"desc\";\n if (order !== \"asc\" && order !== \"desc\") {\n return { ok: false, message: \"Invalid parameter: 'order' must be 'asc' or 'desc'\" };\n }\n if (readAfter.value !== null && readBefore.value !== null) {\n return { ok: false, message: \"Invalid parameter: 'after' and 'before' are mutually exclusive\" };\n }\n const ordered = order === \"desc\" ? itemsNewestFirst : [...itemsNewestFirst].reverse();\n let start = 0;\n if (readAfter.value !== null) {\n const idx = ordered.findIndex((it) => it.id === readAfter.value);\n if (idx === -1) {\n return {\n ok: false,\n message: `Invalid parameter: 'after' is not a known cursor: '${readAfter.value}'`,\n };\n }\n start = idx + 1;\n } else if (readBefore.value !== null) {\n const idx = ordered.findIndex((it) => it.id === readBefore.value);\n if (idx === -1) {\n return {\n ok: false,\n message: `Invalid parameter: 'before' is not a known cursor: '${readBefore.value}'`,\n };\n }\n start = Math.max(0, idx - limit);\n const data = ordered.slice(start, idx);\n return {\n ok: true,\n page: {\n object: \"list\",\n data,\n first_id: data[0]?.id ?? null,\n last_id: data[data.length - 1]?.id ?? null,\n has_more: start > 0,\n },\n };\n }\n const rest = ordered.slice(start);\n const data = rest.slice(0, limit);\n return {\n ok: true,\n page: {\n object: \"list\",\n data,\n first_id: data[0]?.id ?? null,\n last_id: data[data.length - 1]?.id ?? null,\n has_more: rest.length > limit,\n },\n };\n}\n\nfunction parseJsonBody(raw: string): { ok: true; value: unknown } | { ok: false; message: string } {\n if (raw.trim() === \"\") return { ok: true, value: {} };\n try {\n return { ok: true, value: JSON.parse(raw) as unknown };\n } catch (err) {\n return {\n ok: false,\n message: `Malformed JSON: ${err instanceof Error ? err.message : \"unknown\"}`,\n };\n }\n}\n\nfunction attachFile(\n store: VectorStoreObject,\n fileId: string,\n chunking: VectorStoreObject[\"chunking_strategy\"],\n outcome: VectorStoreFileStatus,\n attributes: FileAttributes | null = null,\n): VectorStoreFileObject {\n const bytes = getStoredFileBytes(fileId);\n const now = stamp();\n const entry: VectorStoreFileObject = {\n id: fileId,\n object: \"vector_store.file\",\n attributes,\n created_at: now,\n vector_store_id: store.id,\n status: \"in_progress\",\n usage_bytes: bytes?.length ?? 0,\n last_error: null,\n };\n if (chunking) {\n entry.chunking_strategy =\n chunking.type === \"auto\"\n ? {\n type: \"static\",\n static: { max_chunk_size_tokens: 800, chunk_overlap_tokens: 400 },\n }\n : chunking;\n }\n storeFiles.set(fileKey(store.id, fileId), entry);\n storePolls.set(fileKey(store.id, fileId), 0);\n fileOutcomes.set(fileKey(store.id, fileId), outcome);\n touch(store);\n return entry;\n}\n\nfunction advanceFile(entry: VectorStoreFileObject): VectorStoreFileObject {\n if (TERMINAL_FILE_STATUSES.has(entry.status)) return entry;\n const key = fileKey(entry.vector_store_id, entry.id);\n const polls = (storePolls.get(key) ?? 0) + 1;\n storePolls.set(key, polls);\n if (polls >= 2) {\n const outcome = fileOutcomes.get(key) ?? \"completed\";\n entry.status = outcome;\n if (outcome === \"failed\") {\n entry.last_error = {\n code: \"mock_ingest_failed\",\n message: \"Mock ingestion failed for this file\",\n };\n } else {\n entry.last_error = null;\n }\n }\n const store = stores.get(entry.vector_store_id);\n if (store) refreshStoreStatus(store);\n return entry;\n}\n\nfunction batchCounts(batchId: string): VectorFileBatchObject[\"file_counts\"] {\n const members = batchMembers.get(batchId) ?? [];\n let inProgress = 0;\n let completed = 0;\n let failed = 0;\n let cancelled = 0;\n for (const entry of members) {\n if (entry.status === \"in_progress\") inProgress += 1;\n else if (entry.status === \"completed\") completed += 1;\n else if (entry.status === \"failed\") failed += 1;\n else cancelled += 1;\n }\n return { in_progress: inProgress, completed, failed, cancelled, total: members.length };\n}\n\nfunction advanceBatch(batch: VectorFileBatchObject): VectorFileBatchObject {\n if (TERMINAL_BATCH_STATUSES.has(batch.status)) {\n batch.file_counts = batchCounts(batch.id);\n return batch;\n }\n if (batch.status === \"cancelling\") {\n batch.status = \"cancelled\";\n for (const entry of batchMembers.get(batch.id) ?? []) {\n if (entry.status === \"in_progress\") entry.status = \"cancelled\";\n }\n batch.file_counts = batchCounts(batch.id);\n const store = stores.get(batch.vector_store_id);\n if (store) refreshStoreStatus(store);\n return batch;\n }\n const polls = (batchPolls.get(batch.id) ?? 0) + 1;\n batchPolls.set(batch.id, polls);\n if (polls === 1) {\n batch.status = \"in_progress\";\n } else {\n const outcome = batchOutcomes.get(batch.id) ?? \"completed\";\n batch.status = outcome;\n for (const entry of batchMembers.get(batch.id) ?? []) {\n if (entry.status === \"in_progress\") {\n entry.status = outcome === \"completed\" ? \"completed\" : outcome;\n if (outcome === \"failed\") {\n entry.last_error = {\n code: \"mock_ingest_failed\",\n message: \"Mock ingestion failed for this file\",\n };\n }\n }\n }\n }\n batch.file_counts = batchCounts(batch.id);\n const store = stores.get(batch.vector_store_id);\n if (store) refreshStoreStatus(store);\n return batch;\n}\n\nfunction scoreFor(query: string, fileId: string): number {\n let h = 2166136261;\n const text = `${query}::${fileId}`;\n for (let i = 0; i < text.length; i++) {\n h = Math.imul(h ^ text.charCodeAt(i), 16777619);\n }\n return ((h >>> 0) % 10000) / 10000;\n}\n\nexport async function handleVectorStoresCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? \"/v1/vector_stores\";\n const method = req.method ?? \"POST\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const parsed = parseJsonBody(raw);\n if (!parsed.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(parsed.message), setCorsHeaders);\n return;\n }\n if (!isJsonObject(parsed.value)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(\"Request body must be a JSON object\"), setCorsHeaders);\n return;\n }\n const body = parsed.value;\n if (body[\"name\"] !== undefined && typeof body[\"name\"] !== \"string\") {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(\"Invalid parameter: 'name' must be a string\"), setCorsHeaders);\n return;\n }\n const metadata = readMetadata(body[\"metadata\"]);\n if (!metadata.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(metadata.message), setCorsHeaders);\n return;\n }\n const expires = readExpiresAfter(body[\"expires_after\"]);\n if (!expires.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(expires.message), setCorsHeaders);\n return;\n }\n const chunking = readChunkingStrategy(body[\"chunking_strategy\"]);\n if (!chunking.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(chunking.message), setCorsHeaders);\n return;\n }\n const fileIds = readFileIds(body[\"file_ids\"]);\n if (!fileIds.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(fileIds.message), setCorsHeaders);\n return;\n }\n for (const fileId of fileIds.value) {\n if (getStoredFileBytes(fileId) === undefined) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such file: ${fileId}`), setCorsHeaders);\n return;\n }\n }\n const outcome = readOutcome(req);\n if (!outcome.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(outcome.message), setCorsHeaders);\n return;\n }\n const now = stamp();\n const id = underscoreId(\"vs\");\n const store: VectorStoreObject = {\n id,\n object: \"vector_store\",\n created_at: now,\n name: typeof body[\"name\"] === \"string\" ? body[\"name\"] : `vector-store-${id.slice(3, 9)}`,\n usage_bytes: 0,\n file_counts: { in_progress: 0, completed: 0, failed: 0, cancelled: 0, total: 0 },\n status: \"completed\",\n metadata: metadata.value,\n last_active_at: now,\n expires_at: null,\n };\n if (expires.value) {\n store.expires_after = expires.value;\n store.expires_at = now + expires.value.days * 86400;\n }\n if (chunking.value) store.chunking_strategy = chunking.value;\n stores.set(id, store);\n for (const fileId of fileIds.value) {\n attachFile(store, fileId, chunking.value ?? undefined, outcome.value);\n }\n refreshStoreStatus(store);\n defaults.logger.debug(`Vector stores mock: created ${id}`);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, store, setCorsHeaders);\n}\n\nexport async function handleVectorStoresList(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? \"/v1/vector_stores\";\n const method = req.method ?? \"GET\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n for (const store of stores.values()) refreshStoreStatus(store);\n const data = [...stores.values()].reverse();\n const result = paginateOrdered(data, req.url);\n if (!result.ok || !result.page) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(result.message ?? \"Invalid pagination\"), setCorsHeaders);\n return;\n }\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, result.page, setCorsHeaders);\n}\n\nexport async function handleVectorStoresRetrieve(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}`;\n const method = req.method ?? \"GET\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n touch(store);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, store, setCorsHeaders);\n}\n\nexport async function handleVectorStoresModify(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n raw: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}`;\n const method = req.method ?? \"POST\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const parsed = parseJsonBody(raw);\n if (!parsed.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(parsed.message), setCorsHeaders);\n return;\n }\n if (!isJsonObject(parsed.value)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(\"Request body must be a JSON object\"), setCorsHeaders);\n return;\n }\n const body = parsed.value;\n let name = store.name;\n let metadata = store.metadata;\n let expiresAfter = store.expires_after;\n if (body[\"name\"] !== undefined) {\n if (body[\"name\"] !== null && typeof body[\"name\"] !== \"string\") {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\"Invalid parameter: 'name' must be a string or null\"),\n setCorsHeaders,\n );\n return;\n }\n name = body[\"name\"] ?? \"\";\n }\n if (body[\"metadata\"] !== undefined) {\n const parsedMetadata = readMetadata(body[\"metadata\"]);\n if (!parsedMetadata.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(parsedMetadata.message), setCorsHeaders);\n return;\n }\n metadata = parsedMetadata.value;\n }\n if (body[\"expires_after\"] !== undefined) {\n if (body[\"expires_after\"] === null) {\n expiresAfter = undefined;\n } else {\n const expires = readExpiresAfter(body[\"expires_after\"]);\n if (!expires.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(expires.message), setCorsHeaders);\n return;\n }\n if (expires.value) {\n expiresAfter = expires.value;\n }\n }\n }\n // Commit only after every supplied field has passed validation.\n store.name = name;\n store.metadata = metadata;\n if (body[\"expires_after\"] !== undefined) {\n if (expiresAfter) {\n store.expires_after = expiresAfter;\n store.expires_at = stamp() + expiresAfter.days * 86400;\n } else {\n delete store.expires_after;\n store.expires_at = null;\n }\n }\n touch(store);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, store, setCorsHeaders);\n}\n\nexport async function handleVectorStoresDelete(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}`;\n const method = req.method ?? \"DELETE\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n stores.delete(storeId);\n for (const key of [...storeFiles.keys()]) {\n if (key.startsWith(`${storeId}:`)) {\n storeFiles.delete(key);\n storePolls.delete(key);\n fileOutcomes.delete(key);\n }\n }\n for (const [batchId, batch] of [...fileBatches.entries()]) {\n if (batch.vector_store_id === storeId) {\n fileBatches.delete(batchId);\n batchPolls.delete(batchId);\n batchOutcomes.delete(batchId);\n batchMembers.delete(batchId);\n }\n }\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(\n res,\n 200,\n { id: storeId, object: \"vector_store.deleted\", deleted: true },\n setCorsHeaders,\n );\n}\n\nexport async function handleVectorStoreFilesCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n raw: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/files`;\n const method = req.method ?? \"POST\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const parsed = parseJsonBody(raw);\n if (!parsed.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(parsed.message), setCorsHeaders);\n return;\n }\n if (!isJsonObject(parsed.value)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(\"Request body must be a JSON object\"), setCorsHeaders);\n return;\n }\n const fileId = parsed.value[\"file_id\"];\n if (typeof fileId !== \"string\" || fileId.length === 0) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\"Invalid parameter: 'file_id' must be a non-empty string\"),\n setCorsHeaders,\n );\n return;\n }\n if (getStoredFileBytes(fileId) === undefined) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such file: ${fileId}`), setCorsHeaders);\n return;\n }\n if (storeFiles.has(fileKey(storeId, fileId))) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(`File ${fileId} is already attached to vector store ${storeId}`),\n setCorsHeaders,\n );\n return;\n }\n const chunking = readChunkingStrategy(parsed.value[\"chunking_strategy\"]);\n if (!chunking.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(chunking.message), setCorsHeaders);\n return;\n }\n const attributes = readAttributes(parsed.value[\"attributes\"]);\n if (!attributes.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(attributes.message), setCorsHeaders);\n return;\n }\n const outcome = readOutcome(req);\n if (!outcome.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(outcome.message), setCorsHeaders);\n return;\n }\n const entry = attachFile(\n store,\n fileId,\n chunking.value ?? undefined,\n outcome.value,\n attributes.value,\n );\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, entry, setCorsHeaders);\n}\n\nexport async function handleVectorStoreFilesList(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/files`;\n const method = req.method ?? \"GET\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const params = queryParams(req.url);\n const readFilter = singleParam(params, \"filter\");\n if (!readFilter.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(readFilter.message), setCorsHeaders);\n return;\n }\n if (\n readFilter.value !== null &&\n !TERMINAL_FILE_STATUSES.has(readFilter.value as VectorStoreFileStatus) &&\n readFilter.value !== \"in_progress\"\n ) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\n \"Invalid parameter: 'filter' must be 'in_progress', 'completed', 'failed' or 'cancelled'\",\n ),\n setCorsHeaders,\n );\n return;\n }\n let data = [...storeFiles.values()]\n .filter((f) => f.vector_store_id === storeId)\n .sort((a, b) => b.created_at - a.created_at || (a.id < b.id ? 1 : -1));\n if (readFilter.value !== null) data = data.filter((f) => f.status === readFilter.value);\n const result = paginateOrdered(data, req.url);\n if (!result.ok || !result.page) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(result.message ?? \"Invalid pagination\"), setCorsHeaders);\n return;\n }\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, result.page, setCorsHeaders);\n}\n\nexport async function handleVectorStoreFilesRetrieve(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n fileId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/files/${fileId}`;\n const method = req.method ?? \"GET\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n if (!stores.has(storeId)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const entry = storeFiles.get(fileKey(storeId, fileId));\n if (!entry) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store file: ${fileId}`), setCorsHeaders);\n return;\n }\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, advanceFile(entry), setCorsHeaders);\n}\n\nexport async function handleVectorStoreFilesDelete(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n fileId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/files/${fileId}`;\n const method = req.method ?? \"DELETE\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const key = fileKey(storeId, fileId);\n if (!storeFiles.has(key)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store file: ${fileId}`), setCorsHeaders);\n return;\n }\n storeFiles.delete(key);\n storePolls.delete(key);\n fileOutcomes.delete(key);\n touch(store);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(\n res,\n 200,\n { id: fileId, object: \"vector_store.file.deleted\", deleted: true },\n setCorsHeaders,\n );\n}\n\nexport async function handleVectorFileBatchesCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n raw: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/file_batches`;\n const method = req.method ?? \"POST\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const parsed = parseJsonBody(raw);\n if (!parsed.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(parsed.message), setCorsHeaders);\n return;\n }\n if (!isJsonObject(parsed.value)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(\"Request body must be a JSON object\"), setCorsHeaders);\n return;\n }\n const fileIds = readFileIds(parsed.value[\"file_ids\"]);\n if (!fileIds.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(fileIds.message), setCorsHeaders);\n return;\n }\n if (fileIds.value.length === 0) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\"Invalid parameter: 'file_ids' must contain at least one file\"),\n setCorsHeaders,\n );\n return;\n }\n if (new Set(fileIds.value).size !== fileIds.value.length) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\"Invalid parameter: 'file_ids' must not contain duplicate file IDs\"),\n setCorsHeaders,\n );\n return;\n }\n const chunking = readChunkingStrategy(parsed.value[\"chunking_strategy\"]);\n if (!chunking.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(chunking.message), setCorsHeaders);\n return;\n }\n for (const fileId of fileIds.value) {\n if (getStoredFileBytes(fileId) === undefined) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such file: ${fileId}`), setCorsHeaders);\n return;\n }\n }\n const attributes = readAttributes(parsed.value[\"attributes\"]);\n if (!attributes.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(attributes.message), setCorsHeaders);\n return;\n }\n const outcome = readOutcome(req);\n if (!outcome.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(outcome.message), setCorsHeaders);\n return;\n }\n const id = underscoreId(\"vsfb\");\n const batch: VectorFileBatchObject = {\n id,\n object: \"vector_store.file_batch\",\n created_at: stamp(),\n vector_store_id: storeId,\n status: \"in_progress\",\n file_counts: {\n in_progress: fileIds.value.length,\n completed: 0,\n failed: 0,\n cancelled: 0,\n total: fileIds.value.length,\n },\n };\n fileBatches.set(id, batch);\n batchPolls.set(id, 0);\n batchOutcomes.set(id, outcome.value);\n const members: VectorStoreFileObject[] = [];\n for (const fileId of fileIds.value) {\n const entry =\n storeFiles.get(fileKey(storeId, fileId)) ??\n attachFile(store, fileId, chunking.value ?? undefined, outcome.value, attributes.value);\n members.push(entry);\n }\n batchMembers.set(id, members);\n batch.file_counts = batchCounts(id);\n refreshStoreStatus(store);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, batch, setCorsHeaders);\n}\n\nexport async function handleVectorFileBatchesRetrieve(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n batchId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/file_batches/${batchId}`;\n const method = req.method ?? \"GET\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n if (!stores.has(storeId)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const batch = fileBatches.get(batchId);\n if (!batch || batch.vector_store_id !== storeId) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such file batch: ${batchId}`), setCorsHeaders);\n return;\n }\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, advanceBatch(batch), setCorsHeaders);\n}\n\nexport async function handleVectorFileBatchesCancel(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n batchId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/file_batches/${batchId}/cancel`;\n const method = req.method ?? \"POST\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n if (!stores.has(storeId)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const batch = fileBatches.get(batchId);\n if (!batch || batch.vector_store_id !== storeId) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such file batch: ${batchId}`), setCorsHeaders);\n return;\n }\n if (TERMINAL_BATCH_STATUSES.has(batch.status)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(`Cannot cancel a file batch with status ${batch.status}.`),\n setCorsHeaders,\n );\n return;\n }\n if (batch.status !== \"cancelling\") batch.status = \"cancelling\";\n batch.file_counts = batchCounts(batch.id);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, batch, setCorsHeaders);\n}\n\nexport async function handleVectorFileBatchesFiles(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n batchId: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/file_batches/${batchId}/files`;\n const method = req.method ?? \"GET\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n if (!stores.has(storeId)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const batch = fileBatches.get(batchId);\n if (!batch || batch.vector_store_id !== storeId) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such file batch: ${batchId}`), setCorsHeaders);\n return;\n }\n const params = queryParams(req.url);\n const readFilter = singleParam(params, \"filter\");\n if (!readFilter.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(readFilter.message), setCorsHeaders);\n return;\n }\n if (\n readFilter.value !== null &&\n !TERMINAL_FILE_STATUSES.has(readFilter.value as VectorStoreFileStatus) &&\n readFilter.value !== \"in_progress\"\n ) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\n \"Invalid parameter: 'filter' must be 'in_progress', 'completed', 'failed' or 'cancelled'\",\n ),\n setCorsHeaders,\n );\n return;\n }\n const members = batchMembers.get(batchId) ?? [];\n let data = [...members].sort((a, b) => b.created_at - a.created_at || (a.id < b.id ? 1 : -1));\n if (readFilter.value !== null) data = data.filter((f) => f.status === readFilter.value);\n const result = paginateOrdered(data, req.url);\n if (!result.ok || !result.page) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(result.message ?? \"Invalid pagination\"), setCorsHeaders);\n return;\n }\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(res, 200, result.page, setCorsHeaders);\n}\n\nexport async function handleVectorStoresSearch(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n storeId: string,\n raw: string,\n journal: Journal,\n defaults: Defaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n): Promise<void> {\n const path = req.url ?? `/v1/vector_stores/${storeId}/search`;\n const method = req.method ?? \"POST\";\n if (await chaosHit(req, journal, defaults, method, path, res, setCorsHeaders)) return;\n const store = stores.get(storeId);\n if (!store) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 404);\n writeJson(res, 404, invalid(`No such vector store: ${storeId}`), setCorsHeaders);\n return;\n }\n const parsed = parseJsonBody(raw);\n if (!parsed.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(parsed.message), setCorsHeaders);\n return;\n }\n if (!isJsonObject(parsed.value)) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(\"Request body must be a JSON object\"), setCorsHeaders);\n return;\n }\n const body = parsed.value;\n const query = body[\"query\"];\n const queries = typeof query === \"string\" ? [query] : query;\n if (\n !Array.isArray(queries) ||\n queries.length === 0 ||\n !queries.every((entry) => typeof entry === \"string\" && entry.length > 0)\n ) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\n \"Invalid parameter: 'query' must be a non-empty string or a non-empty array of non-empty strings\",\n ),\n setCorsHeaders,\n );\n return;\n }\n // Preserve string ranking; arrays use their entries joined in request order.\n const normalizedQuery = queries.join(\"\\n\");\n let maxResults = 10;\n if (body[\"max_num_results\"] !== undefined) {\n const n = body[\"max_num_results\"];\n if (typeof n !== \"number\" || !Number.isInteger(n) || n < 1 || n > 50) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\"Invalid parameter: 'max_num_results' must be an integer between 1 and 50\"),\n setCorsHeaders,\n );\n return;\n }\n maxResults = n;\n }\n let threshold = 0;\n if (body[\"ranking_options\"] !== undefined) {\n if (!isJsonObject(body[\"ranking_options\"])) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\"Invalid parameter: 'ranking_options' must be an object\"),\n setCorsHeaders,\n );\n return;\n }\n const score = body[\"ranking_options\"][\"score_threshold\"];\n if (score !== undefined) {\n if (typeof score !== \"number\" || score < 0 || score > 1) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(\n res,\n 400,\n invalid(\n \"Invalid parameter: 'ranking_options.score_threshold' must be a number between 0 and 1\",\n ),\n setCorsHeaders,\n );\n return;\n }\n threshold = score;\n }\n }\n const filters = readAttributeFilter(body[\"filters\"]);\n if (!filters.ok) {\n journalVs(journal, method, path, flattenHeaders(req.headers), 400);\n writeJson(res, 400, invalid(filters.message), setCorsHeaders);\n return;\n }\n const completed = [...storeFiles.values()].filter(\n (f) =>\n f.vector_store_id === storeId &&\n f.status === \"completed\" &&\n (filters.value === null || matchesAttributeFilter(f.attributes, filters.value)),\n );\n const ranked: VectorSearchResult[] = completed\n .map((f) => ({ file: f, score: scoreFor(normalizedQuery, f.id) }))\n .filter((entry) => entry.score >= threshold)\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults)\n .map((entry) => ({\n file_id: entry.file.id,\n attributes: entry.file.attributes,\n filename: getStoredFileName(entry.file.id) ?? `file-${entry.file.id.slice(0, 8)}.txt`,\n score: Math.round(entry.score * 10000) / 10000,\n content: [\n {\n type: \"text\" as const,\n text: `Mock chunk from ${entry.file.id} answering \"${normalizedQuery.slice(0, 120)}\"`,\n },\n ],\n }));\n touch(store);\n journalVs(journal, method, path, flattenHeaders(req.headers), 200);\n writeJson(\n res,\n 200,\n {\n object: \"vector_store.search_results_page\",\n search_query: query,\n data: ranked,\n has_more: false,\n },\n setCorsHeaders,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-types.d.cts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,
|
|
1
|
+
{"version":3,"file":"vector-types.d.cts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMV,CAAM;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,
|
|
1
|
+
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMJ,CAAA;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
|
package/dist/veo-video.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
2
|
const require_helpers = require('./helpers.cjs');
|
|
3
|
-
const require_router = require('./router.cjs');
|
|
4
3
|
const require_sse_writer = require('./sse-writer.cjs');
|
|
5
4
|
const require_chaos = require('./chaos.cjs');
|
|
5
|
+
const require_router = require('./router.cjs');
|
|
6
6
|
const require_url = require('./url.cjs');
|
|
7
7
|
const require_recorder = require('./recorder.cjs');
|
|
8
8
|
const require_fal = require('./fal.cjs');
|
|
@@ -192,7 +192,7 @@ async function handleVeoVideoCreate(req, res, raw, model, fixtures, journal, def
|
|
|
192
192
|
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
193
193
|
defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
194
194
|
} else defaults.logger.debug(`No fixture matched for Veo request (model=${model}, msg="${prompt.slice(0, 80)}")`);
|
|
195
|
-
if (require_chaos.
|
|
195
|
+
if (await require_chaos.applyChaosAsync(res, fixture, defaults.chaos, req.headers, req.url, journal, {
|
|
196
196
|
method,
|
|
197
197
|
path,
|
|
198
198
|
headers: require_helpers.flattenHeaders(req.headers),
|
|
@@ -247,7 +247,7 @@ async function handleVeoVideoCreate(req, res, raw, model, fixtures, journal, def
|
|
|
247
247
|
const worldGeneration = jobs.generation;
|
|
248
248
|
const response = await require_helpers.resolveResponse(fixture, syntheticReq);
|
|
249
249
|
if (require_helpers.isErrorResponse(response)) {
|
|
250
|
-
if (
|
|
250
|
+
if (require_chaos.responseGone(res)) return;
|
|
251
251
|
const status = response.status ?? 500;
|
|
252
252
|
journal.add({
|
|
253
253
|
method,
|
|
@@ -263,7 +263,7 @@ async function handleVeoVideoCreate(req, res, raw, model, fixtures, journal, def
|
|
|
263
263
|
return;
|
|
264
264
|
}
|
|
265
265
|
if (!require_helpers.isVideoResponse(response)) {
|
|
266
|
-
if (
|
|
266
|
+
if (require_chaos.responseGone(res)) return;
|
|
267
267
|
journal.add({
|
|
268
268
|
method,
|
|
269
269
|
path,
|
|
@@ -277,7 +277,7 @@ async function handleVeoVideoCreate(req, res, raw, model, fixtures, journal, def
|
|
|
277
277
|
require_sse_writer.writeErrorResponse(res, 500, geminiError(500, "Fixture response is not a video type", "INTERNAL"));
|
|
278
278
|
return;
|
|
279
279
|
}
|
|
280
|
-
if (
|
|
280
|
+
if (require_chaos.responseGone(res)) return;
|
|
281
281
|
journal.add({
|
|
282
282
|
method,
|
|
283
283
|
path,
|
|
@@ -312,7 +312,7 @@ async function handleVeoVideoStatus(req, res, operationName, fixtures, journal,
|
|
|
312
312
|
setCorsHeaders(res);
|
|
313
313
|
const path = req.url ?? `/v1beta/${operationName}`;
|
|
314
314
|
const method = req.method ?? "GET";
|
|
315
|
-
if (require_chaos.
|
|
315
|
+
if (await require_chaos.applyChaosAsync(res, null, defaults.chaos, req.headers, req.url, journal, {
|
|
316
316
|
method,
|
|
317
317
|
path,
|
|
318
318
|
headers: require_helpers.flattenHeaders(req.headers),
|
|
@@ -367,7 +367,7 @@ async function handleVeoVideoStatus(req, res, operationName, fixtures, journal,
|
|
|
367
367
|
});
|
|
368
368
|
return;
|
|
369
369
|
}
|
|
370
|
-
if (
|
|
370
|
+
if (require_chaos.responseGone(res)) return;
|
|
371
371
|
advanceVeoJob(job);
|
|
372
372
|
jobs.set(key, job);
|
|
373
373
|
journal.add({
|
|
@@ -421,7 +421,7 @@ async function proxyVeoVideoSubmit(args) {
|
|
|
421
421
|
}
|
|
422
422
|
const proxyError = (msg) => {
|
|
423
423
|
defaults.logger.error(`Veo video submit proxy failed: ${msg}`);
|
|
424
|
-
if (
|
|
424
|
+
if (require_chaos.responseGone(res)) return "handled";
|
|
425
425
|
journal.add({
|
|
426
426
|
method,
|
|
427
427
|
path,
|
|
@@ -471,7 +471,7 @@ async function proxyVeoVideoSubmit(args) {
|
|
|
471
471
|
}
|
|
472
472
|
if (fetched.status === 401 || fetched.status === 403) {
|
|
473
473
|
defaults.logger.warn(`Upstream rejected the Veo video submit (${fetched.status}) — relaying the upstream status`);
|
|
474
|
-
if (
|
|
474
|
+
if (require_chaos.responseGone(res)) return "handled";
|
|
475
475
|
journal.add({
|
|
476
476
|
method,
|
|
477
477
|
path,
|
|
@@ -526,7 +526,7 @@ async function proxyVeoVideoSubmit(args) {
|
|
|
526
526
|
};
|
|
527
527
|
if (jobs.generation === worldGeneration) jobs.set(`${testId}:${operationName}`, job);
|
|
528
528
|
else defaults.logger.warn(`Veo video submit for upstream operation ${upstreamOperationName} completed after a fixtures reset — not inserting the job into the new world (its polls will 404)`);
|
|
529
|
-
if (
|
|
529
|
+
if (require_chaos.responseGone(res)) return "handled";
|
|
530
530
|
journal.add({
|
|
531
531
|
method,
|
|
532
532
|
path,
|
|
@@ -573,7 +573,7 @@ async function proxyVeoVideoRecordPoll(args) {
|
|
|
573
573
|
};
|
|
574
574
|
const proxyError = (msg) => {
|
|
575
575
|
logger.error(`Veo video poll proxy failed: ${msg}`);
|
|
576
|
-
if (
|
|
576
|
+
if (require_chaos.responseGone(res)) return;
|
|
577
577
|
journalProxy(502);
|
|
578
578
|
require_sse_writer.writeErrorResponse(res, 502, JSON.stringify({ error: {
|
|
579
579
|
message: `Proxy to upstream failed: ${msg}`,
|
|
@@ -607,7 +607,7 @@ async function proxyVeoVideoRecordPoll(args) {
|
|
|
607
607
|
}
|
|
608
608
|
if (fetched.status === 401 || fetched.status === 403) {
|
|
609
609
|
logger.warn(`Upstream rejected the Veo status poll for operation ${job.upstreamOperationName} (${fetched.status}) — relaying the upstream status`);
|
|
610
|
-
if (
|
|
610
|
+
if (require_chaos.responseGone(res)) return;
|
|
611
611
|
journalProxy(fetched.status);
|
|
612
612
|
res.writeHead(fetched.status, { "Content-Type": fetched.contentType ?? "application/json" });
|
|
613
613
|
res.end(fetched.text);
|
|
@@ -637,7 +637,7 @@ async function proxyVeoVideoRecordPoll(args) {
|
|
|
637
637
|
name: job.operationName
|
|
638
638
|
};
|
|
639
639
|
const relayJson = () => {
|
|
640
|
-
if (
|
|
640
|
+
if (require_chaos.responseGone(res)) return;
|
|
641
641
|
journalProxy(200);
|
|
642
642
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
643
643
|
res.end(JSON.stringify(relayBody));
|
package/dist/veo-video.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"veo-video.cjs","names":["flattenHeaders","getContext","getTestId","matchFixtureDiagnostic","applyChaos","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","resolveResponse","isErrorResponse","serializeErrorResponse","isVideoResponse","crypto","resolveProgression","testIdSuffix","resolveUpstreamUrl","prepareEgressHeaders","upstreamTimeoutSignal","readEnvelopeText","buildFixtureMatch","persistFixture","sanitizeHeaderValue"],"sources":["../src/veo-video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport type {\n ChatCompletionRequest,\n Fixture,\n HandlerDefaults,\n RecordConfig,\n VideoResponse,\n} from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { resolveProgression } from \"./fal.js\";\nimport {\n buildFixtureMatch,\n prepareEgressHeaders,\n persistFixture,\n sanitizeHeaderValue,\n} from \"./recorder.js\";\nimport { resolveUpstreamUrl } from \"./url.js\";\nimport { readEnvelopeText, testIdSuffix, upstreamTimeoutSignal } from \"./video-proxy-shared.js\";\n\n/**\n * Google Veo async video lifecycle mock. Submit\n * `POST /v1beta/models/{model}:predictLongRunning` returns\n * `{ name: \"operations/...\" }`; status `GET /v1beta/operations/{name}` polls\n * `done:false → done:true`. The Files-API `uri` is served AS-IS — aimock does\n * NOT proxy or capture video bytes. With `record.providers.veo` configured an\n * unmatched submit becomes a live interactive proxy (submit + poll forwarded\n * 1:1, eager fixture capture on terminal status). Strict mode still wins.\n *\n * ASSUMED Veo create body shape (the `@google/genai` :predictLongRunning\n * envelope from issue #278): `{ instances: [{ prompt, image? }], parameters }`.\n * Match surface is `instances[0].prompt` only.\n */\n\n/** Files-API-shaped placeholder served when a completed fixture omits a uri. */\nconst DEFAULT_VEO_FILES_URI = \"https://generativelanguage.googleapis.com/v1beta/files/placeholder\";\n\n// The `:predictLongRunning` envelope nests the prompt under instances[].\ninterface VeoVideoRequest {\n instances?: Array<{ prompt?: unknown; [key: string]: unknown }>;\n parameters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ─── VeoVideoJobMap (TTL + bounded) ─────────────────────────────────────────\n\nexport const VEO_VIDEO_MAX_ENTRIES = 10_000;\nconst VEO_VIDEO_TTL_MS = 3_600_000; // 1 hour\n\ntype VeoVideoStatus = \"pending\" | \"in_progress\" | \"completed\" | \"failed\";\n\ninterface VeoVideoReplayJob {\n kind: \"replay\";\n operationName: string;\n status: VeoVideoStatus;\n pollCount: number;\n pollsBeforeInProgress: number;\n pollsBeforeCompleted: number;\n video: VideoResponse[\"video\"];\n /** Latch for the empty-`error` authoring warn on failed polls (once/job). */\n emptyErrorWarned?: boolean;\n}\n\ninterface VeoVideoRecordJob {\n kind: \"record\";\n operationName: string;\n status: VeoVideoStatus;\n upstreamOperationName: string;\n upstreamPollingUrl: string;\n match: Fixture[\"match\"];\n capturing?: boolean;\n}\n\nexport type VeoVideoJob = VeoVideoReplayJob | VeoVideoRecordJob;\n\ninterface VeoVideoEntry {\n job: VeoVideoJob;\n createdAt: number;\n}\n\n/**\n * Per-testId job state for the Veo video handler. Mirrors OpenRouterVideoJobMap\n * (openrouter-video.ts): lazy TTL eviction on `get`, FIFO eviction of the\n * oldest entries on `set` when over capacity, delete-before-set TTL refresh,\n * monotonic world-generation counter for reset-mid-flight detection, no\n * background sweep timer. Keys are `${testId}:${operationName}`.\n */\nexport class VeoVideoJobMap {\n private readonly entries = new Map<string, VeoVideoEntry>();\n private worldGeneration = 0;\n\n get generation(): number {\n return this.worldGeneration;\n }\n\n get(key: string): VeoVideoJob | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VEO_VIDEO_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.job;\n }\n\n set(key: string, job: VeoVideoJob): void {\n this.entries.delete(key);\n this.entries.set(key, { job, createdAt: Date.now() });\n if (this.entries.size > VEO_VIDEO_MAX_ENTRIES) {\n const excess = this.entries.size - VEO_VIDEO_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 this.worldGeneration++;\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\n// ─── Job progression ────────────────────────────────────────────────────────\n\n/**\n * Maps the fixture's terminal video status onto the job lifecycle. Anything\n * that is not \"failed\" — including a fixture authored as \"processing\" — is\n * treated as completed, since this surface always drives jobs to a terminal\n * state.\n */\nfunction terminalStatus(job: VeoVideoReplayJob): VeoVideoStatus {\n return job.video.status === \"failed\" ? \"failed\" : \"completed\";\n}\n\n/**\n * Mutates a job in place to advance its state on a status poll.\n * `pending → in_progress → completed | failed` based on poll-count thresholds.\n * No-op once terminal. The in_progress threshold is checked first so a job\n * whose thresholds are equal still spends one poll in in_progress instead of\n * jumping straight to the terminal status (fal advanceJob semantics). The wire\n * value is derived from this internal status (pending/in_progress → done:false,\n * completed/failed → done:true).\n */\nfunction advanceVeoJob(job: VeoVideoReplayJob): void {\n if (job.status === \"completed\" || job.status === \"failed\") return;\n\n job.pollCount += 1;\n if (job.status === \"pending\" && job.pollCount >= job.pollsBeforeInProgress) {\n job.status = \"in_progress\";\n } else if (job.pollCount >= job.pollsBeforeCompleted) {\n job.status = terminalStatus(job);\n }\n}\n\n/** Gemini-style error envelope used by every Veo error response. */\nfunction geminiError(code: number, message: string, status: string): string {\n return JSON.stringify({ error: { code, message, status } });\n}\n\n/**\n * The done:true operation body for a completed replay job — the Files-API uri\n * is served as-is (the fixture's stored `video.url`, or the documented\n * placeholder when omitted).\n */\nfunction completedOperationBody(operationName: string, uri: string): Record<string, unknown> {\n return {\n name: operationName,\n done: true,\n response: {\n generateVideoResponse: {\n generatedSamples: [{ video: { uri } }],\n },\n },\n };\n}\n\n// ─── POST /v1beta/models/{model}:predictLongRunning — submit ─────────────────\n\nexport async function handleVeoVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n model: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n jobs: VeoVideoJobMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? `/v1beta/models/${model}:predictLongRunning`;\n const method = req.method ?? \"POST\";\n\n let videoReq: VeoVideoRequest;\n try {\n videoReq = JSON.parse(raw) as VeoVideoRequest;\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(res, 400, geminiError(400, `Malformed JSON: ${detail}`, \"INVALID_ARGUMENT\"));\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object before touching fields.\n if (videoReq === null || typeof videoReq !== \"object\" || Array.isArray(videoReq)) {\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 geminiError(400, \"Request body must be a JSON object\", \"INVALID_ARGUMENT\"),\n );\n return;\n }\n\n // Prompt lives at instances[0].prompt (the @google/genai envelope).\n const firstInstance = Array.isArray(videoReq.instances) ? videoReq.instances[0] : undefined;\n const prompt = firstInstance?.prompt;\n // Synthesize a structurally valid journal body for field-validation 400s\n // (JournalEntry.body is ChatCompletionRequest | null). Strip reserved\n // underscore-prefixed keys so a request cannot spoof handler discriminators.\n const sanitized = Object.fromEntries(\n Object.entries(videoReq).filter(([key]) => !key.startsWith(\"_\")),\n );\n const parsedBody: ChatCompletionRequest = { ...sanitized, model, messages: [] };\n\n if (typeof prompt !== \"string\" || !prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: parsedBody,\n response: { status: 400, fixture: null },\n });\n const message =\n prompt === undefined\n ? \"Missing required parameter: 'instances[0].prompt'\"\n : \"Invalid type for parameter: 'instances[0].prompt' must be a non-empty string\";\n writeErrorResponse(res, 400, geminiError(400, message, \"INVALID_ARGUMENT\"));\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [{ role: \"user\", content: prompt }],\n _endpointType: \"video\",\n _videoProvider: \"veo\",\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(\n `No fixture matched for Veo request (model=${model}, msg=\"${prompt.slice(0, 80)}\")`,\n );\n }\n\n // Chaos rolls AFTER body validation and fixture matching (mirrors the\n // OpenRouter submit). An unmatched submit is proxied upstream when record\n // mode has a veo provider AND strict would not win — label that roll \"proxy\".\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\n ? \"fixture\"\n : resolveStrictMode(defaults.strict, req.headers)\n ? \"internal\"\n : defaults.record?.providers.veo\n ? \"proxy\"\n : \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n // Strict mode wins over record: a strict no-match fails loudly with 503.\n if (resolveStrictMode(defaults.strict, req.headers)) {\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(res, 503, geminiError(503, strictMessage, \"UNAVAILABLE\"));\n return;\n }\n\n if (defaults.record) {\n const outcome = await proxyVeoVideoSubmit({\n req,\n res,\n raw,\n syntheticReq,\n record: defaults.record,\n journal,\n defaults,\n jobs,\n method,\n path,\n });\n if (outcome === \"handled\") return;\n // outcome === \"no_upstream\" — fall through to 404 (fal convention).\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(res, 404, geminiError(404, \"No fixture matched\", \"NOT_FOUND\"));\n return;\n }\n\n // World-generation snapshot (mirrors the record-submit guard): a fixtures\n // reset can land while the fixture's ResponseFactory below is awaited, and\n // the job insertion at the bottom must not seed the NEW world.\n const worldGeneration = jobs.generation;\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n if (res.destroyed || res.writableEnded) return;\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 if (!isVideoResponse(response)) {\n if (res.destroyed || res.writableEnded) return;\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 geminiError(500, \"Fixture response is not a video type\", \"INTERNAL\"),\n );\n return;\n }\n\n if (res.destroyed || res.writableEnded) return;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const fixtureStatus: string = response.video.status;\n if (fixtureStatus === \"processing\") {\n defaults.logger.warn(\n `Veo video fixture has status \"processing\" — treated as completed for the operations lifecycle`,\n );\n } else if (fixtureStatus !== \"completed\" && fixtureStatus !== \"failed\") {\n defaults.logger.warn(\n `Veo video fixture has unknown status \"${fixtureStatus}\" — treating as completed`,\n );\n }\n\n const operationName = `operations/${crypto.randomUUID()}`;\n const progression = resolveProgression(defaults.veoVideo);\n const job: VeoVideoReplayJob = {\n kind: \"replay\",\n operationName,\n status: \"pending\",\n pollCount: 0,\n pollsBeforeInProgress: progression.pollsBeforeInProgress,\n pollsBeforeCompleted: progression.pollsBeforeCompleted,\n video: { ...response.video },\n };\n // Default 0/0 progression seeds the job terminal at submit; the submit\n // envelope still reports a not-done operation.\n if (progression.pollsBeforeCompleted === 0) {\n job.status = terminalStatus(job);\n }\n if (jobs.generation === worldGeneration) {\n jobs.set(`${testId}:${operationName}`, job);\n } else {\n defaults.logger.warn(\n `Veo video submit resolved after a fixtures reset — not inserting operation ${operationName} into the new world (its polls will 404)`,\n );\n }\n\n // Embed the testId in the RETURNED name (not the stored key) so a multi-tenant\n // client can poll the opaque name without an x-test-id header — the testId\n // travels via getTestId's `?testId=` fallback. Mirrors OpenRouter's polling_url\n // treatment; testIdSuffix is \"\" for the default testId, keeping the name bare.\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ name: operationName + testIdSuffix(testId, \"?\") }));\n}\n\n// ─── GET /v1beta/operations/{name} — status poll ─────────────────────────────\n\nexport async function handleVeoVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n operationName: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n jobs: VeoVideoJobMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? `/v1beta/${operationName}`;\n const method = req.method ?? \"GET\";\n\n // Chaos rolls BEFORE the job lookup — the label stays \"internal\" even in\n // record mode, and a chaos-dropped poll never reaches the upstream.\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const key = `${testId}:${operationName}`;\n const job = jobs.get(key);\n\n if (!job) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n geminiError(404, `Operation ${operationName} not found`, \"NOT_FOUND\"),\n );\n return;\n }\n\n if (job.kind === \"record\") {\n // Strict means nothing reaches an upstream — a record job's polls are pure\n // upstream proxies, so an effective-strict request is refused with 503.\n if (resolveStrictMode(defaults.strict, req.headers)) {\n defaults.logger.error(\n `STRICT: Veo operation ${operationName} is proxied live upstream (record mode) — refusing the upstream poll`,\n );\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n geminiError(\n 503,\n `Strict mode: Veo operation ${operationName} is proxied live upstream (record mode) — nothing reaches an upstream under strict mode`,\n \"UNAVAILABLE\",\n ),\n );\n return;\n }\n await proxyVeoVideoRecordPoll({\n req,\n res,\n job,\n key,\n testId,\n fixtures,\n journal,\n defaults,\n jobs,\n method,\n path,\n });\n return;\n }\n\n // Guard BEFORE advancing or journaling (file convention): a disconnected\n // client consumes no progression step or TTL refresh.\n if (res.destroyed || res.writableEnded) return;\n advanceVeoJob(job);\n // Refresh the TTL on every replay poll (delete-before-set also moves the\n // entry to the back of the FIFO eviction order).\n jobs.set(key, job);\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n let body: Record<string, unknown>;\n if (job.status === \"completed\") {\n // Truthy guard (not `??`): an empty-string fixture url must still fall back\n // to the placeholder Files-API uri rather than being served as an empty uri.\n const rawUrl = job.video.url;\n body = completedOperationBody(\n operationName,\n typeof rawUrl === \"string\" && rawUrl ? rawUrl : DEFAULT_VEO_FILES_URI,\n );\n } else if (job.status === \"failed\") {\n if (job.video.error === \"\" && !job.emptyErrorWarned) {\n job.emptyErrorWarned = true;\n defaults.logger.warn(\n `Veo video fixture for operation ${operationName} has an empty error message — using the default`,\n );\n }\n body = {\n name: operationName,\n done: true,\n error: { code: 3, message: job.video.error || \"Video generation failed\" },\n };\n } else {\n body = { name: operationName, done: false };\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n\n// ─── Record mode: live interactive proxy (submit) ───────────────────────────\n\n/**\n * Proxy an unmatched Veo submit to the configured upstream and answer the\n * client with a mock-rewritten envelope: a fresh aimock operation name. The\n * upstream lifecycle is driven interactively by the client's own polls.\n *\n * Returns \"no_upstream\" when record mode has no veo provider URL — the caller\n * falls through to its 404 branch (fal convention).\n */\nasync function proxyVeoVideoSubmit(args: {\n req: http.IncomingMessage;\n res: http.ServerResponse;\n raw: string;\n syntheticReq: ChatCompletionRequest;\n record: RecordConfig;\n journal: Journal;\n defaults: HandlerDefaults;\n jobs: VeoVideoJobMap;\n method: string;\n path: string;\n}): Promise<\"handled\" | \"no_upstream\"> {\n const { req, res, raw, syntheticReq, record, journal, defaults, jobs, method, path } = args;\n\n const upstreamBase = record.providers.veo;\n if (!upstreamBase) {\n defaults.logger.warn(`No upstream URL configured for provider \"veo\" — cannot proxy`);\n return \"no_upstream\";\n }\n\n const proxyError = (msg: string): \"handled\" => {\n defaults.logger.error(`Veo video submit proxy failed: ${msg}`);\n if (res.destroyed || res.writableEnded) return \"handled\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 502,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 502,\n JSON.stringify({\n error: { message: `Proxy to upstream failed: ${msg}`, type: \"proxy_error\" },\n }),\n );\n return \"handled\";\n };\n\n const submitPath = `/v1beta/models/${syntheticReq.model}:predictLongRunning`;\n let submitUrl: URL;\n let upstreamOrigin: string;\n try {\n submitUrl = resolveUpstreamUrl(upstreamBase, submitPath);\n upstreamOrigin = new URL(upstreamBase).origin;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return proxyError(`Invalid upstream URL: ${upstreamBase} (${msg})`);\n }\n\n defaults.logger.warn(\n `NO FIXTURE MATCH — proxying Veo video submit to ${upstreamBase}${submitPath}`,\n );\n\n // World-generation snapshot: a fixtures reset landing during the upstream\n // fetch clears the job map — the insertion guard compares against this.\n const worldGeneration = jobs.generation;\n\n let fetched: { status: number; contentType: string | null; text: string };\n try {\n const headers = prepareEgressHeaders(req, submitUrl, \"veo\", record.providerKeys?.veo);\n if (!headers) return proxyError(\"No configured provider credential\");\n const upstreamRes = await fetch(submitUrl, {\n method: \"POST\",\n headers,\n body: raw,\n signal: upstreamTimeoutSignal(record),\n });\n fetched = {\n status: upstreamRes.status,\n contentType: upstreamRes.headers.get(\"content-type\"),\n text: await readEnvelopeText(upstreamRes, record),\n };\n } catch (err) {\n return proxyError(err instanceof Error ? err.message : \"Unknown proxy error\");\n }\n\n if (fetched.status === 401 || fetched.status === 403) {\n // Real-API fidelity: relay an upstream auth rejection verbatim.\n defaults.logger.warn(\n `Upstream rejected the Veo video submit (${fetched.status}) — relaying the upstream status`,\n );\n if (res.destroyed || res.writableEnded) return \"handled\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: fetched.status,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n res.writeHead(fetched.status, { \"Content-Type\": fetched.contentType ?? \"application/json\" });\n res.end(fetched.text);\n return \"handled\";\n }\n\n let upstreamOperationName: string;\n {\n if (fetched.status < 200 || fetched.status >= 300) {\n return proxyError(`Submit ${fetched.status}: ${fetched.text.slice(0, 200)}`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(fetched.text);\n } catch {\n return proxyError(`Submit returned non-JSON: ${fetched.text.slice(0, 200)}`);\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return proxyError(\"Submit response is not a JSON object\");\n }\n upstreamOperationName = String((parsed as Record<string, unknown>).name ?? \"\").trim();\n if (!upstreamOperationName) {\n return proxyError(\"Submit response missing name\");\n }\n }\n\n // Veo has no polling_url field — the poll URL is constructed from the\n // provider base + `/v1beta/{operationName}`. Origin-validate the constructed\n // URL (the client's Authorization travels to it on every poll); fall back to\n // a string on the provider base on any parse failure.\n let upstreamPollingUrl: string;\n try {\n const constructed = resolveUpstreamUrl(\n upstreamBase,\n `/v1beta/${upstreamOperationName.replace(/^\\/+/, \"\")}`,\n );\n if (constructed.origin === upstreamOrigin) {\n upstreamPollingUrl = constructed.toString();\n } else {\n defaults.logger.warn(\n `Constructed Veo poll URL origin ${constructed.origin} differs from the configured provider origin ${upstreamOrigin} — using the provider-origin URL`,\n );\n upstreamPollingUrl = `${upstreamOrigin}/v1beta/${upstreamOperationName.replace(/^\\/+/, \"\")}`;\n }\n } catch {\n defaults.logger.warn(\n `Could not construct the Veo poll URL for ${upstreamOperationName} — using the provider-origin URL`,\n );\n upstreamPollingUrl = `${upstreamOrigin}/v1beta/${upstreamOperationName.replace(/^\\/+/, \"\")}`;\n }\n\n const testId = getTestId(req);\n const matchRequest = defaults.requestTransform\n ? defaults.requestTransform(syntheticReq)\n : syntheticReq;\n const operationName = `operations/${crypto.randomUUID()}`;\n const job: VeoVideoRecordJob = {\n kind: \"record\",\n operationName,\n status: \"pending\",\n upstreamOperationName,\n upstreamPollingUrl,\n match: buildFixtureMatch(matchRequest, record),\n };\n if (jobs.generation === worldGeneration) {\n jobs.set(`${testId}:${operationName}`, job);\n } else {\n defaults.logger.warn(\n `Veo video submit for upstream operation ${upstreamOperationName} completed after a fixtures reset — not inserting the job into the new world (its polls will 404)`,\n );\n }\n\n if (res.destroyed || res.writableEnded) return \"handled\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 200,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n\n // Embed the testId in the RETURNED name (see the replay submit) so record-mode\n // multi-tenant polls resolve via `?testId=`; the upstream poll still uses the\n // bare job.operationName / job.upstreamPollingUrl, untouched by the suffix.\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ name: operationName + testIdSuffix(testId, \"?\") }));\n return \"handled\";\n}\n\n// ─── Record mode: live interactive proxy (poll + eager capture) ─────────────\n\n/**\n * Proxy a status poll for a record-mode Veo job 1:1 to the upstream and relay\n * the result with the operation name rewritten to the mock operation (the\n * Files-API uri inside `response` passes through verbatim — aimock never\n * downloads bytes). When the upstream reports `done:true` with a `response`,\n * the rewritten body is relayed IMMEDIATELY and the eager capture (persist the\n * uri as a fixture, mutate to a terminal replay job) runs DETACHED. A\n * `done:true` with an `error` persists a failed fixture synchronously. Under\n * `record.proxyOnly` nothing is captured, persisted, or mutated. Every\n * post-await map mutation is identity-guarded.\n */\nasync function proxyVeoVideoRecordPoll(args: {\n req: http.IncomingMessage;\n res: http.ServerResponse;\n job: VeoVideoRecordJob;\n key: string;\n testId: string;\n fixtures: Fixture[];\n journal: Journal;\n defaults: HandlerDefaults;\n jobs: VeoVideoJobMap;\n method: string;\n path: string;\n}): Promise<void> {\n const { req, res, job, key, testId, fixtures, journal, defaults, jobs, method, path } = args;\n const logger = defaults.logger;\n\n const journalProxy = (status: number): void => {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n };\n\n const proxyError = (msg: string): void => {\n logger.error(`Veo video poll proxy failed: ${msg}`);\n if (res.destroyed || res.writableEnded) return;\n journalProxy(502);\n writeErrorResponse(\n res,\n 502,\n JSON.stringify({\n error: { message: `Proxy to upstream failed: ${msg}`, type: \"proxy_error\" },\n }),\n );\n };\n\n // Recording can be disabled mid-flight — an orphaned record job must fail\n // loudly before contacting the upstream.\n const record = defaults.record;\n if (!record) {\n proxyError(\"record mode is no longer configured for an in-flight record job\");\n return;\n }\n\n let fetched: { status: number; contentType: string | null; text: string };\n try {\n const target = new URL(job.upstreamPollingUrl);\n const headers = prepareEgressHeaders(req, target, \"veo\", record.providerKeys?.veo);\n if (!headers) {\n proxyError(\"No configured provider credential\");\n return;\n }\n const upstreamRes = await fetch(job.upstreamPollingUrl, {\n headers,\n signal: upstreamTimeoutSignal(record),\n });\n fetched = {\n status: upstreamRes.status,\n contentType: upstreamRes.headers.get(\"content-type\"),\n text: await readEnvelopeText(upstreamRes, record),\n };\n } catch (err) {\n proxyError(err instanceof Error ? err.message : \"Unknown proxy error\");\n return;\n }\n\n if (fetched.status === 401 || fetched.status === 403) {\n logger.warn(\n `Upstream rejected the Veo status poll for operation ${job.upstreamOperationName} (${fetched.status}) — relaying the upstream status`,\n );\n if (res.destroyed || res.writableEnded) return;\n journalProxy(fetched.status);\n res.writeHead(fetched.status, { \"Content-Type\": fetched.contentType ?? \"application/json\" });\n res.end(fetched.text);\n return;\n }\n\n let upstreamBody: Record<string, unknown>;\n {\n if (fetched.status < 200 || fetched.status >= 300) {\n proxyError(`Status ${fetched.status}: ${fetched.text.slice(0, 200)}`);\n return;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(fetched.text);\n } catch {\n proxyError(`Status returned non-JSON: ${fetched.text.slice(0, 200)}`);\n return;\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n proxyError(\"Status response is not a JSON object\");\n return;\n }\n upstreamBody = parsed as Record<string, unknown>;\n }\n\n // Rewrite ONLY the top-level operation name so no upstream identifier\n // escapes — the `response` (carrying the Files-API uri the client needs) and\n // every other field pass through verbatim.\n const relayBody: Record<string, unknown> = { ...upstreamBody, name: job.operationName };\n\n const relayJson = (): void => {\n if (res.destroyed || res.writableEnded) return;\n journalProxy(200);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(relayBody));\n };\n\n const done = upstreamBody.done === true;\n const upstreamError = upstreamBody.error;\n const hasError =\n upstreamError !== undefined && upstreamError !== null && typeof upstreamError === \"object\";\n\n if (!done) {\n // Non-terminal: identity-guarded status write + TTL refresh, relay.\n if (jobs.get(key) === job) {\n if (!job.capturing && job.status !== \"completed\" && job.status !== \"failed\") {\n job.status = \"in_progress\";\n }\n jobs.set(key, job);\n }\n relayJson();\n return;\n }\n\n if (hasError) {\n // Terminal failure: persist a failed fixture synchronously (mirrors the\n // OpenRouter failed branch), then relay.\n if (record.proxyOnly) {\n if (jobs.get(key) === job) {\n job.status = \"failed\";\n jobs.set(key, job);\n }\n relayJson();\n return;\n }\n if (jobs.get(key) !== job) {\n // A concurrent terminal poll already persisted/replaced the entry, or a\n // fixtures reset cleared the world — relay without a duplicate fixture.\n relayJson();\n return;\n }\n const errObj = upstreamError as Record<string, unknown>;\n const rawMessage = errObj.message;\n const error = typeof rawMessage === \"string\" && rawMessage ? rawMessage : undefined;\n const video: VideoResponse[\"video\"] = {\n id: job.upstreamOperationName,\n status: \"failed\",\n ...(error !== undefined ? { error } : {}),\n };\n const persistResult = persistFixture({\n record,\n providerKey: \"veo\",\n testId,\n fixture: { match: job.match, response: { video } },\n fixtures,\n logger,\n });\n if (persistResult.kind === \"failed\" && !res.headersSent) {\n res.setHeader(\"X-AIMock-Record-Error\", sanitizeHeaderValue(persistResult.error));\n }\n jobs.set(key, {\n kind: \"replay\",\n operationName: job.operationName,\n status: \"failed\",\n pollCount: 0,\n pollsBeforeInProgress: 0,\n pollsBeforeCompleted: 0,\n video: { ...video },\n });\n relayJson();\n return;\n }\n\n // Terminal success (done:true with a response).\n if (record.proxyOnly) {\n if (jobs.get(key) === job) {\n job.status = \"completed\";\n jobs.set(key, job);\n }\n relayJson();\n return;\n }\n\n if (job.capturing || jobs.get(key) !== job) {\n // A concurrent poll already entered the capture sequence, or this\n // reference is detached — relay without starting a second capture and\n // never re-insert the stale object.\n if (jobs.get(key) === job) {\n jobs.set(key, job); // TTL refresh\n }\n relayJson();\n return;\n }\n\n // Open the capturing window SYNCHRONOUSLY before the first await.\n job.capturing = true;\n job.status = \"completed\";\n jobs.set(key, job); // TTL refresh — identity-checked above, no await since\n\n // Relay IMMEDIATELY; the persist + replay mutation runs DETACHED.\n relayJson();\n\n void captureVeoVideoRecordFixture({\n job,\n key,\n testId,\n fixtures,\n defaults,\n jobs,\n record,\n upstreamBody,\n });\n}\n\n/**\n * Detached eager-capture for a completed Veo record job. Extracts the\n * Files-API uri from the terminal poll body (NO download), persists a\n * fixture, and mutates the map entry into a terminal replay job. Every failure\n * is handled internally; the returned promise NEVER rejects. World-generation\n * guarded immediately before persist.\n */\nasync function captureVeoVideoRecordFixture(args: {\n job: VeoVideoRecordJob;\n key: string;\n testId: string;\n fixtures: Fixture[];\n defaults: HandlerDefaults;\n jobs: VeoVideoJobMap;\n record: RecordConfig;\n upstreamBody: Record<string, unknown>;\n}): Promise<void> {\n const { job, key, testId, fixtures, defaults, jobs, record, upstreamBody } = args;\n const logger = defaults.logger;\n\n try {\n // Drill into response.generateVideoResponse.generatedSamples[0].video.uri.\n let uri: string | undefined;\n const response = upstreamBody.response;\n if (response !== null && typeof response === \"object\" && !Array.isArray(response)) {\n const gvr = (response as Record<string, unknown>).generateVideoResponse;\n if (gvr !== null && typeof gvr === \"object\" && !Array.isArray(gvr)) {\n const samples = (gvr as Record<string, unknown>).generatedSamples;\n const first = Array.isArray(samples) ? samples[0] : undefined;\n if (first !== null && typeof first === \"object\" && !Array.isArray(first)) {\n const video = (first as Record<string, unknown>).video;\n if (video !== null && typeof video === \"object\" && !Array.isArray(video)) {\n const rawUri = (video as Record<string, unknown>).uri;\n if (typeof rawUri === \"string\" && rawUri) uri = rawUri;\n }\n }\n }\n }\n if (!uri) {\n logger.warn(\n `Upstream Veo operation ${job.upstreamOperationName} completed without a usable Files-API uri — capture skipped, nothing persisted; the next completed poll retries`,\n );\n return;\n }\n\n const video: VideoResponse[\"video\"] = {\n id: job.upstreamOperationName,\n status: \"completed\",\n url: uri,\n };\n\n // World-generation guard: a fixtures reset landing during the await above\n // clears the job map — map identity is a valid proxy for \"same world\".\n if (jobs.get(key) !== job) {\n logger.warn(\n `Veo video capture for operation ${job.upstreamOperationName} discarded: the job map no longer holds this job (fixtures reset or TTL eviction) — nothing persisted`,\n );\n return;\n }\n persistFixture({\n record,\n providerKey: \"veo\",\n testId,\n fixture: { match: job.match, response: { video } },\n fixtures,\n logger,\n });\n\n // Mutate the entry into a terminal replay job: later polls serve locally.\n if (jobs.get(key) === job) {\n jobs.set(key, {\n kind: \"replay\",\n operationName: job.operationName,\n status: \"completed\",\n pollCount: 0,\n pollsBeforeInProgress: 0,\n pollsBeforeCompleted: 0,\n video: { ...video },\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\n `Veo video capture for operation ${job.upstreamOperationName} failed unexpectedly (${msg}) — fixture not persisted; the job keeps proxying live`,\n );\n } finally {\n // Close the capturing window when the map still holds this record job (a\n // step threw before the replay mutation). On the success path the entry\n // was just replaced; the detached object deliberately keeps capturing=true.\n if (jobs.get(key) === job) {\n job.capturing = false;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"veo-video.cjs","names":["flattenHeaders","getContext","getTestId","matchFixtureDiagnostic","applyChaosAsync","resolveStrictMode","strictNoMatchMessage","strictNoMatchLogLine","strictOverrideField","resolveResponse","isErrorResponse","responseGone","serializeErrorResponse","isVideoResponse","crypto","resolveProgression","testIdSuffix","resolveUpstreamUrl","prepareEgressHeaders","upstreamTimeoutSignal","readEnvelopeText","buildFixtureMatch","persistFixture","sanitizeHeaderValue"],"sources":["../src/veo-video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport type {\n ChatCompletionRequest,\n Fixture,\n HandlerDefaults,\n RecordConfig,\n VideoResponse,\n} from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n getContext,\n strictNoMatchMessage,\n strictNoMatchLogLine,\n} from \"./helpers.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaosAsync, responseGone } from \"./chaos.js\";\nimport { resolveProgression } from \"./fal.js\";\nimport {\n buildFixtureMatch,\n prepareEgressHeaders,\n persistFixture,\n sanitizeHeaderValue,\n} from \"./recorder.js\";\nimport { resolveUpstreamUrl } from \"./url.js\";\nimport { readEnvelopeText, testIdSuffix, upstreamTimeoutSignal } from \"./video-proxy-shared.js\";\n\n/**\n * Google Veo async video lifecycle mock. Submit\n * `POST /v1beta/models/{model}:predictLongRunning` returns\n * `{ name: \"operations/...\" }`; status `GET /v1beta/operations/{name}` polls\n * `done:false → done:true`. The Files-API `uri` is served AS-IS — aimock does\n * NOT proxy or capture video bytes. With `record.providers.veo` configured an\n * unmatched submit becomes a live interactive proxy (submit + poll forwarded\n * 1:1, eager fixture capture on terminal status). Strict mode still wins.\n *\n * ASSUMED Veo create body shape (the `@google/genai` :predictLongRunning\n * envelope from issue #278): `{ instances: [{ prompt, image? }], parameters }`.\n * Match surface is `instances[0].prompt` only.\n */\n\n/** Files-API-shaped placeholder served when a completed fixture omits a uri. */\nconst DEFAULT_VEO_FILES_URI = \"https://generativelanguage.googleapis.com/v1beta/files/placeholder\";\n\n// The `:predictLongRunning` envelope nests the prompt under instances[].\ninterface VeoVideoRequest {\n instances?: Array<{ prompt?: unknown; [key: string]: unknown }>;\n parameters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ─── VeoVideoJobMap (TTL + bounded) ─────────────────────────────────────────\n\nexport const VEO_VIDEO_MAX_ENTRIES = 10_000;\nconst VEO_VIDEO_TTL_MS = 3_600_000; // 1 hour\n\ntype VeoVideoStatus = \"pending\" | \"in_progress\" | \"completed\" | \"failed\";\n\ninterface VeoVideoReplayJob {\n kind: \"replay\";\n operationName: string;\n status: VeoVideoStatus;\n pollCount: number;\n pollsBeforeInProgress: number;\n pollsBeforeCompleted: number;\n video: VideoResponse[\"video\"];\n /** Latch for the empty-`error` authoring warn on failed polls (once/job). */\n emptyErrorWarned?: boolean;\n}\n\ninterface VeoVideoRecordJob {\n kind: \"record\";\n operationName: string;\n status: VeoVideoStatus;\n upstreamOperationName: string;\n upstreamPollingUrl: string;\n match: Fixture[\"match\"];\n capturing?: boolean;\n}\n\nexport type VeoVideoJob = VeoVideoReplayJob | VeoVideoRecordJob;\n\ninterface VeoVideoEntry {\n job: VeoVideoJob;\n createdAt: number;\n}\n\n/**\n * Per-testId job state for the Veo video handler. Mirrors OpenRouterVideoJobMap\n * (openrouter-video.ts): lazy TTL eviction on `get`, FIFO eviction of the\n * oldest entries on `set` when over capacity, delete-before-set TTL refresh,\n * monotonic world-generation counter for reset-mid-flight detection, no\n * background sweep timer. Keys are `${testId}:${operationName}`.\n */\nexport class VeoVideoJobMap {\n private readonly entries = new Map<string, VeoVideoEntry>();\n private worldGeneration = 0;\n\n get generation(): number {\n return this.worldGeneration;\n }\n\n get(key: string): VeoVideoJob | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VEO_VIDEO_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.job;\n }\n\n set(key: string, job: VeoVideoJob): void {\n this.entries.delete(key);\n this.entries.set(key, { job, createdAt: Date.now() });\n if (this.entries.size > VEO_VIDEO_MAX_ENTRIES) {\n const excess = this.entries.size - VEO_VIDEO_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 this.worldGeneration++;\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\n// ─── Job progression ────────────────────────────────────────────────────────\n\n/**\n * Maps the fixture's terminal video status onto the job lifecycle. Anything\n * that is not \"failed\" — including a fixture authored as \"processing\" — is\n * treated as completed, since this surface always drives jobs to a terminal\n * state.\n */\nfunction terminalStatus(job: VeoVideoReplayJob): VeoVideoStatus {\n return job.video.status === \"failed\" ? \"failed\" : \"completed\";\n}\n\n/**\n * Mutates a job in place to advance its state on a status poll.\n * `pending → in_progress → completed | failed` based on poll-count thresholds.\n * No-op once terminal. The in_progress threshold is checked first so a job\n * whose thresholds are equal still spends one poll in in_progress instead of\n * jumping straight to the terminal status (fal advanceJob semantics). The wire\n * value is derived from this internal status (pending/in_progress → done:false,\n * completed/failed → done:true).\n */\nfunction advanceVeoJob(job: VeoVideoReplayJob): void {\n if (job.status === \"completed\" || job.status === \"failed\") return;\n\n job.pollCount += 1;\n if (job.status === \"pending\" && job.pollCount >= job.pollsBeforeInProgress) {\n job.status = \"in_progress\";\n } else if (job.pollCount >= job.pollsBeforeCompleted) {\n job.status = terminalStatus(job);\n }\n}\n\n/** Gemini-style error envelope used by every Veo error response. */\nfunction geminiError(code: number, message: string, status: string): string {\n return JSON.stringify({ error: { code, message, status } });\n}\n\n/**\n * The done:true operation body for a completed replay job — the Files-API uri\n * is served as-is (the fixture's stored `video.url`, or the documented\n * placeholder when omitted).\n */\nfunction completedOperationBody(operationName: string, uri: string): Record<string, unknown> {\n return {\n name: operationName,\n done: true,\n response: {\n generateVideoResponse: {\n generatedSamples: [{ video: { uri } }],\n },\n },\n };\n}\n\n// ─── POST /v1beta/models/{model}:predictLongRunning — submit ─────────────────\n\nexport async function handleVeoVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n model: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n jobs: VeoVideoJobMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? `/v1beta/models/${model}:predictLongRunning`;\n const method = req.method ?? \"POST\";\n\n let videoReq: VeoVideoRequest;\n try {\n videoReq = JSON.parse(raw) as VeoVideoRequest;\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(res, 400, geminiError(400, `Malformed JSON: ${detail}`, \"INVALID_ARGUMENT\"));\n return;\n }\n\n // Reject bodies that parsed but are not a JSON object before touching fields.\n if (videoReq === null || typeof videoReq !== \"object\" || Array.isArray(videoReq)) {\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 geminiError(400, \"Request body must be a JSON object\", \"INVALID_ARGUMENT\"),\n );\n return;\n }\n\n // Prompt lives at instances[0].prompt (the @google/genai envelope).\n const firstInstance = Array.isArray(videoReq.instances) ? videoReq.instances[0] : undefined;\n const prompt = firstInstance?.prompt;\n // Synthesize a structurally valid journal body for field-validation 400s\n // (JournalEntry.body is ChatCompletionRequest | null). Strip reserved\n // underscore-prefixed keys so a request cannot spoof handler discriminators.\n const sanitized = Object.fromEntries(\n Object.entries(videoReq).filter(([key]) => !key.startsWith(\"_\")),\n );\n const parsedBody: ChatCompletionRequest = { ...sanitized, model, messages: [] };\n\n if (typeof prompt !== \"string\" || !prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: parsedBody,\n response: { status: 400, fixture: null },\n });\n const message =\n prompt === undefined\n ? \"Missing required parameter: 'instances[0].prompt'\"\n : \"Invalid type for parameter: 'instances[0].prompt' must be a non-empty string\";\n writeErrorResponse(res, 400, geminiError(400, message, \"INVALID_ARGUMENT\"));\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [{ role: \"user\", content: prompt }],\n _endpointType: \"video\",\n _videoProvider: \"veo\",\n _context: getContext(req),\n };\n\n const testId = getTestId(req);\n const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(\n `No fixture matched for Veo request (model=${model}, msg=\"${prompt.slice(0, 80)}\")`,\n );\n }\n\n // Chaos rolls AFTER body validation and fixture matching (mirrors the\n // OpenRouter submit). An unmatched submit is proxied upstream when record\n // mode has a veo provider AND strict would not win — label that roll \"proxy\".\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\n ? \"fixture\"\n : resolveStrictMode(defaults.strict, req.headers)\n ? \"internal\"\n : defaults.record?.providers.veo\n ? \"proxy\"\n : \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n // Strict mode wins over record: a strict no-match fails loudly with 503.\n if (resolveStrictMode(defaults.strict, req.headers)) {\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(res, 503, geminiError(503, strictMessage, \"UNAVAILABLE\"));\n return;\n }\n\n if (defaults.record) {\n const outcome = await proxyVeoVideoSubmit({\n req,\n res,\n raw,\n syntheticReq,\n record: defaults.record,\n journal,\n defaults,\n jobs,\n method,\n path,\n });\n if (outcome === \"handled\") return;\n // outcome === \"no_upstream\" — fall through to 404 (fal convention).\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(res, 404, geminiError(404, \"No fixture matched\", \"NOT_FOUND\"));\n return;\n }\n\n // World-generation snapshot (mirrors the record-submit guard): a fixtures\n // reset can land while the fixture's ResponseFactory below is awaited, and\n // the job insertion at the bottom must not seed the NEW world.\n const worldGeneration = jobs.generation;\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n if (responseGone(res)) return;\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 if (!isVideoResponse(response)) {\n if (responseGone(res)) return;\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 geminiError(500, \"Fixture response is not a video type\", \"INTERNAL\"),\n );\n return;\n }\n\n if (responseGone(res)) return;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const fixtureStatus: string = response.video.status;\n if (fixtureStatus === \"processing\") {\n defaults.logger.warn(\n `Veo video fixture has status \"processing\" — treated as completed for the operations lifecycle`,\n );\n } else if (fixtureStatus !== \"completed\" && fixtureStatus !== \"failed\") {\n defaults.logger.warn(\n `Veo video fixture has unknown status \"${fixtureStatus}\" — treating as completed`,\n );\n }\n\n const operationName = `operations/${crypto.randomUUID()}`;\n const progression = resolveProgression(defaults.veoVideo);\n const job: VeoVideoReplayJob = {\n kind: \"replay\",\n operationName,\n status: \"pending\",\n pollCount: 0,\n pollsBeforeInProgress: progression.pollsBeforeInProgress,\n pollsBeforeCompleted: progression.pollsBeforeCompleted,\n video: { ...response.video },\n };\n // Default 0/0 progression seeds the job terminal at submit; the submit\n // envelope still reports a not-done operation.\n if (progression.pollsBeforeCompleted === 0) {\n job.status = terminalStatus(job);\n }\n if (jobs.generation === worldGeneration) {\n jobs.set(`${testId}:${operationName}`, job);\n } else {\n defaults.logger.warn(\n `Veo video submit resolved after a fixtures reset — not inserting operation ${operationName} into the new world (its polls will 404)`,\n );\n }\n\n // Embed the testId in the RETURNED name (not the stored key) so a multi-tenant\n // client can poll the opaque name without an x-test-id header — the testId\n // travels via getTestId's `?testId=` fallback. Mirrors OpenRouter's polling_url\n // treatment; testIdSuffix is \"\" for the default testId, keeping the name bare.\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ name: operationName + testIdSuffix(testId, \"?\") }));\n}\n\n// ─── GET /v1beta/operations/{name} — status poll ─────────────────────────────\n\nexport async function handleVeoVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n operationName: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n jobs: VeoVideoJobMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? `/v1beta/${operationName}`;\n const method = req.method ?? \"GET\";\n\n // Chaos rolls BEFORE the job lookup — the label stays \"internal\" even in\n // record mode, and a chaos-dropped poll never reaches the upstream.\n if (\n await applyChaosAsync(\n res,\n null,\n defaults.chaos,\n req.headers,\n req.url,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const key = `${testId}:${operationName}`;\n const job = jobs.get(key);\n\n if (!job) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n geminiError(404, `Operation ${operationName} not found`, \"NOT_FOUND\"),\n );\n return;\n }\n\n if (job.kind === \"record\") {\n // Strict means nothing reaches an upstream — a record job's polls are pure\n // upstream proxies, so an effective-strict request is refused with 503.\n if (resolveStrictMode(defaults.strict, req.headers)) {\n defaults.logger.error(\n `STRICT: Veo operation ${operationName} is proxied live upstream (record mode) — refusing the upstream poll`,\n );\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n geminiError(\n 503,\n `Strict mode: Veo operation ${operationName} is proxied live upstream (record mode) — nothing reaches an upstream under strict mode`,\n \"UNAVAILABLE\",\n ),\n );\n return;\n }\n await proxyVeoVideoRecordPoll({\n req,\n res,\n job,\n key,\n testId,\n fixtures,\n journal,\n defaults,\n jobs,\n method,\n path,\n });\n return;\n }\n\n // Guard BEFORE advancing or journaling (file convention): a disconnected\n // client consumes no progression step or TTL refresh.\n if (responseGone(res)) return;\n advanceVeoJob(job);\n // Refresh the TTL on every replay poll (delete-before-set also moves the\n // entry to the back of the FIFO eviction order).\n jobs.set(key, job);\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n let body: Record<string, unknown>;\n if (job.status === \"completed\") {\n // Truthy guard (not `??`): an empty-string fixture url must still fall back\n // to the placeholder Files-API uri rather than being served as an empty uri.\n const rawUrl = job.video.url;\n body = completedOperationBody(\n operationName,\n typeof rawUrl === \"string\" && rawUrl ? rawUrl : DEFAULT_VEO_FILES_URI,\n );\n } else if (job.status === \"failed\") {\n if (job.video.error === \"\" && !job.emptyErrorWarned) {\n job.emptyErrorWarned = true;\n defaults.logger.warn(\n `Veo video fixture for operation ${operationName} has an empty error message — using the default`,\n );\n }\n body = {\n name: operationName,\n done: true,\n error: { code: 3, message: job.video.error || \"Video generation failed\" },\n };\n } else {\n body = { name: operationName, done: false };\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n\n// ─── Record mode: live interactive proxy (submit) ───────────────────────────\n\n/**\n * Proxy an unmatched Veo submit to the configured upstream and answer the\n * client with a mock-rewritten envelope: a fresh aimock operation name. The\n * upstream lifecycle is driven interactively by the client's own polls.\n *\n * Returns \"no_upstream\" when record mode has no veo provider URL — the caller\n * falls through to its 404 branch (fal convention).\n */\nasync function proxyVeoVideoSubmit(args: {\n req: http.IncomingMessage;\n res: http.ServerResponse;\n raw: string;\n syntheticReq: ChatCompletionRequest;\n record: RecordConfig;\n journal: Journal;\n defaults: HandlerDefaults;\n jobs: VeoVideoJobMap;\n method: string;\n path: string;\n}): Promise<\"handled\" | \"no_upstream\"> {\n const { req, res, raw, syntheticReq, record, journal, defaults, jobs, method, path } = args;\n\n const upstreamBase = record.providers.veo;\n if (!upstreamBase) {\n defaults.logger.warn(`No upstream URL configured for provider \"veo\" — cannot proxy`);\n return \"no_upstream\";\n }\n\n const proxyError = (msg: string): \"handled\" => {\n defaults.logger.error(`Veo video submit proxy failed: ${msg}`);\n if (responseGone(res)) return \"handled\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 502,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 502,\n JSON.stringify({\n error: { message: `Proxy to upstream failed: ${msg}`, type: \"proxy_error\" },\n }),\n );\n return \"handled\";\n };\n\n const submitPath = `/v1beta/models/${syntheticReq.model}:predictLongRunning`;\n let submitUrl: URL;\n let upstreamOrigin: string;\n try {\n submitUrl = resolveUpstreamUrl(upstreamBase, submitPath);\n upstreamOrigin = new URL(upstreamBase).origin;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return proxyError(`Invalid upstream URL: ${upstreamBase} (${msg})`);\n }\n\n defaults.logger.warn(\n `NO FIXTURE MATCH — proxying Veo video submit to ${upstreamBase}${submitPath}`,\n );\n\n // World-generation snapshot: a fixtures reset landing during the upstream\n // fetch clears the job map — the insertion guard compares against this.\n const worldGeneration = jobs.generation;\n\n let fetched: { status: number; contentType: string | null; text: string };\n try {\n const headers = prepareEgressHeaders(req, submitUrl, \"veo\", record.providerKeys?.veo);\n if (!headers) return proxyError(\"No configured provider credential\");\n const upstreamRes = await fetch(submitUrl, {\n method: \"POST\",\n headers,\n body: raw,\n signal: upstreamTimeoutSignal(record),\n });\n fetched = {\n status: upstreamRes.status,\n contentType: upstreamRes.headers.get(\"content-type\"),\n text: await readEnvelopeText(upstreamRes, record),\n };\n } catch (err) {\n return proxyError(err instanceof Error ? err.message : \"Unknown proxy error\");\n }\n\n if (fetched.status === 401 || fetched.status === 403) {\n // Real-API fidelity: relay an upstream auth rejection verbatim.\n defaults.logger.warn(\n `Upstream rejected the Veo video submit (${fetched.status}) — relaying the upstream status`,\n );\n if (responseGone(res)) return \"handled\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: fetched.status,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n res.writeHead(fetched.status, { \"Content-Type\": fetched.contentType ?? \"application/json\" });\n res.end(fetched.text);\n return \"handled\";\n }\n\n let upstreamOperationName: string;\n {\n if (fetched.status < 200 || fetched.status >= 300) {\n return proxyError(`Submit ${fetched.status}: ${fetched.text.slice(0, 200)}`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(fetched.text);\n } catch {\n return proxyError(`Submit returned non-JSON: ${fetched.text.slice(0, 200)}`);\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return proxyError(\"Submit response is not a JSON object\");\n }\n upstreamOperationName = String((parsed as Record<string, unknown>).name ?? \"\").trim();\n if (!upstreamOperationName) {\n return proxyError(\"Submit response missing name\");\n }\n }\n\n // Veo has no polling_url field — the poll URL is constructed from the\n // provider base + `/v1beta/{operationName}`. Origin-validate the constructed\n // URL (the client's Authorization travels to it on every poll); fall back to\n // a string on the provider base on any parse failure.\n let upstreamPollingUrl: string;\n try {\n const constructed = resolveUpstreamUrl(\n upstreamBase,\n `/v1beta/${upstreamOperationName.replace(/^\\/+/, \"\")}`,\n );\n if (constructed.origin === upstreamOrigin) {\n upstreamPollingUrl = constructed.toString();\n } else {\n defaults.logger.warn(\n `Constructed Veo poll URL origin ${constructed.origin} differs from the configured provider origin ${upstreamOrigin} — using the provider-origin URL`,\n );\n upstreamPollingUrl = `${upstreamOrigin}/v1beta/${upstreamOperationName.replace(/^\\/+/, \"\")}`;\n }\n } catch {\n defaults.logger.warn(\n `Could not construct the Veo poll URL for ${upstreamOperationName} — using the provider-origin URL`,\n );\n upstreamPollingUrl = `${upstreamOrigin}/v1beta/${upstreamOperationName.replace(/^\\/+/, \"\")}`;\n }\n\n const testId = getTestId(req);\n const matchRequest = defaults.requestTransform\n ? defaults.requestTransform(syntheticReq)\n : syntheticReq;\n const operationName = `operations/${crypto.randomUUID()}`;\n const job: VeoVideoRecordJob = {\n kind: \"record\",\n operationName,\n status: \"pending\",\n upstreamOperationName,\n upstreamPollingUrl,\n match: buildFixtureMatch(matchRequest, record),\n };\n if (jobs.generation === worldGeneration) {\n jobs.set(`${testId}:${operationName}`, job);\n } else {\n defaults.logger.warn(\n `Veo video submit for upstream operation ${upstreamOperationName} completed after a fixtures reset — not inserting the job into the new world (its polls will 404)`,\n );\n }\n\n if (responseGone(res)) return \"handled\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 200,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n\n // Embed the testId in the RETURNED name (see the replay submit) so record-mode\n // multi-tenant polls resolve via `?testId=`; the upstream poll still uses the\n // bare job.operationName / job.upstreamPollingUrl, untouched by the suffix.\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ name: operationName + testIdSuffix(testId, \"?\") }));\n return \"handled\";\n}\n\n// ─── Record mode: live interactive proxy (poll + eager capture) ─────────────\n\n/**\n * Proxy a status poll for a record-mode Veo job 1:1 to the upstream and relay\n * the result with the operation name rewritten to the mock operation (the\n * Files-API uri inside `response` passes through verbatim — aimock never\n * downloads bytes). When the upstream reports `done:true` with a `response`,\n * the rewritten body is relayed IMMEDIATELY and the eager capture (persist the\n * uri as a fixture, mutate to a terminal replay job) runs DETACHED. A\n * `done:true` with an `error` persists a failed fixture synchronously. Under\n * `record.proxyOnly` nothing is captured, persisted, or mutated. Every\n * post-await map mutation is identity-guarded.\n */\nasync function proxyVeoVideoRecordPoll(args: {\n req: http.IncomingMessage;\n res: http.ServerResponse;\n job: VeoVideoRecordJob;\n key: string;\n testId: string;\n fixtures: Fixture[];\n journal: Journal;\n defaults: HandlerDefaults;\n jobs: VeoVideoJobMap;\n method: string;\n path: string;\n}): Promise<void> {\n const { req, res, job, key, testId, fixtures, journal, defaults, jobs, method, path } = args;\n const logger = defaults.logger;\n\n const journalProxy = (status: number): void => {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: {\n status,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n };\n\n const proxyError = (msg: string): void => {\n logger.error(`Veo video poll proxy failed: ${msg}`);\n if (responseGone(res)) return;\n journalProxy(502);\n writeErrorResponse(\n res,\n 502,\n JSON.stringify({\n error: { message: `Proxy to upstream failed: ${msg}`, type: \"proxy_error\" },\n }),\n );\n };\n\n // Recording can be disabled mid-flight — an orphaned record job must fail\n // loudly before contacting the upstream.\n const record = defaults.record;\n if (!record) {\n proxyError(\"record mode is no longer configured for an in-flight record job\");\n return;\n }\n\n let fetched: { status: number; contentType: string | null; text: string };\n try {\n const target = new URL(job.upstreamPollingUrl);\n const headers = prepareEgressHeaders(req, target, \"veo\", record.providerKeys?.veo);\n if (!headers) {\n proxyError(\"No configured provider credential\");\n return;\n }\n const upstreamRes = await fetch(job.upstreamPollingUrl, {\n headers,\n signal: upstreamTimeoutSignal(record),\n });\n fetched = {\n status: upstreamRes.status,\n contentType: upstreamRes.headers.get(\"content-type\"),\n text: await readEnvelopeText(upstreamRes, record),\n };\n } catch (err) {\n proxyError(err instanceof Error ? err.message : \"Unknown proxy error\");\n return;\n }\n\n if (fetched.status === 401 || fetched.status === 403) {\n logger.warn(\n `Upstream rejected the Veo status poll for operation ${job.upstreamOperationName} (${fetched.status}) — relaying the upstream status`,\n );\n if (responseGone(res)) return;\n journalProxy(fetched.status);\n res.writeHead(fetched.status, { \"Content-Type\": fetched.contentType ?? \"application/json\" });\n res.end(fetched.text);\n return;\n }\n\n let upstreamBody: Record<string, unknown>;\n {\n if (fetched.status < 200 || fetched.status >= 300) {\n proxyError(`Status ${fetched.status}: ${fetched.text.slice(0, 200)}`);\n return;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(fetched.text);\n } catch {\n proxyError(`Status returned non-JSON: ${fetched.text.slice(0, 200)}`);\n return;\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n proxyError(\"Status response is not a JSON object\");\n return;\n }\n upstreamBody = parsed as Record<string, unknown>;\n }\n\n // Rewrite ONLY the top-level operation name so no upstream identifier\n // escapes — the `response` (carrying the Files-API uri the client needs) and\n // every other field pass through verbatim.\n const relayBody: Record<string, unknown> = { ...upstreamBody, name: job.operationName };\n\n const relayJson = (): void => {\n if (responseGone(res)) return;\n journalProxy(200);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(relayBody));\n };\n\n const done = upstreamBody.done === true;\n const upstreamError = upstreamBody.error;\n const hasError =\n upstreamError !== undefined && upstreamError !== null && typeof upstreamError === \"object\";\n\n if (!done) {\n // Non-terminal: identity-guarded status write + TTL refresh, relay.\n if (jobs.get(key) === job) {\n if (!job.capturing && job.status !== \"completed\" && job.status !== \"failed\") {\n job.status = \"in_progress\";\n }\n jobs.set(key, job);\n }\n relayJson();\n return;\n }\n\n if (hasError) {\n // Terminal failure: persist a failed fixture synchronously (mirrors the\n // OpenRouter failed branch), then relay.\n if (record.proxyOnly) {\n if (jobs.get(key) === job) {\n job.status = \"failed\";\n jobs.set(key, job);\n }\n relayJson();\n return;\n }\n if (jobs.get(key) !== job) {\n // A concurrent terminal poll already persisted/replaced the entry, or a\n // fixtures reset cleared the world — relay without a duplicate fixture.\n relayJson();\n return;\n }\n const errObj = upstreamError as Record<string, unknown>;\n const rawMessage = errObj.message;\n const error = typeof rawMessage === \"string\" && rawMessage ? rawMessage : undefined;\n const video: VideoResponse[\"video\"] = {\n id: job.upstreamOperationName,\n status: \"failed\",\n ...(error !== undefined ? { error } : {}),\n };\n const persistResult = persistFixture({\n record,\n providerKey: \"veo\",\n testId,\n fixture: { match: job.match, response: { video } },\n fixtures,\n logger,\n });\n if (persistResult.kind === \"failed\" && !res.headersSent) {\n res.setHeader(\"X-AIMock-Record-Error\", sanitizeHeaderValue(persistResult.error));\n }\n jobs.set(key, {\n kind: \"replay\",\n operationName: job.operationName,\n status: \"failed\",\n pollCount: 0,\n pollsBeforeInProgress: 0,\n pollsBeforeCompleted: 0,\n video: { ...video },\n });\n relayJson();\n return;\n }\n\n // Terminal success (done:true with a response).\n if (record.proxyOnly) {\n if (jobs.get(key) === job) {\n job.status = \"completed\";\n jobs.set(key, job);\n }\n relayJson();\n return;\n }\n\n if (job.capturing || jobs.get(key) !== job) {\n // A concurrent poll already entered the capture sequence, or this\n // reference is detached — relay without starting a second capture and\n // never re-insert the stale object.\n if (jobs.get(key) === job) {\n jobs.set(key, job); // TTL refresh\n }\n relayJson();\n return;\n }\n\n // Open the capturing window SYNCHRONOUSLY before the first await.\n job.capturing = true;\n job.status = \"completed\";\n jobs.set(key, job); // TTL refresh — identity-checked above, no await since\n\n // Relay IMMEDIATELY; the persist + replay mutation runs DETACHED.\n relayJson();\n\n void captureVeoVideoRecordFixture({\n job,\n key,\n testId,\n fixtures,\n defaults,\n jobs,\n record,\n upstreamBody,\n });\n}\n\n/**\n * Detached eager-capture for a completed Veo record job. Extracts the\n * Files-API uri from the terminal poll body (NO download), persists a\n * fixture, and mutates the map entry into a terminal replay job. Every failure\n * is handled internally; the returned promise NEVER rejects. World-generation\n * guarded immediately before persist.\n */\nasync function captureVeoVideoRecordFixture(args: {\n job: VeoVideoRecordJob;\n key: string;\n testId: string;\n fixtures: Fixture[];\n defaults: HandlerDefaults;\n jobs: VeoVideoJobMap;\n record: RecordConfig;\n upstreamBody: Record<string, unknown>;\n}): Promise<void> {\n const { job, key, testId, fixtures, defaults, jobs, record, upstreamBody } = args;\n const logger = defaults.logger;\n\n try {\n // Drill into response.generateVideoResponse.generatedSamples[0].video.uri.\n let uri: string | undefined;\n const response = upstreamBody.response;\n if (response !== null && typeof response === \"object\" && !Array.isArray(response)) {\n const gvr = (response as Record<string, unknown>).generateVideoResponse;\n if (gvr !== null && typeof gvr === \"object\" && !Array.isArray(gvr)) {\n const samples = (gvr as Record<string, unknown>).generatedSamples;\n const first = Array.isArray(samples) ? samples[0] : undefined;\n if (first !== null && typeof first === \"object\" && !Array.isArray(first)) {\n const video = (first as Record<string, unknown>).video;\n if (video !== null && typeof video === \"object\" && !Array.isArray(video)) {\n const rawUri = (video as Record<string, unknown>).uri;\n if (typeof rawUri === \"string\" && rawUri) uri = rawUri;\n }\n }\n }\n }\n if (!uri) {\n logger.warn(\n `Upstream Veo operation ${job.upstreamOperationName} completed without a usable Files-API uri — capture skipped, nothing persisted; the next completed poll retries`,\n );\n return;\n }\n\n const video: VideoResponse[\"video\"] = {\n id: job.upstreamOperationName,\n status: \"completed\",\n url: uri,\n };\n\n // World-generation guard: a fixtures reset landing during the await above\n // clears the job map — map identity is a valid proxy for \"same world\".\n if (jobs.get(key) !== job) {\n logger.warn(\n `Veo video capture for operation ${job.upstreamOperationName} discarded: the job map no longer holds this job (fixtures reset or TTL eviction) — nothing persisted`,\n );\n return;\n }\n persistFixture({\n record,\n providerKey: \"veo\",\n testId,\n fixture: { match: job.match, response: { video } },\n fixtures,\n logger,\n });\n\n // Mutate the entry into a terminal replay job: later polls serve locally.\n if (jobs.get(key) === job) {\n jobs.set(key, {\n kind: \"replay\",\n operationName: job.operationName,\n status: \"completed\",\n pollCount: 0,\n pollsBeforeInProgress: 0,\n pollsBeforeCompleted: 0,\n video: { ...video },\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\n `Veo video capture for operation ${job.upstreamOperationName} failed unexpectedly (${msg}) — fixture not persisted; the job keeps proxying live`,\n );\n } finally {\n // Close the capturing window when the map still holds this record job (a\n // step threw before the replay mutation). On the success path the entry\n // was just replaced; the detached object deliberately keeps capturing=true.\n if (jobs.get(key) === job) {\n job.capturing = false;\n }\n }\n}\n"],"mappings":"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"}
|