@copilotkit/aimock 1.42.1 → 1.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +50 -0
- package/README.md +102 -16
- package/dist/agui-mock.cjs +1 -1
- package/dist/agui-mock.cjs.map +1 -1
- package/dist/agui-mock.d.cts.map +1 -1
- package/dist/agui-mock.d.ts.map +1 -1
- package/dist/agui-mock.js +1 -1
- package/dist/agui-mock.js.map +1 -1
- package/dist/agui-recorder.cjs +33 -11
- package/dist/agui-recorder.cjs.map +1 -1
- package/dist/agui-recorder.d.cts +10 -1
- package/dist/agui-recorder.d.cts.map +1 -1
- package/dist/agui-recorder.d.ts +10 -1
- package/dist/agui-recorder.d.ts.map +1 -1
- package/dist/agui-recorder.js +33 -11
- package/dist/agui-recorder.js.map +1 -1
- package/dist/agui-types.d.cts +1 -0
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts +1 -0
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +38 -10
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.d.cts +5 -0
- package/dist/aimock-cli.d.cts.map +1 -1
- package/dist/aimock-cli.d.ts +5 -0
- package/dist/aimock-cli.d.ts.map +1 -1
- package/dist/aimock-cli.js +38 -10
- package/dist/aimock-cli.js.map +1 -1
- package/dist/batches.cjs +458 -0
- package/dist/batches.cjs.map +1 -0
- package/dist/batches.d.cts +57 -0
- package/dist/batches.d.cts.map +1 -0
- package/dist/batches.d.ts +57 -0
- package/dist/batches.d.ts.map +1 -0
- package/dist/batches.js +453 -0
- package/dist/batches.js.map +1 -0
- package/dist/bedrock-converse.cjs +12 -8
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +14 -10
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +10 -8
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +12 -10
- package/dist/bedrock.js.map +1 -1
- package/dist/byteplus-video.cjs +3 -3
- package/dist/byteplus-video.cjs.map +1 -1
- package/dist/byteplus-video.js +4 -4
- package/dist/byteplus-video.js.map +1 -1
- package/dist/chaos.cjs +622 -72
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts +164 -7
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts +164 -7
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +613 -74
- package/dist/chaos.js.map +1 -1
- package/dist/cli.cjs +42 -23
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +42 -23
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +10 -8
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +12 -10
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/convert.cjs +1 -1
- package/dist/convert.cjs.map +1 -1
- package/dist/convert.js +1 -1
- package/dist/convert.js.map +1 -1
- package/dist/elevenlabs-audio.cjs +3 -3
- package/dist/elevenlabs-audio.cjs.map +1 -1
- package/dist/elevenlabs-audio.js +4 -4
- package/dist/elevenlabs-audio.js.map +1 -1
- package/dist/elevenlabs-voice.cjs +1053 -0
- package/dist/elevenlabs-voice.cjs.map +1 -0
- package/dist/elevenlabs-voice.d.cts +72 -0
- package/dist/elevenlabs-voice.d.cts.map +1 -0
- package/dist/elevenlabs-voice.d.ts +72 -0
- package/dist/elevenlabs-voice.d.ts.map +1 -0
- package/dist/elevenlabs-voice.js +1048 -0
- package/dist/elevenlabs-voice.js.map +1 -0
- package/dist/embeddings.cjs +8 -4
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +9 -5
- package/dist/embeddings.js.map +1 -1
- package/dist/fal-audio.cjs +3 -3
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.js +4 -4
- package/dist/fal-audio.js.map +1 -1
- package/dist/fal.cjs +28 -4
- package/dist/fal.cjs.map +1 -1
- package/dist/fal.d.cts +16 -1
- package/dist/fal.d.cts.map +1 -1
- package/dist/fal.d.ts +16 -1
- package/dist/fal.d.ts.map +1 -1
- package/dist/fal.js +28 -5
- package/dist/fal.js.map +1 -1
- package/dist/files.cjs +1071 -0
- package/dist/files.cjs.map +1 -0
- package/dist/files.d.cts +68 -0
- package/dist/files.d.cts.map +1 -0
- package/dist/files.d.ts +68 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +1059 -0
- package/dist/files.js.map +1 -0
- package/dist/fine-tuning.cjs +1051 -0
- package/dist/fine-tuning.cjs.map +1 -0
- package/dist/fine-tuning.d.cts +96 -0
- package/dist/fine-tuning.d.cts.map +1 -0
- package/dist/fine-tuning.d.ts +96 -0
- package/dist/fine-tuning.d.ts.map +1 -0
- package/dist/fine-tuning.js +1044 -0
- package/dist/fine-tuning.js.map +1 -0
- package/dist/fixture-loader.cjs +0 -0
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts +37 -5
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts +37 -5
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +0 -0
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-embeddings.cjs +2 -2
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +3 -3
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +13 -7
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +15 -9
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +11 -7
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +13 -9
- package/dist/gemini.js.map +1 -1
- package/dist/grok-video.cjs +14 -14
- package/dist/grok-video.cjs.map +1 -1
- package/dist/grok-video.js +15 -15
- package/dist/grok-video.js.map +1 -1
- package/dist/helpers.cjs +221 -5
- 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 +213 -6
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +54 -123
- package/dist/images.cjs.map +1 -1
- package/dist/images.d.cts.map +1 -1
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js +55 -124
- package/dist/images.js.map +1 -1
- package/dist/index.cjs +41 -8
- package/dist/index.d.cts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +14 -10
- package/dist/jest.cjs +14 -7
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +3 -2
- package/dist/jest.d.cts.map +1 -1
- package/dist/jest.d.ts +3 -2
- package/dist/jest.d.ts.map +1 -1
- package/dist/jest.js +14 -7
- package/dist/jest.js.map +1 -1
- package/dist/journal.cjs +41 -4
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts +44 -3
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts +44 -3
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +41 -5
- package/dist/journal.js.map +1 -1
- package/dist/live-fixture.cjs +1192 -0
- package/dist/live-fixture.cjs.map +1 -0
- package/dist/live-fixture.js +1187 -0
- package/dist/live-fixture.js.map +1 -0
- package/dist/live-recorder.cjs +256 -0
- package/dist/live-recorder.cjs.map +1 -0
- package/dist/live-recorder.js +254 -0
- package/dist/live-recorder.js.map +1 -0
- package/dist/live-replay.cjs +286 -0
- package/dist/live-replay.cjs.map +1 -0
- package/dist/live-replay.js +285 -0
- package/dist/live-replay.js.map +1 -0
- package/dist/live-sanitize.cjs +196 -0
- package/dist/live-sanitize.cjs.map +1 -0
- package/dist/live-sanitize.js +196 -0
- package/dist/live-sanitize.js.map +1 -0
- package/dist/live-types.d.cts +71 -0
- package/dist/live-types.d.cts.map +1 -0
- package/dist/live-types.d.ts +71 -0
- package/dist/live-types.d.ts.map +1 -0
- package/dist/llmock.cjs +52 -41
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +16 -5
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +16 -5
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +53 -42
- package/dist/llmock.js.map +1 -1
- package/dist/messages.cjs +11 -7
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +13 -9
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +258 -5
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts +3 -1
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts +3 -1
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +255 -6
- package/dist/metrics.js.map +1 -1
- package/dist/moderation.cjs +10 -1
- package/dist/moderation.cjs.map +1 -1
- package/dist/moderation.d.cts.map +1 -1
- package/dist/moderation.d.ts.map +1 -1
- package/dist/moderation.js +10 -1
- package/dist/moderation.js.map +1 -1
- package/dist/ollama.cjs +5 -5
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.js +6 -6
- package/dist/ollama.js.map +1 -1
- package/dist/openrouter-video.cjs +5 -5
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.js +6 -6
- package/dist/openrouter-video.js.map +1 -1
- package/dist/recorder.cjs +45 -9
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +43 -11
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +4 -3
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.js +5 -5
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +20 -33
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +4 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts +4 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +20 -34
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +701 -625
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -0
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +704 -628
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +2 -2
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +3 -3
- package/dist/speech.js.map +1 -1
- package/dist/transcription.cjs +4 -4
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.js +5 -5
- package/dist/transcription.js.map +1 -1
- package/dist/types.d.cts +119 -16
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +119 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-cli.cjs +925 -0
- package/dist/validate-cli.cjs.map +1 -0
- package/dist/validate-cli.js +924 -0
- package/dist/validate-cli.js.map +1 -0
- package/dist/veo-video.cjs +13 -13
- package/dist/veo-video.cjs.map +1 -1
- package/dist/veo-video.js +14 -14
- package/dist/veo-video.js.map +1 -1
- package/dist/video.cjs +4 -4
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +5 -5
- package/dist/video.js.map +1 -1
- package/dist/vitest.cjs +13 -6
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +2 -1
- package/dist/vitest.d.cts.map +1 -1
- package/dist/vitest.d.ts +2 -1
- package/dist/vitest.d.ts.map +1 -1
- package/dist/vitest.js +14 -7
- package/dist/vitest.js.map +1 -1
- package/dist/watcher.cjs +2 -1
- package/dist/watcher.cjs.map +1 -1
- package/dist/watcher.js +2 -1
- package/dist/watcher.js.map +1 -1
- package/dist/ws-framing.cjs +150 -35
- package/dist/ws-framing.cjs.map +1 -1
- package/dist/ws-framing.d.cts +18 -3
- package/dist/ws-framing.d.cts.map +1 -1
- package/dist/ws-framing.d.ts +18 -3
- package/dist/ws-framing.d.ts.map +1 -1
- package/dist/ws-framing.js +151 -36
- package/dist/ws-framing.js.map +1 -1
- package/dist/ws-gemini-live.cjs +2 -2
- package/dist/ws-gemini-live.d.ts +2 -2
- package/dist/ws-gemini-live.js +2 -2
- package/dist/ws-live.cjs +401 -0
- package/dist/ws-live.cjs.map +1 -0
- package/dist/ws-live.js +400 -0
- package/dist/ws-live.js.map +1 -0
- package/dist/ws-realtime.cjs +46 -2
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts +2 -2
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +46 -2
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +2 -2
- package/dist/ws-responses.js +2 -2
- package/dist/ws-upstream.cjs +118 -0
- package/dist/ws-upstream.cjs.map +1 -0
- package/dist/ws-upstream.js +115 -0
- package/dist/ws-upstream.js.map +1 -0
- package/fixtures/openai-live-client.json +390 -0
- package/fixtures/openai-live-managed.json +709 -0
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -2,15 +2,16 @@ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
|
2
2
|
const require_constants = require('./constants.cjs');
|
|
3
3
|
const require_api_key_auth = require('./api-key-auth.cjs');
|
|
4
4
|
const require_helpers = require('./helpers.cjs');
|
|
5
|
+
const require_live_fixture = require('./live-fixture.cjs');
|
|
6
|
+
const require_sse_writer = require('./sse-writer.cjs');
|
|
7
|
+
const require_chaos = require('./chaos.cjs');
|
|
8
|
+
const require_fixture_loader = require('./fixture-loader.cjs');
|
|
9
|
+
const require_router = require('./router.cjs');
|
|
10
|
+
const require_recorder = require('./recorder.cjs');
|
|
5
11
|
const require_logger = require('./logger.cjs');
|
|
6
12
|
const require_journal = require('./journal.cjs');
|
|
7
|
-
const require_router = require('./router.cjs');
|
|
8
|
-
const require_fixture_loader = require('./fixture-loader.cjs');
|
|
9
|
-
const require_sse_writer = require('./sse-writer.cjs');
|
|
10
13
|
const require_interruption = require('./interruption.cjs');
|
|
11
14
|
const require_openrouter_chat = require('./openrouter-chat.cjs');
|
|
12
|
-
const require_chaos = require('./chaos.cjs');
|
|
13
|
-
const require_recorder = require('./recorder.cjs');
|
|
14
15
|
const require_responses = require('./responses.cjs');
|
|
15
16
|
const require_messages = require('./messages.cjs');
|
|
16
17
|
const require_gemini = require('./gemini.cjs');
|
|
@@ -30,22 +31,30 @@ const require_veo_video = require('./veo-video.cjs');
|
|
|
30
31
|
const require_grok_video = require('./grok-video.cjs');
|
|
31
32
|
const require_byteplus_video = require('./byteplus-video.cjs');
|
|
32
33
|
const require_elevenlabs_audio = require('./elevenlabs-audio.cjs');
|
|
34
|
+
const require_elevenlabs_voice = require('./elevenlabs-voice.cjs');
|
|
33
35
|
const require_ollama = require('./ollama.cjs');
|
|
34
36
|
const require_cohere = require('./cohere.cjs');
|
|
35
37
|
const require_search = require('./search.cjs');
|
|
36
38
|
const require_rerank = require('./rerank.cjs');
|
|
37
39
|
const require_moderation = require('./moderation.cjs');
|
|
40
|
+
const require_fine_tuning = require('./fine-tuning.cjs');
|
|
41
|
+
const require_files = require('./files.cjs');
|
|
42
|
+
const require_batches = require('./batches.cjs');
|
|
38
43
|
const require_ws_framing = require('./ws-framing.cjs');
|
|
44
|
+
const require_ws_live = require('./ws-live.cjs');
|
|
39
45
|
const require_ws_responses = require('./ws-responses.cjs');
|
|
40
46
|
const require_ws_realtime = require('./ws-realtime.cjs');
|
|
41
47
|
const require_ws_gemini_live = require('./ws-gemini-live.cjs');
|
|
42
48
|
const require_metrics = require('./metrics.cjs');
|
|
43
49
|
let node_http = require("node:http");
|
|
44
50
|
node_http = require_runtime.__toESM(node_http);
|
|
51
|
+
let node_async_hooks = require("node:async_hooks");
|
|
45
52
|
|
|
46
53
|
//#region src/server.ts
|
|
54
|
+
const liveClosers = /* @__PURE__ */ new WeakMap();
|
|
47
55
|
const COMPLETIONS_PATH = "/v1/chat/completions";
|
|
48
56
|
const RESPONSES_PATH = "/v1/responses";
|
|
57
|
+
const LIVE_PATH = "/v1/live/sessions";
|
|
49
58
|
const REALTIME_PATH = "/v1/realtime";
|
|
50
59
|
const GEMINI_LIVE_PATH = "/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent";
|
|
51
60
|
const MESSAGES_PATH = "/v1/messages";
|
|
@@ -66,10 +75,12 @@ const GEMINI_PREDICT_RE = /^\/v1beta\/models\/([^:]+):predict$/;
|
|
|
66
75
|
const ELEVENLABS_SOUND_GENERATION_PATH = "/v1/sound-generation";
|
|
67
76
|
const ELEVENLABS_TTS_RE = /^\/v1\/text-to-speech\/([^/]+)$/;
|
|
68
77
|
const ELEVENLABS_MUSIC_RE = /^\/v1\/music(?:\/(.+))?$/;
|
|
78
|
+
const ELEVENLABS_VOICE_DESIGN_PATH = "/v1/text-to-voice/design";
|
|
79
|
+
const ELEVENLABS_VOICE_CREATE_PATH = "/v1/text-to-voice";
|
|
80
|
+
const ELEVENLABS_VOICE_RE = /^\/v1\/voices\/([^/]+)$/;
|
|
69
81
|
const FAL_QUEUE_SUBMIT_RE = /^\/fal\/queue\/submit\/(.+)$/;
|
|
70
82
|
const FAL_QUEUE_REQUESTS_RE = /^\/fal\/queue\/requests\/(.+)$/;
|
|
71
83
|
const FAL_RUN_RE = /^\/fal\/run\/(.+)$/;
|
|
72
|
-
const FAL_PREFIX_RE = /^\/fal(?:\/.*)?$/;
|
|
73
84
|
const DEFAULT_CHUNK_SIZE = 20;
|
|
74
85
|
const COMPAT_SUFFIXES = [
|
|
75
86
|
"/chat/completions",
|
|
@@ -118,6 +129,14 @@ const HEALTH_PATH = "/health";
|
|
|
118
129
|
const READY_PATH = "/ready";
|
|
119
130
|
const MODELS_PATH = "/v1/models";
|
|
120
131
|
const REQUESTS_PATH = "/v1/_requests";
|
|
132
|
+
const BATCHES_PATH = "/v1/batches";
|
|
133
|
+
const BATCHES_ID_RE = /^\/v1\/batches\/([^/]+)$/;
|
|
134
|
+
const BATCHES_CANCEL_RE = /^\/v1\/batches\/([^/]+)\/cancel$/;
|
|
135
|
+
const FILES_PATH = "/v1/files";
|
|
136
|
+
const FINE_TUNING_JOBS_PATH = "/v1/fine_tuning/jobs";
|
|
137
|
+
const FINE_TUNING_ID_RE = /^\/v1\/fine_tuning\/jobs\/([^/]+)$/;
|
|
138
|
+
const FINE_TUNING_CANCEL_RE = /^\/v1\/fine_tuning\/jobs\/([^/]+)\/cancel$/;
|
|
139
|
+
const FINE_TUNING_EVENTS_RE = /^\/v1\/fine_tuning\/jobs\/([^/]+)\/events$/;
|
|
121
140
|
const DEFAULT_MODELS = [
|
|
122
141
|
"gpt-4",
|
|
123
142
|
"gpt-4o",
|
|
@@ -129,7 +148,7 @@ const CORS_HEADERS = {
|
|
|
129
148
|
"Access-Control-Allow-Origin": "*",
|
|
130
149
|
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
|
|
131
150
|
"Access-Control-Allow-Headers": "*",
|
|
132
|
-
"Access-Control-Expose-Headers": "X-Total-Count"
|
|
151
|
+
"Access-Control-Expose-Headers": "X-Total-Count, X-Request-Id"
|
|
133
152
|
};
|
|
134
153
|
function setCorsHeaders(res) {
|
|
135
154
|
for (const [key, value] of Object.entries(CORS_HEADERS)) res.setHeader(key, value);
|
|
@@ -157,14 +176,18 @@ const JOURNAL_PARAMS = new Set([
|
|
|
157
176
|
"method",
|
|
158
177
|
"status",
|
|
159
178
|
"service",
|
|
160
|
-
"testId"
|
|
179
|
+
"testId",
|
|
180
|
+
"requestId"
|
|
161
181
|
]);
|
|
162
182
|
/**
|
|
163
183
|
* Perform a full reset: clear the fixtures array, the journal (entries *and*
|
|
164
184
|
* per-test fixture match-counts, i.e. sequence position), the video and fal.ai
|
|
165
|
-
* job/queue state, the
|
|
166
|
-
*
|
|
167
|
-
*
|
|
185
|
+
* job/queue state, the fine-tuning store (jobs, their append-only event logs,
|
|
186
|
+
* their poll counts, the create-time suffixes their model names are built from,
|
|
187
|
+
* and the module's monotonic clock), the ElevenLabs Voice Design store, the
|
|
188
|
+
* Gemini interaction/event-id counters, and any runtime chaos override
|
|
189
|
+
* (reverting to the construction-time chaos config), then re-zero the
|
|
190
|
+
* `aimock_fixtures_loaded` gauge.
|
|
168
191
|
*
|
|
169
192
|
* `targets` is `null` when no server is running (an in-process `reset()` before
|
|
170
193
|
* `start()`). The process-global generation state is reset either way, since it
|
|
@@ -174,13 +197,19 @@ const JOURNAL_PARAMS = new Set([
|
|
|
174
197
|
* `POST /__aimock/reset/fixtures` alias, and `LLMock.reset()`.
|
|
175
198
|
*/
|
|
176
199
|
function performFullReset(fixtures, targets) {
|
|
177
|
-
fixtures
|
|
200
|
+
require_fixture_loader.clearFixtureQueue(fixtures);
|
|
178
201
|
require_fal_audio.falJobs.clear();
|
|
179
202
|
require_fal.falQueueStates.clear();
|
|
203
|
+
require_batches.clearBatchStore();
|
|
204
|
+
require_elevenlabs_voice.clearElevenLabsVoices();
|
|
205
|
+
require_files.clearFileStore();
|
|
206
|
+
require_fine_tuning.clearFineTuningStore();
|
|
180
207
|
require_gemini_interactions.resetInteractionCounter();
|
|
181
208
|
require_gemini_interactions.resetEventIdCounter();
|
|
182
209
|
if (!targets) return;
|
|
210
|
+
liveClosers.get(targets.defaults)?.();
|
|
183
211
|
targets.journal.clear();
|
|
212
|
+
require_chaos.resetChaosWarnings(targets.defaults.logger);
|
|
184
213
|
targets.defaults.chaos = void 0;
|
|
185
214
|
targets.videoStates.clear();
|
|
186
215
|
targets.openRouterVideoJobs.clear();
|
|
@@ -232,22 +261,18 @@ function fixtureResponseKind(response) {
|
|
|
232
261
|
return "unknown";
|
|
233
262
|
}
|
|
234
263
|
/**
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
264
|
+
* The testId a journal entry was scoped under — `resolveTestId` applied to the
|
|
265
|
+
* journaled headers and path, i.e. the SAME function that scoped the request
|
|
266
|
+
* (fixture match-counts, chaos) when it arrived. Node folds a repeated
|
|
267
|
+
* `X-Test-Id` into one string ("a, a") before either side sees it, and the
|
|
268
|
+
* request is counted and chaos-evaluated under that folded string, so the
|
|
269
|
+
* `?testId=` filter matches it verbatim too: no token-splitting here that the
|
|
270
|
+
* scoping path does not also do. (Splitting on "," additionally broke every
|
|
271
|
+
* legitimately comma-bearing id.) A raw `path.includes("testId=t1")` both
|
|
272
|
+
* prefix-collides with `t10` and matches unrelated params like `notTestId`.
|
|
241
273
|
*/
|
|
242
274
|
function journalEntryTestId(entry) {
|
|
243
|
-
|
|
244
|
-
if (header) return header;
|
|
245
|
-
const qIdx = entry.path.indexOf("?");
|
|
246
|
-
if (qIdx !== -1) {
|
|
247
|
-
const queryValue = new URLSearchParams(entry.path.slice(qIdx + 1)).get("testId");
|
|
248
|
-
if (queryValue) return queryValue;
|
|
249
|
-
}
|
|
250
|
-
return require_constants.DEFAULT_TEST_ID;
|
|
275
|
+
return require_helpers.resolveTestId(entry.headers, entry.path);
|
|
251
276
|
}
|
|
252
277
|
/**
|
|
253
278
|
* The testId a chaos override is stored under, and read back with — resolved by
|
|
@@ -274,10 +299,14 @@ function writeBlankTestId(res) {
|
|
|
274
299
|
res.end(JSON.stringify({ error: "Invalid 'X-Test-Id': header is present but empty" }));
|
|
275
300
|
return true;
|
|
276
301
|
}
|
|
277
|
-
/**
|
|
302
|
+
/**
|
|
303
|
+
* The chaos config in effect for one testId: its override, else the baseline —
|
|
304
|
+
* one or the other, never the two merged. Mirrors `resolveScopedDefaults` in
|
|
305
|
+
* chaos.ts, so what `GET /__aimock/chaos` reports for a scope is exactly what
|
|
306
|
+
* that scope's traffic is evaluated against.
|
|
307
|
+
*/
|
|
278
308
|
function effectiveChaos(defaults, scopeId) {
|
|
279
|
-
|
|
280
|
-
if (scoped) return scoped;
|
|
309
|
+
if (defaults.chaosByTestId?.has(scopeId)) return defaults.chaosByTestId.get(scopeId) ?? {};
|
|
281
310
|
const current = defaults.chaos;
|
|
282
311
|
if (!current) return {};
|
|
283
312
|
return require_chaos.isChaosScope(current) ? current.base ?? {} : current;
|
|
@@ -322,6 +351,7 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
322
351
|
const methodFilter = searchParams.get("method");
|
|
323
352
|
const serviceFilter = searchParams.get("service");
|
|
324
353
|
const testIdFilter = searchParams.get("testId");
|
|
354
|
+
const requestIdFilter = searchParams.get("requestId");
|
|
325
355
|
let entries = journal.getAll();
|
|
326
356
|
if (methodFilter !== null) {
|
|
327
357
|
const want = methodFilter.toUpperCase();
|
|
@@ -331,6 +361,7 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
331
361
|
if (statusFilter !== void 0) entries = entries.filter((e) => e.response.status === statusFilter);
|
|
332
362
|
if (serviceFilter !== null) entries = entries.filter((e) => e.service === serviceFilter);
|
|
333
363
|
if (testIdFilter !== null) entries = entries.filter((e) => journalEntryTestId(e) === testIdFilter);
|
|
364
|
+
if (requestIdFilter !== null) entries = entries.filter((e) => e.headers["x-request-id"] === requestIdFilter);
|
|
334
365
|
const total = entries.length;
|
|
335
366
|
if (offset > 0) entries = entries.slice(offset);
|
|
336
367
|
if (limit >= 0) entries = entries.slice(0, limit);
|
|
@@ -364,7 +395,7 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
364
395
|
fixtures: fixtures.map((fixture, index) => ({
|
|
365
396
|
index,
|
|
366
397
|
match: redactForInspection(fixture.match),
|
|
367
|
-
responseKind: fixtureResponseKind(fixture.response),
|
|
398
|
+
responseKind: require_fixture_loader.isOneShotError(fixture) ? "error" : fixtureResponseKind(fixture.response),
|
|
368
399
|
...fixture.latency !== void 0 ? { latency: fixture.latency } : {},
|
|
369
400
|
...fixture.chaos !== void 0 ? { chaos: fixture.chaos } : {}
|
|
370
401
|
}))
|
|
@@ -414,26 +445,29 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
414
445
|
res.end(JSON.stringify({ error: "Invalid body: expected a JSON object" }));
|
|
415
446
|
return true;
|
|
416
447
|
}
|
|
417
|
-
const
|
|
418
|
-
"dropRate",
|
|
419
|
-
"malformedRate",
|
|
420
|
-
"disconnectRate"
|
|
421
|
-
];
|
|
422
|
-
for (const key of Object.keys(parsed)) if (!allowed.includes(key)) {
|
|
448
|
+
for (const key of Object.keys(parsed)) if (!require_chaos.CHAOS_FIELD_NAMES.includes(key)) {
|
|
423
449
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
424
450
|
res.end(JSON.stringify({ error: `Unknown chaos field: '${key}'` }));
|
|
425
451
|
return true;
|
|
426
452
|
}
|
|
427
453
|
const next = {};
|
|
428
|
-
for (const key of
|
|
454
|
+
for (const key of require_chaos.CHAOS_FIELD_NAMES) {
|
|
429
455
|
const value = parsed[key];
|
|
430
456
|
if (value === void 0) continue;
|
|
431
|
-
|
|
457
|
+
const accepted = typeof value === "number" ? require_chaos.parseChaosField(key, value) : void 0;
|
|
458
|
+
if (accepted === void 0) {
|
|
459
|
+
const shape = require_chaos.CHAOS_FIELDS[key].integer ? "a whole number of ms" : "a number";
|
|
432
460
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
433
|
-
res.end(JSON.stringify({ error: `Invalid '${key}': must be
|
|
461
|
+
res.end(JSON.stringify({ error: `Invalid '${key}': must be ${shape} between 0 and ${require_chaos.CHAOS_FIELDS[key].max}` }));
|
|
434
462
|
return true;
|
|
435
463
|
}
|
|
436
|
-
next[key] =
|
|
464
|
+
next[key] = accepted;
|
|
465
|
+
}
|
|
466
|
+
const shadowed = effectiveChaos(defaults, scopeId);
|
|
467
|
+
const droppedFields = Object.keys(shadowed).filter((key) => shadowed[key] !== void 0 && next[key] === void 0);
|
|
468
|
+
if (droppedFields.length > 0) {
|
|
469
|
+
const lost = droppedFields.map((key) => `${key}=${shadowed[key]}`).join(", ");
|
|
470
|
+
defaults.logger.warn(`[chaos] POST /__aimock/chaos (testId '${scopeId}') replaces the chaos config for this scope wholesale, it is not merged: ${lost} no longer applies here. Restate the field in the body to keep it.`);
|
|
437
471
|
}
|
|
438
472
|
defaults.chaosByTestId?.set(scopeId, next);
|
|
439
473
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -483,7 +517,7 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
483
517
|
return true;
|
|
484
518
|
}
|
|
485
519
|
if (subPath === "/fixtures" && req.method === "DELETE") {
|
|
486
|
-
fixtures
|
|
520
|
+
require_fixture_loader.clearFixtureQueue(fixtures);
|
|
487
521
|
if (defaults.registry) defaults.registry.setGauge("aimock_fixtures_loaded", {}, fixtures.length);
|
|
488
522
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
489
523
|
res.end(JSON.stringify({ cleared: true }));
|
|
@@ -577,32 +611,7 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
577
611
|
}
|
|
578
612
|
}
|
|
579
613
|
}
|
|
580
|
-
|
|
581
|
-
match: { predicate: () => true },
|
|
582
|
-
response: {
|
|
583
|
-
error: {
|
|
584
|
-
message: errorBody?.message ?? "Injected error",
|
|
585
|
-
type: errorBody?.type ?? "server_error",
|
|
586
|
-
code: errorBody?.code
|
|
587
|
-
},
|
|
588
|
-
status
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
fixtures.unshift(errorFixture);
|
|
592
|
-
let consumed = false;
|
|
593
|
-
const original = errorFixture.match.predicate;
|
|
594
|
-
errorFixture.match.predicate = (req) => {
|
|
595
|
-
if (consumed) return false;
|
|
596
|
-
const result = original(req);
|
|
597
|
-
if (result) {
|
|
598
|
-
consumed = true;
|
|
599
|
-
queueMicrotask(() => {
|
|
600
|
-
const idx = fixtures.indexOf(errorFixture);
|
|
601
|
-
if (idx !== -1) fixtures.splice(idx, 1);
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
return result;
|
|
605
|
-
};
|
|
614
|
+
require_fixture_loader.queueOneShotError(fixtures, status, errorBody ?? void 0);
|
|
606
615
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
607
616
|
res.end(JSON.stringify({ queued: true }));
|
|
608
617
|
return true;
|
|
@@ -610,6 +619,19 @@ async function handleControlAPI(req, res, pathname, searchParams, fixtures, jour
|
|
|
610
619
|
handleNotFound(res, `Unknown control endpoint: ${pathname}`);
|
|
611
620
|
return true;
|
|
612
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* The client tore the connection down before its request body had fully
|
|
624
|
+
* arrived. Node rejects the pending body read with `aborted` (ECONNRESET) and
|
|
625
|
+
* destroys the response, so the rejection surfaces in the handler's read arm
|
|
626
|
+
* looking like any other thrown error. It is caller behaviour, not a server
|
|
627
|
+
* fault: no status can reach the client, so none must be journaled as
|
|
628
|
+
* delivered. A body that blew its size cap also leaves the request destroyed
|
|
629
|
+
* and incomplete, but that one is aimock's own decision, not a peer abort.
|
|
630
|
+
*/
|
|
631
|
+
function clientAbortedMidBody(req, res, err) {
|
|
632
|
+
if (err instanceof require_helpers.RequestBodyTooLargeError) return false;
|
|
633
|
+
return res.destroyed && !req.complete;
|
|
634
|
+
}
|
|
613
635
|
async function handleCompletions(req, res, fixtures, journal, defaults, modelFallback, providerKey, openRouter = false) {
|
|
614
636
|
setCorsHeaders(res);
|
|
615
637
|
let raw;
|
|
@@ -617,19 +639,43 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
617
639
|
raw = await require_helpers.readBody(req);
|
|
618
640
|
} catch (err) {
|
|
619
641
|
const msg = err instanceof Error ? err.message : "Failed to read request body";
|
|
642
|
+
const clientFault = err instanceof require_helpers.RequestBodyTooLargeError;
|
|
643
|
+
const route = `${req.method ?? "POST"} ${req.url ?? COMPLETIONS_PATH}`;
|
|
644
|
+
const clientAbort = clientAbortedMidBody(req, res, err);
|
|
645
|
+
const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);
|
|
646
|
+
if (clientAbort || bodyLimitDisconnect) {
|
|
647
|
+
const interruptReason = bodyLimitDisconnect ? "request body exceeded size limit" : "client aborted";
|
|
648
|
+
defaults.logger.warn(bodyLimitDisconnect ? `${route}: ${msg}` : `${route}: client aborted mid-body (${msg})`);
|
|
649
|
+
journal.add({
|
|
650
|
+
method: req.method ?? "POST",
|
|
651
|
+
path: req.url ?? COMPLETIONS_PATH,
|
|
652
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
653
|
+
body: null,
|
|
654
|
+
response: {
|
|
655
|
+
status: 0,
|
|
656
|
+
fixture: null,
|
|
657
|
+
interrupted: true,
|
|
658
|
+
interruptReason
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const status = clientFault ? 400 : 500;
|
|
664
|
+
if (clientFault) defaults.logger.warn(`${route}: ${msg}`);
|
|
665
|
+
else defaults.logger.error(`${route}: ${msg}`);
|
|
620
666
|
journal.add({
|
|
621
667
|
method: req.method ?? "POST",
|
|
622
668
|
path: req.url ?? COMPLETIONS_PATH,
|
|
623
669
|
headers: require_helpers.flattenHeaders(req.headers),
|
|
624
670
|
body: null,
|
|
625
671
|
response: {
|
|
626
|
-
status
|
|
672
|
+
status,
|
|
627
673
|
fixture: null
|
|
628
674
|
}
|
|
629
675
|
});
|
|
630
|
-
require_sse_writer.writeErrorResponse(res,
|
|
676
|
+
require_sse_writer.writeErrorResponse(res, status, openRouter ? require_openrouter_chat.serializeOpenRouterError(status, `Request body read failed: ${msg}`) : JSON.stringify({ error: {
|
|
631
677
|
message: `Request body read failed: ${msg}`,
|
|
632
|
-
type: "server_error"
|
|
678
|
+
type: clientFault ? "invalid_request_error" : "server_error"
|
|
633
679
|
} }));
|
|
634
680
|
return;
|
|
635
681
|
}
|
|
@@ -705,7 +751,15 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
705
751
|
let preResolvedResponse = null;
|
|
706
752
|
let responseModel = body.model;
|
|
707
753
|
let fixtureCountIncremented = false;
|
|
708
|
-
|
|
754
|
+
const openRouterFallback = openRouter && Array.isArray(body.models) && body.models.length > 0;
|
|
755
|
+
const selectFixture = (probe, counts) => {
|
|
756
|
+
for (;;) {
|
|
757
|
+
const attempt = require_router.matchFixtureDiagnostic(fixtures, probe, counts, defaults.requestTransform, matchOptions);
|
|
758
|
+
if (attempt.fixture && require_fixture_loader.isOneShotError(attempt.fixture) && !require_fixture_loader.claimOneShotError(fixtures, attempt.fixture)) continue;
|
|
759
|
+
return attempt;
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
if (openRouterFallback) {
|
|
709
763
|
const candidates = require_openrouter_chat.buildOpenRouterCandidates(body);
|
|
710
764
|
let matchCounts = journal.getFixtureMatchCountsForTest(testId);
|
|
711
765
|
const allowFallbacks = body.provider?.allow_fallbacks !== false;
|
|
@@ -716,7 +770,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
716
770
|
...body,
|
|
717
771
|
model: candidate
|
|
718
772
|
};
|
|
719
|
-
const attempt =
|
|
773
|
+
const attempt = selectFixture(probe, matchCounts);
|
|
720
774
|
skippedBySequenceOrTurn = Math.max(skippedBySequenceOrTurn, attempt.skippedBySequenceOrTurn);
|
|
721
775
|
if (!attempt.fixture) return null;
|
|
722
776
|
const response = await require_helpers.resolveResponse(attempt.fixture, probe);
|
|
@@ -753,35 +807,48 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
753
807
|
preResolvedResponse = lastErrorResponse;
|
|
754
808
|
}
|
|
755
809
|
} else {
|
|
756
|
-
const single =
|
|
810
|
+
const single = selectFixture(body, journal.getFixtureMatchCountsForTest(testId));
|
|
757
811
|
fixture = single.fixture;
|
|
758
812
|
skippedBySequenceOrTurn = single.skippedBySequenceOrTurn;
|
|
759
813
|
}
|
|
760
814
|
if (fixture) {
|
|
761
815
|
if (!fixtureCountIncremented) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
762
|
-
defaults.logger.debug(`Fixture matched: ${
|
|
816
|
+
defaults.logger.debug(`Fixture matched: ${require_helpers.describeMatch(fixture.match, fixtures.indexOf(fixture))}`);
|
|
763
817
|
} else {
|
|
764
818
|
const lastUserMsg = body.messages.filter((m) => m.role === "user").pop();
|
|
765
819
|
const snippet = typeof lastUserMsg?.content === "string" ? lastUserMsg.content.slice(0, 80) : "";
|
|
766
820
|
defaults.logger.debug(`No fixture matched for request (model=${body.model ?? "?"}, msg="${snippet}")`);
|
|
767
821
|
}
|
|
768
|
-
const
|
|
822
|
+
const chaosConfig = require_chaos.resolveChaosConfig(fixture, defaults.chaos, req.headers, defaults.logger, req.url);
|
|
823
|
+
await require_chaos.awaitChaosLatency(fixture, defaults.chaos, req.headers, defaults.logger, req.url, res, chaosConfig);
|
|
824
|
+
const goneAfterLatency = require_chaos.responseGoneReason(res);
|
|
825
|
+
if (goneAfterLatency !== null) {
|
|
826
|
+
require_fixture_loader.releaseOneShotError(fixtures, fixture);
|
|
827
|
+
defaults.logger.debug(`[chaos] ${method} ${path}: ${require_chaos.describeUnwritableReason(goneAfterLatency)} after the latency delay — not served, not journalled`);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
const chaosAction = require_chaos.evaluateChaos(fixture, defaults.chaos, req.headers, defaults.logger, req.url, chaosConfig);
|
|
769
831
|
const chaosContext = {
|
|
770
832
|
method,
|
|
771
833
|
path,
|
|
772
834
|
headers: flatHeaders,
|
|
773
835
|
body
|
|
774
836
|
};
|
|
775
|
-
|
|
776
|
-
|
|
837
|
+
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
838
|
+
const missWouldProxy = require_helpers.wouldProxyMiss(effectiveStrict, defaults.record, providerKey);
|
|
839
|
+
const noFixtureSource = missWouldProxy ? "proxy" : "internal";
|
|
840
|
+
if (chaosAction === "drop" || chaosAction === "disconnect" || chaosAction === "rateLimit") {
|
|
841
|
+
require_chaos.applyChaosAction(chaosAction, res, fixture, journal, chaosContext, fixture ? "fixture" : noFixtureSource, defaults.registry, defaults.logger);
|
|
842
|
+
require_fixture_loader.releaseOneShotError(fixtures, fixture);
|
|
777
843
|
return;
|
|
778
844
|
}
|
|
779
|
-
if (
|
|
780
|
-
require_chaos.applyChaosAction(chaosAction, res, fixture, journal, chaosContext, "fixture", defaults.registry);
|
|
845
|
+
if (chaosAction === "malformed" && (fixture || !missWouldProxy)) {
|
|
846
|
+
require_chaos.applyChaosAction(chaosAction, res, fixture, journal, chaosContext, fixture ? "fixture" : "internal", defaults.registry, defaults.logger);
|
|
847
|
+
require_fixture_loader.releaseOneShotError(fixtures, fixture);
|
|
781
848
|
return;
|
|
782
849
|
}
|
|
783
850
|
if (!fixture) {
|
|
784
|
-
if (
|
|
851
|
+
if (effectiveStrict) {
|
|
785
852
|
const strictStatus = 503;
|
|
786
853
|
const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
|
|
787
854
|
defaults.logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", req.url ?? COMPLETIONS_PATH, skippedBySequenceOrTurn));
|
|
@@ -807,7 +874,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
807
874
|
if (defaults.record && providerKey) {
|
|
808
875
|
const hookOptions = chaosAction === "malformed" ? {
|
|
809
876
|
beforeWriteResponse: () => {
|
|
810
|
-
require_chaos.applyChaosAction(chaosAction, res, null, journal, chaosContext, "proxy", defaults.registry);
|
|
877
|
+
require_chaos.applyChaosAction(chaosAction, res, null, journal, chaosContext, "proxy", defaults.registry, defaults.logger);
|
|
811
878
|
return true;
|
|
812
879
|
},
|
|
813
880
|
onHookBypassed: (reason) => {
|
|
@@ -819,9 +886,22 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
819
886
|
});
|
|
820
887
|
}
|
|
821
888
|
} : void 0;
|
|
822
|
-
|
|
889
|
+
let clientHungUp = false;
|
|
890
|
+
const noteClientHangUp = () => {
|
|
891
|
+
if (!res.writableEnded) clientHungUp = true;
|
|
892
|
+
};
|
|
893
|
+
req.socket?.on("end", noteClientHangUp);
|
|
894
|
+
req.socket?.on("error", noteClientHangUp);
|
|
895
|
+
let outcome;
|
|
896
|
+
try {
|
|
897
|
+
outcome = await require_recorder.proxyAndRecord(req, res, body, providerKey, req.url ?? COMPLETIONS_PATH, fixtures, defaults, raw, hookOptions);
|
|
898
|
+
} finally {
|
|
899
|
+
req.socket?.off("end", noteClientHangUp);
|
|
900
|
+
req.socket?.off("error", noteClientHangUp);
|
|
901
|
+
}
|
|
823
902
|
if (outcome === "handled_by_hook") return;
|
|
824
903
|
if (outcome !== "not_configured") {
|
|
904
|
+
const destroyedMidStream = res.destroyed && !res.writableEnded;
|
|
825
905
|
journal.add({
|
|
826
906
|
method: req.method ?? "POST",
|
|
827
907
|
path: req.url ?? COMPLETIONS_PATH,
|
|
@@ -830,11 +910,19 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
830
910
|
response: {
|
|
831
911
|
status: res.statusCode ?? 200,
|
|
832
912
|
fixture: null,
|
|
833
|
-
source: "proxy"
|
|
913
|
+
source: "proxy",
|
|
914
|
+
...destroyedMidStream ? {
|
|
915
|
+
interrupted: true,
|
|
916
|
+
interruptReason: clientHungUp ? "client aborted" : "proxy stream destroyed"
|
|
917
|
+
} : {}
|
|
834
918
|
}
|
|
835
919
|
});
|
|
836
920
|
return;
|
|
837
921
|
}
|
|
922
|
+
if (chaosAction === "malformed") {
|
|
923
|
+
require_chaos.applyChaosAction(chaosAction, res, null, journal, chaosContext, "internal", defaults.registry, defaults.logger);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
838
926
|
}
|
|
839
927
|
journal.add({
|
|
840
928
|
method: req.method ?? "POST",
|
|
@@ -910,7 +998,7 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
910
998
|
const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
|
|
911
999
|
const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, responseModel, effectiveStrict, defaults.logger);
|
|
912
1000
|
const streaming = body.stream === true;
|
|
913
|
-
const
|
|
1001
|
+
const blockOutcome = response.blocks && response.blocks.length > 0 ? require_helpers.resolveFixtureBlockOutcome(response.blocks) : void 0;
|
|
914
1002
|
const journalEntry = journal.add({
|
|
915
1003
|
method: req.method ?? "POST",
|
|
916
1004
|
path: req.url ?? COMPLETIONS_PATH,
|
|
@@ -922,12 +1010,15 @@ async function handleCompletions(req, res, fixtures, journal, defaults, modelFal
|
|
|
922
1010
|
}
|
|
923
1011
|
});
|
|
924
1012
|
if (!streaming) {
|
|
925
|
-
const completion = require_helpers.buildContentWithToolCallsCompletion(response.content ?? "", response.toolCalls ?? [], responseModel, effReasoning,
|
|
1013
|
+
const completion = require_helpers.buildContentWithToolCallsCompletion(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? response.toolCalls ?? [], responseModel, effReasoning, blockOutcome ? {
|
|
1014
|
+
...overrides,
|
|
1015
|
+
finishReason: overrides?.finishReason ?? (blockOutcome.hasToolCalls ? "tool_calls" : "stop")
|
|
1016
|
+
} : overrides, body.messages);
|
|
926
1017
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
927
1018
|
res.end(JSON.stringify(shapeORCompletion(completion, overrides)));
|
|
928
1019
|
} else {
|
|
929
|
-
const chunks = require_helpers.buildContentWithToolCallsChunks(response.content ?? "", response.toolCalls ?? [], responseModel, chunkSize, effReasoning, overrides,
|
|
930
|
-
const completionText =
|
|
1020
|
+
const chunks = require_helpers.buildContentWithToolCallsChunks(blockOutcome?.content ?? response.content ?? "", blockOutcome?.toolCalls ?? response.toolCalls ?? [], responseModel, chunkSize, effReasoning, overrides, blockOutcome?.ordered);
|
|
1021
|
+
const completionText = blockOutcome ? blockOutcome.content + blockOutcome.toolCalls.map((tc) => tc.name + tc.arguments).join("") : (response.content ?? "") + (response.toolCalls ?? []).map((tc) => tc.name + tc.arguments).join("");
|
|
931
1022
|
const usageChunk = emitStreamingUsage ? require_helpers.buildUsageChunk(chunks[0]?.id ?? "chatcmpl-unknown", overrides?.model ?? responseModel, chunks[0]?.created ?? Math.floor(Date.now() / 1e3), resolveStreamingUsageTokens(overrides, completionText), overrides?.systemFingerprint) : void 0;
|
|
932
1023
|
shapeORChunks(chunks, usageChunk, overrides);
|
|
933
1024
|
const interruption = require_interruption.createInterruptionSignal(fixture);
|
|
@@ -1111,21 +1202,14 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1111
1202
|
}
|
|
1112
1203
|
};
|
|
1113
1204
|
if (options?.chaos) {
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
},
|
|
1123
|
-
{
|
|
1124
|
-
name: "disconnectRate",
|
|
1125
|
-
value: options.chaos.disconnectRate
|
|
1126
|
-
}
|
|
1127
|
-
];
|
|
1128
|
-
for (const { name, value } of chaosRates) if (value !== void 0 && (value < 0 || value > 1)) logger.warn(`Chaos ${name} (${value}) is outside 0-1 range — will be clamped at runtime`);
|
|
1205
|
+
const chaosDefaults = options.chaos;
|
|
1206
|
+
for (const field of require_chaos.CHAOS_FIELD_NAMES) {
|
|
1207
|
+
const value = chaosDefaults[field];
|
|
1208
|
+
if (value === void 0) continue;
|
|
1209
|
+
if (typeof value === "number" && require_chaos.parseChaosField(field, value) !== void 0) continue;
|
|
1210
|
+
const shape = require_chaos.CHAOS_FIELDS[field].integer ? "a whole number of ms" : "a number";
|
|
1211
|
+
logger.warn(`Chaos default ${field} value ${JSON.stringify(value)} — must be ${shape} in [0,${require_chaos.CHAOS_FIELDS[field].max}]; rejected at runtime, never clamped: this default is ignored`);
|
|
1212
|
+
}
|
|
1129
1213
|
}
|
|
1130
1214
|
for (const { name, config } of [
|
|
1131
1215
|
{
|
|
@@ -1171,62 +1255,241 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1171
1255
|
if (basePath !== void 0 && /(^|\/)api\/v3\/?$/.test(basePath)) throw new Error(`record.providers.byteplus (${bytePlusBase}) ends in /api/v3, but aimock appends the /api/v3 prefix itself — every BytePlus request would go to /api/v3/api/v3/... and fail upstream. Configure the ORIGIN only (e.g. https://ark.ap-southeast.bytepluses.com).`);
|
|
1172
1256
|
}
|
|
1173
1257
|
}
|
|
1258
|
+
/**
|
|
1259
|
+
* The in-flight request, scoped to the async execution that serves it.
|
|
1260
|
+
* Entered once in the `http.createServer` callback, so every handler —
|
|
1261
|
+
* including the ones in other modules that only ever see the shared
|
|
1262
|
+
* `journal` — runs inside it.
|
|
1263
|
+
*/
|
|
1264
|
+
const requestScope = new node_async_hooks.AsyncLocalStorage();
|
|
1265
|
+
/** The journal entry each request produced, keyed by the request object. */
|
|
1266
|
+
const ownJournalEntry = /* @__PURE__ */ new WeakMap();
|
|
1174
1267
|
const journal = new require_journal.Journal({
|
|
1175
1268
|
maxEntries: options?.journalMaxEntries ?? 1e3,
|
|
1176
|
-
fixtureCountsMaxTestIds: options?.fixtureCountsMaxTestIds ?? 500
|
|
1269
|
+
fixtureCountsMaxTestIds: options?.fixtureCountsMaxTestIds ?? 500,
|
|
1270
|
+
onAdd: (entry) => {
|
|
1271
|
+
const req = requestScope.getStore();
|
|
1272
|
+
if (req) ownJournalEntry.set(req, entry);
|
|
1273
|
+
}
|
|
1177
1274
|
});
|
|
1178
1275
|
const videoStates = new require_video.VideoStateMap();
|
|
1179
1276
|
const openRouterVideoJobs = new require_openrouter_video.OpenRouterVideoJobMap();
|
|
1180
1277
|
const veoVideoJobs = new require_veo_video.VeoVideoJobMap();
|
|
1181
1278
|
const grokVideoJobs = new require_grok_video.GrokVideoJobMap();
|
|
1182
1279
|
const bytePlusVideoJobs = new require_byteplus_video.BytePlusVideoJobMap();
|
|
1280
|
+
/**
|
|
1281
|
+
* The OpenAI error `type` that goes with a status: 4xx is the caller's
|
|
1282
|
+
* fault, everything else is ours. Shared by `routeError` and the envelopes
|
|
1283
|
+
* it calls so the body can never disagree with the status line.
|
|
1284
|
+
*/
|
|
1285
|
+
function errorTypeForStatus(status) {
|
|
1286
|
+
return status >= 400 && status < 500 ? "invalid_request_error" : "server_error";
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* The newest journal entry this request already produced, or null.
|
|
1290
|
+
*
|
|
1291
|
+
* Attribution is by the identity of the `IncomingMessage` the entry was
|
|
1292
|
+
* written under — never by `x-request-id`. That header is CALLER-supplied
|
|
1293
|
+
* (`resolveRequestId` echoes a well-formed one) and nothing makes it
|
|
1294
|
+
* unique: a retry, a harness that pins one id, or a load generator sends
|
|
1295
|
+
* the same id on many requests, and keying off it made a crash rewrite an
|
|
1296
|
+
* EARLIER request's entry while leaving the crashing request untraced. The
|
|
1297
|
+
* request object cannot be collided by a caller, so one entry belongs to
|
|
1298
|
+
* exactly one request. A handler writes at most one entry; if it writes
|
|
1299
|
+
* more, the newest wins, which is the entry the old scan would have found.
|
|
1300
|
+
*/
|
|
1301
|
+
function lastJournalEntryFor(req) {
|
|
1302
|
+
return ownJournalEntry.get(req) ?? null;
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Uniform terminal arm for a route handler that threw. Every route error
|
|
1306
|
+
* path logs the route, journals the failure, sets CORS and answers the error
|
|
1307
|
+
* envelope — so a handler crash is never invisible in the logs or in
|
|
1308
|
+
* `/__aimock/journal`.
|
|
1309
|
+
*
|
|
1310
|
+
* ONE request produces ONE entry. `res.headersSent` is not the test for that:
|
|
1311
|
+
* a handler that journaled its 200 and then threw before `writeHead` has
|
|
1312
|
+
* sent no headers, and journaling again would leave two contradicting
|
|
1313
|
+
* entries for one request. So the existing entry is looked up by request
|
|
1314
|
+
* identity ({@link lastJournalEntryFor}) and AMENDED — status to what the
|
|
1315
|
+
* client actually got when the response is still changeable, or interrupted
|
|
1316
|
+
* when it isn't — and a fresh entry is
|
|
1317
|
+
* added only when the handler journaled nothing. That holds after the
|
|
1318
|
+
* response too: a handler that answered and then crashed before its own
|
|
1319
|
+
* journal write gets an entry carrying the status already sent, so a
|
|
1320
|
+
* post-response crash is never invisible.
|
|
1321
|
+
*
|
|
1322
|
+
* Once headers are on the wire the status can't change, so the socket is
|
|
1323
|
+
* destroyed: a clean `end()` reads as EOF and the client treats a truncated
|
|
1324
|
+
* stream as a complete response. The chat-style SSE routes whose clients
|
|
1325
|
+
* surface an error frame pass `streamEvent`; that frame is written first,
|
|
1326
|
+
* but the tear-down still follows it.
|
|
1327
|
+
*
|
|
1328
|
+
* A body that blew its size cap is the CALLER's fault, not a server fault:
|
|
1329
|
+
* it logs at warn, but if the reader destroyed the socket it journals an
|
|
1330
|
+
* interruption with status 0 because no 4xx reached the client. A client
|
|
1331
|
+
* that hung up before its body arrived
|
|
1332
|
+
* ({@link clientAbortedMidBody}) is not a fault at all: it logs at warn and
|
|
1333
|
+
* journals a torn socket (`interrupted`, status 0), never a 500 the client
|
|
1334
|
+
* could not have received.
|
|
1335
|
+
*/
|
|
1336
|
+
function routeError(req, res, err, pathname, opts) {
|
|
1337
|
+
const route = `${req.method ?? "?"} ${pathname}`;
|
|
1338
|
+
const msg = err instanceof Error ? err.message : "Internal error";
|
|
1339
|
+
const clientFault = err instanceof require_helpers.RequestBodyTooLargeError;
|
|
1340
|
+
const clientAbort = clientAbortedMidBody(req, res, err);
|
|
1341
|
+
const status = clientFault ? 400 : 500;
|
|
1342
|
+
if (clientAbort) logger.warn(`${route}: client aborted mid-body (${msg})`);
|
|
1343
|
+
else if (clientFault) logger.warn(`${route}: ${msg}`);
|
|
1344
|
+
else logger.error(`${route}: ${msg}`);
|
|
1345
|
+
if (err instanceof Error && err.stack) logger.debug(err.stack);
|
|
1346
|
+
const existing = lastJournalEntryFor(req);
|
|
1347
|
+
const bodyLimitDisconnect = clientFault && (req.destroyed || res.destroyed);
|
|
1348
|
+
if ((clientAbort || bodyLimitDisconnect) && !res.headersSent) {
|
|
1349
|
+
const interruptReason = bodyLimitDisconnect ? "request body exceeded size limit" : "client aborted";
|
|
1350
|
+
if (existing) {
|
|
1351
|
+
if (!existing.response.interrupted) {
|
|
1352
|
+
existing.response.status = 0;
|
|
1353
|
+
existing.response.interrupted = true;
|
|
1354
|
+
existing.response.interruptReason = interruptReason;
|
|
1355
|
+
}
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
try {
|
|
1359
|
+
journal.add({
|
|
1360
|
+
method: req.method ?? "?",
|
|
1361
|
+
path: req.url ?? "?",
|
|
1362
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
1363
|
+
body: null,
|
|
1364
|
+
...opts?.service ? { service: opts.service } : {},
|
|
1365
|
+
response: {
|
|
1366
|
+
status: 0,
|
|
1367
|
+
fixture: null,
|
|
1368
|
+
source: "internal",
|
|
1369
|
+
interrupted: true,
|
|
1370
|
+
interruptReason
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
} catch (jErr) {
|
|
1374
|
+
logger.warn(`${route}: journal write failed after body-read interruption: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1375
|
+
}
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
if (!res.headersSent) {
|
|
1379
|
+
if (existing) existing.response.status = status;
|
|
1380
|
+
else try {
|
|
1381
|
+
journal.add({
|
|
1382
|
+
method: req.method ?? "?",
|
|
1383
|
+
path: req.url ?? "?",
|
|
1384
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
1385
|
+
body: null,
|
|
1386
|
+
...opts?.service ? { service: opts.service } : {},
|
|
1387
|
+
response: {
|
|
1388
|
+
status,
|
|
1389
|
+
fixture: null,
|
|
1390
|
+
source: "internal"
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
} catch (jErr) {
|
|
1394
|
+
logger.warn(`${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1395
|
+
}
|
|
1396
|
+
setCorsHeaders(res);
|
|
1397
|
+
require_sse_writer.writeErrorResponse(res, status, opts?.envelope ? opts.envelope(msg, status) : JSON.stringify({ error: {
|
|
1398
|
+
message: msg,
|
|
1399
|
+
type: errorTypeForStatus(status)
|
|
1400
|
+
} }));
|
|
1401
|
+
} else {
|
|
1402
|
+
const midStreamReason = clientAbort ? "client aborted" : "handler crashed mid-stream";
|
|
1403
|
+
if (existing) {
|
|
1404
|
+
if (res.writableEnded) {
|
|
1405
|
+
if (existing.response.error === void 0) existing.response.error = msg;
|
|
1406
|
+
} else if (!existing.response.interrupted) {
|
|
1407
|
+
existing.response.interrupted = true;
|
|
1408
|
+
existing.response.interruptReason = midStreamReason;
|
|
1409
|
+
}
|
|
1410
|
+
} else try {
|
|
1411
|
+
journal.add({
|
|
1412
|
+
method: req.method ?? "?",
|
|
1413
|
+
path: req.url ?? "?",
|
|
1414
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
1415
|
+
body: null,
|
|
1416
|
+
...opts?.service ? { service: opts.service } : {},
|
|
1417
|
+
response: {
|
|
1418
|
+
status: res.statusCode,
|
|
1419
|
+
fixture: null,
|
|
1420
|
+
source: "internal",
|
|
1421
|
+
...res.writableEnded ? { error: msg } : {
|
|
1422
|
+
interrupted: true,
|
|
1423
|
+
interruptReason: midStreamReason
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
} catch (jErr) {
|
|
1428
|
+
logger.warn(`${route}: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1429
|
+
}
|
|
1430
|
+
if (res.writableEnded) return;
|
|
1431
|
+
if (opts?.streamEvent) try {
|
|
1432
|
+
res.write(opts.streamEvent(msg, status), () => {
|
|
1433
|
+
if (!res.destroyed) res.destroy();
|
|
1434
|
+
});
|
|
1435
|
+
} catch (writeErr) {
|
|
1436
|
+
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1437
|
+
res.destroy();
|
|
1438
|
+
}
|
|
1439
|
+
else res.destroy();
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1183
1442
|
if (mounts) for (const { handler } of mounts) {
|
|
1184
1443
|
if (handler.setJournal) handler.setJournal(journal);
|
|
1185
1444
|
if (registry && handler.setRegistry) handler.setRegistry(registry);
|
|
1186
1445
|
}
|
|
1187
1446
|
if (registry) registry.setGauge("aimock_fixtures_loaded", {}, fixtures.length);
|
|
1188
1447
|
const server = node_http.createServer((req, res) => {
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const url = req.url ?? "?";
|
|
1194
|
-
defaults.logger.warn(`Unhandled request error on ${method} ${url}: ${msg}\n${stack}`);
|
|
1195
|
-
if (!res.headersSent) {
|
|
1196
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1197
|
-
res.end(JSON.stringify({ error: {
|
|
1198
|
-
message: msg,
|
|
1199
|
-
type: "server_error"
|
|
1200
|
-
} }));
|
|
1201
|
-
} else if (!res.writableEnded) res.end();
|
|
1448
|
+
requestScope.run(req, () => {
|
|
1449
|
+
handleHttpRequest(req, res).catch((err) => {
|
|
1450
|
+
routeError(req, res, err, req.url ?? "?");
|
|
1451
|
+
});
|
|
1202
1452
|
});
|
|
1203
1453
|
});
|
|
1204
1454
|
async function handleHttpRequest(req, res) {
|
|
1205
1455
|
const startTime = registry ? process.hrtime.bigint() : 0n;
|
|
1456
|
+
const { id: requestId, generated: requestIdMinted } = require_helpers.resolveRequestId(req.headers);
|
|
1457
|
+
req.headers["x-request-id"] = requestId;
|
|
1458
|
+
require_helpers.markMintedRequestId(req, requestIdMinted);
|
|
1459
|
+
res.setHeader("X-Request-Id", requestId);
|
|
1460
|
+
let pathname = "";
|
|
1461
|
+
if (registry) {
|
|
1462
|
+
let recorded = false;
|
|
1463
|
+
const recordOutcome = (status) => {
|
|
1464
|
+
if (recorded) return;
|
|
1465
|
+
recorded = true;
|
|
1466
|
+
try {
|
|
1467
|
+
const normalizedPath = require_metrics.normalizePathLabel(pathname, mounts ? mounts.map((m) => m.path) : []);
|
|
1468
|
+
const method = req.method ?? "UNKNOWN";
|
|
1469
|
+
registry.incrementCounter("aimock_requests_total", {
|
|
1470
|
+
method,
|
|
1471
|
+
path: normalizedPath,
|
|
1472
|
+
status
|
|
1473
|
+
});
|
|
1474
|
+
const elapsed = Number(process.hrtime.bigint() - startTime) / 1e9;
|
|
1475
|
+
registry.observeHistogram("aimock_request_duration_seconds", {
|
|
1476
|
+
method,
|
|
1477
|
+
path: normalizedPath
|
|
1478
|
+
}, elapsed);
|
|
1479
|
+
} catch (err) {
|
|
1480
|
+
defaults.logger.warn("metrics instrumentation error", err);
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
res.on("finish", () => recordOutcome(String(res.statusCode)));
|
|
1484
|
+
res.on("close", () => {
|
|
1485
|
+
if (!res.writableFinished) recordOutcome(require_metrics.DESTROYED_STATUS_LABEL);
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1206
1488
|
const parsedUrl = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
1207
|
-
|
|
1489
|
+
pathname = parsedUrl.pathname;
|
|
1208
1490
|
const originalPathname = pathname;
|
|
1209
1491
|
const isOpenRouter = require_openrouter_chat.isOpenRouterPath(originalPathname);
|
|
1210
1492
|
const isBytePlusArk = defaults.record?.providers.byteplus !== void 0 && originalPathname.startsWith("/api/v3/");
|
|
1211
|
-
if (registry) res.on("finish", () => {
|
|
1212
|
-
try {
|
|
1213
|
-
const normalizedPath = require_metrics.normalizePathLabel(pathname);
|
|
1214
|
-
const method = req.method ?? "UNKNOWN";
|
|
1215
|
-
const status = String(res.statusCode);
|
|
1216
|
-
registry.incrementCounter("aimock_requests_total", {
|
|
1217
|
-
method,
|
|
1218
|
-
path: normalizedPath,
|
|
1219
|
-
status
|
|
1220
|
-
});
|
|
1221
|
-
const elapsed = Number(process.hrtime.bigint() - startTime) / 1e9;
|
|
1222
|
-
registry.observeHistogram("aimock_request_duration_seconds", {
|
|
1223
|
-
method,
|
|
1224
|
-
path: normalizedPath
|
|
1225
|
-
}, elapsed);
|
|
1226
|
-
} catch (err) {
|
|
1227
|
-
defaults.logger.warn("metrics instrumentation error", err);
|
|
1228
|
-
}
|
|
1229
|
-
});
|
|
1230
1493
|
if (req.method === "OPTIONS" && (!resolvedAuth.policy.enabled || req.headers.origin !== void 0 && req.headers["access-control-request-method"] !== void 0)) {
|
|
1231
1494
|
handleOptions(res);
|
|
1232
1495
|
return;
|
|
@@ -1252,12 +1515,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1252
1515
|
try {
|
|
1253
1516
|
await require_ollama.handleOllama(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1254
1517
|
} catch (err) {
|
|
1255
|
-
|
|
1256
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1257
|
-
message: msg,
|
|
1258
|
-
type: "server_error"
|
|
1259
|
-
} }));
|
|
1260
|
-
else if (!res.writableEnded) res.destroy();
|
|
1518
|
+
routeError(req, res, err, pathname);
|
|
1261
1519
|
}
|
|
1262
1520
|
return;
|
|
1263
1521
|
}
|
|
@@ -1265,12 +1523,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1265
1523
|
try {
|
|
1266
1524
|
await require_ollama.handleOllamaGenerate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1267
1525
|
} catch (err) {
|
|
1268
|
-
|
|
1269
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1270
|
-
message: msg,
|
|
1271
|
-
type: "server_error"
|
|
1272
|
-
} }));
|
|
1273
|
-
else if (!res.writableEnded) res.destroy();
|
|
1526
|
+
routeError(req, res, err, pathname);
|
|
1274
1527
|
}
|
|
1275
1528
|
return;
|
|
1276
1529
|
}
|
|
@@ -1278,12 +1531,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1278
1531
|
try {
|
|
1279
1532
|
await require_ollama.handleOllamaEmbeddings(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1280
1533
|
} catch (err) {
|
|
1281
|
-
|
|
1282
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1283
|
-
message: msg,
|
|
1284
|
-
type: "server_error"
|
|
1285
|
-
} }));
|
|
1286
|
-
else if (!res.writableEnded) res.destroy();
|
|
1534
|
+
routeError(req, res, err, pathname);
|
|
1287
1535
|
}
|
|
1288
1536
|
return;
|
|
1289
1537
|
}
|
|
@@ -1308,28 +1556,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1308
1556
|
try {
|
|
1309
1557
|
await require_openrouter_video.handleOpenRouterVideoContent(req, res, openRouterVideoContentMatch[1], journal, defaults, setCorsHeaders, openRouterVideoJobs);
|
|
1310
1558
|
} catch (err) {
|
|
1311
|
-
|
|
1312
|
-
defaults.logger.error(`openrouter-video content: ${msg}`);
|
|
1313
|
-
if (!res.headersSent) {
|
|
1314
|
-
try {
|
|
1315
|
-
journal.add({
|
|
1316
|
-
method: req.method ?? "GET",
|
|
1317
|
-
path: req.url ?? pathname,
|
|
1318
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1319
|
-
body: null,
|
|
1320
|
-
response: {
|
|
1321
|
-
status: 500,
|
|
1322
|
-
fixture: null
|
|
1323
|
-
}
|
|
1324
|
-
});
|
|
1325
|
-
} catch (jErr) {
|
|
1326
|
-
defaults.logger.warn(`openrouter-video content: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1327
|
-
}
|
|
1328
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1329
|
-
message: msg,
|
|
1330
|
-
type: "server_error"
|
|
1331
|
-
} }));
|
|
1332
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1559
|
+
routeError(req, res, err, pathname);
|
|
1333
1560
|
}
|
|
1334
1561
|
return;
|
|
1335
1562
|
}
|
|
@@ -1337,28 +1564,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1337
1564
|
try {
|
|
1338
1565
|
await require_openrouter_video.handleOpenRouterVideoModels(req, res, fixtures, journal, defaults, setCorsHeaders);
|
|
1339
1566
|
} catch (err) {
|
|
1340
|
-
|
|
1341
|
-
defaults.logger.error(`openrouter-video models: ${msg}`);
|
|
1342
|
-
if (!res.headersSent) {
|
|
1343
|
-
try {
|
|
1344
|
-
journal.add({
|
|
1345
|
-
method: req.method ?? "GET",
|
|
1346
|
-
path: req.url ?? pathname,
|
|
1347
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1348
|
-
body: null,
|
|
1349
|
-
response: {
|
|
1350
|
-
status: 500,
|
|
1351
|
-
fixture: null
|
|
1352
|
-
}
|
|
1353
|
-
});
|
|
1354
|
-
} catch (jErr) {
|
|
1355
|
-
defaults.logger.warn(`openrouter-video models: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1356
|
-
}
|
|
1357
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1358
|
-
message: msg,
|
|
1359
|
-
type: "server_error"
|
|
1360
|
-
} }));
|
|
1361
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1567
|
+
routeError(req, res, err, pathname);
|
|
1362
1568
|
}
|
|
1363
1569
|
return;
|
|
1364
1570
|
}
|
|
@@ -1367,28 +1573,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1367
1573
|
try {
|
|
1368
1574
|
await require_openrouter_video.handleOpenRouterVideoStatus(req, res, openRouterVideoStatusMatch[1], fixtures, journal, defaults, setCorsHeaders, openRouterVideoJobs);
|
|
1369
1575
|
} catch (err) {
|
|
1370
|
-
|
|
1371
|
-
defaults.logger.error(`openrouter-video status: ${msg}`);
|
|
1372
|
-
if (!res.headersSent) {
|
|
1373
|
-
try {
|
|
1374
|
-
journal.add({
|
|
1375
|
-
method: req.method ?? "GET",
|
|
1376
|
-
path: req.url ?? pathname,
|
|
1377
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1378
|
-
body: null,
|
|
1379
|
-
response: {
|
|
1380
|
-
status: 500,
|
|
1381
|
-
fixture: null
|
|
1382
|
-
}
|
|
1383
|
-
});
|
|
1384
|
-
} catch (jErr) {
|
|
1385
|
-
defaults.logger.warn(`openrouter-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1386
|
-
}
|
|
1387
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1388
|
-
message: msg,
|
|
1389
|
-
type: "server_error"
|
|
1390
|
-
} }));
|
|
1391
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1576
|
+
routeError(req, res, err, pathname);
|
|
1392
1577
|
}
|
|
1393
1578
|
return;
|
|
1394
1579
|
}
|
|
@@ -1397,28 +1582,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1397
1582
|
try {
|
|
1398
1583
|
await require_openrouter_video.handleOpenRouterVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, openRouterVideoJobs);
|
|
1399
1584
|
} catch (err) {
|
|
1400
|
-
|
|
1401
|
-
defaults.logger.error(`openrouter-video submit: ${msg}`);
|
|
1402
|
-
if (!res.headersSent) {
|
|
1403
|
-
try {
|
|
1404
|
-
journal.add({
|
|
1405
|
-
method: req.method ?? "POST",
|
|
1406
|
-
path: req.url ?? pathname,
|
|
1407
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1408
|
-
body: null,
|
|
1409
|
-
response: {
|
|
1410
|
-
status: 500,
|
|
1411
|
-
fixture: null
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1414
|
-
} catch (jErr) {
|
|
1415
|
-
defaults.logger.warn(`openrouter-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1416
|
-
}
|
|
1417
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1418
|
-
message: msg,
|
|
1419
|
-
type: "server_error"
|
|
1420
|
-
} }));
|
|
1421
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1585
|
+
routeError(req, res, err, pathname);
|
|
1422
1586
|
}
|
|
1423
1587
|
return;
|
|
1424
1588
|
}
|
|
@@ -1427,28 +1591,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1427
1591
|
try {
|
|
1428
1592
|
await require_byteplus_video.handleBytePlusVideoStatus(req, res, bytePlusVideoStatusMatch[1], fixtures, journal, defaults, setCorsHeaders, bytePlusVideoJobs);
|
|
1429
1593
|
} catch (err) {
|
|
1430
|
-
|
|
1431
|
-
defaults.logger.error(`byteplus-video status: ${msg}`);
|
|
1432
|
-
if (!res.headersSent) {
|
|
1433
|
-
try {
|
|
1434
|
-
journal.add({
|
|
1435
|
-
method: req.method ?? "GET",
|
|
1436
|
-
path: req.url ?? pathname,
|
|
1437
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1438
|
-
body: null,
|
|
1439
|
-
response: {
|
|
1440
|
-
status: 500,
|
|
1441
|
-
fixture: null
|
|
1442
|
-
}
|
|
1443
|
-
});
|
|
1444
|
-
} catch (jErr) {
|
|
1445
|
-
defaults.logger.warn(`byteplus-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1446
|
-
}
|
|
1447
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1448
|
-
message: msg,
|
|
1449
|
-
type: "server_error"
|
|
1450
|
-
} }));
|
|
1451
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1594
|
+
routeError(req, res, err, pathname);
|
|
1452
1595
|
}
|
|
1453
1596
|
return;
|
|
1454
1597
|
}
|
|
@@ -1457,28 +1600,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1457
1600
|
try {
|
|
1458
1601
|
await require_byteplus_video.handleBytePlusVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, bytePlusVideoJobs);
|
|
1459
1602
|
} catch (err) {
|
|
1460
|
-
|
|
1461
|
-
defaults.logger.error(`byteplus-video submit: ${msg}`);
|
|
1462
|
-
if (!res.headersSent) {
|
|
1463
|
-
try {
|
|
1464
|
-
journal.add({
|
|
1465
|
-
method: req.method ?? "POST",
|
|
1466
|
-
path: req.url ?? pathname,
|
|
1467
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1468
|
-
body: null,
|
|
1469
|
-
response: {
|
|
1470
|
-
status: 500,
|
|
1471
|
-
fixture: null
|
|
1472
|
-
}
|
|
1473
|
-
});
|
|
1474
|
-
} catch (jErr) {
|
|
1475
|
-
defaults.logger.warn(`byteplus-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1476
|
-
}
|
|
1477
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1478
|
-
message: msg,
|
|
1479
|
-
type: "server_error"
|
|
1480
|
-
} }));
|
|
1481
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1603
|
+
routeError(req, res, err, pathname);
|
|
1482
1604
|
}
|
|
1483
1605
|
return;
|
|
1484
1606
|
}
|
|
@@ -1556,6 +1678,127 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1556
1678
|
}));
|
|
1557
1679
|
return;
|
|
1558
1680
|
}
|
|
1681
|
+
const batchesCancelMatch = pathname.match(BATCHES_CANCEL_RE);
|
|
1682
|
+
if (batchesCancelMatch && req.method === "POST") {
|
|
1683
|
+
try {
|
|
1684
|
+
await require_helpers.readBody(req);
|
|
1685
|
+
await require_batches.handleBatchesCancel(req, res, batchesCancelMatch[1], journal, defaults, setCorsHeaders);
|
|
1686
|
+
} catch (err) {
|
|
1687
|
+
routeError(req, res, err, pathname, { service: "batches" });
|
|
1688
|
+
}
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
const batchesIdMatch = pathname.match(BATCHES_ID_RE);
|
|
1692
|
+
if (batchesIdMatch && req.method === "GET") {
|
|
1693
|
+
try {
|
|
1694
|
+
await require_batches.handleBatchesRetrieve(req, res, batchesIdMatch[1], journal, defaults, setCorsHeaders);
|
|
1695
|
+
} catch (err) {
|
|
1696
|
+
routeError(req, res, err, pathname, { service: "batches" });
|
|
1697
|
+
}
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
if (pathname === BATCHES_PATH && req.method === "GET") {
|
|
1701
|
+
try {
|
|
1702
|
+
await require_batches.handleBatchesList(req, res, journal, defaults, setCorsHeaders);
|
|
1703
|
+
} catch (err) {
|
|
1704
|
+
routeError(req, res, err, pathname, { service: "batches" });
|
|
1705
|
+
}
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (pathname === BATCHES_PATH && req.method === "POST") {
|
|
1709
|
+
try {
|
|
1710
|
+
await require_batches.handleBatchesCreate(req, res, await require_helpers.readBody(req), journal, defaults, setCorsHeaders);
|
|
1711
|
+
} catch (err) {
|
|
1712
|
+
routeError(req, res, err, pathname, { service: "batches" });
|
|
1713
|
+
}
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
const filesContentMatch = pathname.match(require_metrics.FILES_CONTENT_RE);
|
|
1717
|
+
if (filesContentMatch && req.method === "GET") {
|
|
1718
|
+
try {
|
|
1719
|
+
await require_files.handleFilesContent(req, res, filesContentMatch[1], journal, defaults, setCorsHeaders);
|
|
1720
|
+
} catch (err) {
|
|
1721
|
+
routeError(req, res, err, pathname, { service: "files" });
|
|
1722
|
+
}
|
|
1723
|
+
return;
|
|
1724
|
+
}
|
|
1725
|
+
const filesIdMatch = pathname.match(require_metrics.FILES_ID_RE);
|
|
1726
|
+
if (filesIdMatch && req.method === "GET") {
|
|
1727
|
+
try {
|
|
1728
|
+
await require_files.handleFilesRetrieve(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);
|
|
1729
|
+
} catch (err) {
|
|
1730
|
+
routeError(req, res, err, pathname, { service: "files" });
|
|
1731
|
+
}
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
if (filesIdMatch && req.method === "DELETE") {
|
|
1735
|
+
try {
|
|
1736
|
+
await require_files.handleFilesDelete(req, res, filesIdMatch[1], journal, defaults, setCorsHeaders);
|
|
1737
|
+
} catch (err) {
|
|
1738
|
+
routeError(req, res, err, pathname, { service: "files" });
|
|
1739
|
+
}
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
if (pathname === FILES_PATH && req.method === "GET") {
|
|
1743
|
+
try {
|
|
1744
|
+
await require_files.handleFilesList(req, res, journal, defaults, setCorsHeaders);
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
routeError(req, res, err, pathname, { service: "files" });
|
|
1747
|
+
}
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
if (pathname === FILES_PATH && req.method === "POST") {
|
|
1751
|
+
try {
|
|
1752
|
+
await require_files.handleFilesCreate(req, res, (await require_helpers.readBodyBufferBounded(req, require_files.FILES_BODY_MAX_BYTES, require_files.FILES_BODY_DRAIN_MAX_BYTES)).buffer ?? require_files.FILES_BODY_OVERSIZED, journal, defaults, setCorsHeaders);
|
|
1753
|
+
} catch (err) {
|
|
1754
|
+
routeError(req, res, err, pathname, { service: "files" });
|
|
1755
|
+
}
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
const ftCancelMatch = pathname.match(FINE_TUNING_CANCEL_RE);
|
|
1759
|
+
if (ftCancelMatch && req.method === "POST") {
|
|
1760
|
+
try {
|
|
1761
|
+
await require_helpers.readBody(req);
|
|
1762
|
+
await require_fine_tuning.handleFineTuningCancel(req, res, ftCancelMatch[1], journal, defaults, setCorsHeaders);
|
|
1763
|
+
} catch (err) {
|
|
1764
|
+
routeError(req, res, err, pathname, { service: "fine-tuning" });
|
|
1765
|
+
}
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
const ftEventsMatch = pathname.match(FINE_TUNING_EVENTS_RE);
|
|
1769
|
+
if (ftEventsMatch && req.method === "GET") {
|
|
1770
|
+
try {
|
|
1771
|
+
await require_fine_tuning.handleFineTuningEvents(req, res, ftEventsMatch[1], journal, defaults, setCorsHeaders);
|
|
1772
|
+
} catch (err) {
|
|
1773
|
+
routeError(req, res, err, pathname, { service: "fine-tuning" });
|
|
1774
|
+
}
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
const ftIdMatch = pathname.match(FINE_TUNING_ID_RE);
|
|
1778
|
+
if (ftIdMatch && req.method === "GET") {
|
|
1779
|
+
try {
|
|
1780
|
+
await require_fine_tuning.handleFineTuningRetrieve(req, res, ftIdMatch[1], journal, defaults, setCorsHeaders);
|
|
1781
|
+
} catch (err) {
|
|
1782
|
+
routeError(req, res, err, pathname, { service: "fine-tuning" });
|
|
1783
|
+
}
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
if (pathname === FINE_TUNING_JOBS_PATH && req.method === "GET") {
|
|
1787
|
+
try {
|
|
1788
|
+
await require_fine_tuning.handleFineTuningList(req, res, journal, defaults, setCorsHeaders);
|
|
1789
|
+
} catch (err) {
|
|
1790
|
+
routeError(req, res, err, pathname, { service: "fine-tuning" });
|
|
1791
|
+
}
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1794
|
+
if (pathname === FINE_TUNING_JOBS_PATH && req.method === "POST") {
|
|
1795
|
+
try {
|
|
1796
|
+
await require_fine_tuning.handleFineTuningCreate(req, res, await require_helpers.readBody(req), journal, defaults, setCorsHeaders);
|
|
1797
|
+
} catch (err) {
|
|
1798
|
+
routeError(req, res, err, pathname, { service: "fine-tuning" });
|
|
1799
|
+
}
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1559
1802
|
if (pathname === REQUESTS_PATH) {
|
|
1560
1803
|
setCorsHeaders(res);
|
|
1561
1804
|
if (req.method === "GET") {
|
|
@@ -1590,17 +1833,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1590
1833
|
try {
|
|
1591
1834
|
await require_responses.handleResponses(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1592
1835
|
} catch (err) {
|
|
1593
|
-
|
|
1594
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1595
|
-
message: msg,
|
|
1596
|
-
type: "server_error"
|
|
1597
|
-
} }));
|
|
1598
|
-
else if (!res.writableEnded) try {
|
|
1599
|
-
res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
|
|
1600
|
-
res.end();
|
|
1601
|
-
} catch (writeErr) {
|
|
1602
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1603
|
-
}
|
|
1836
|
+
routeError(req, res, err, pathname, { streamEvent: (m) => `event: error\ndata: ${JSON.stringify({ error: { message: m } })}\n\n` });
|
|
1604
1837
|
}
|
|
1605
1838
|
return;
|
|
1606
1839
|
}
|
|
@@ -1608,17 +1841,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1608
1841
|
try {
|
|
1609
1842
|
await require_messages.handleMessages(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1610
1843
|
} catch (err) {
|
|
1611
|
-
|
|
1612
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1613
|
-
message: msg,
|
|
1614
|
-
type: "server_error"
|
|
1615
|
-
} }));
|
|
1616
|
-
else if (!res.writableEnded) try {
|
|
1617
|
-
res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
|
|
1618
|
-
res.end();
|
|
1619
|
-
} catch (writeErr) {
|
|
1620
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1621
|
-
}
|
|
1844
|
+
routeError(req, res, err, pathname, { streamEvent: (m) => `event: error\ndata: ${JSON.stringify({ error: { message: m } })}\n\n` });
|
|
1622
1845
|
}
|
|
1623
1846
|
return;
|
|
1624
1847
|
}
|
|
@@ -1626,17 +1849,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1626
1849
|
try {
|
|
1627
1850
|
await require_cohere.handleCohere(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1628
1851
|
} catch (err) {
|
|
1629
|
-
|
|
1630
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1631
|
-
message: msg,
|
|
1632
|
-
type: "server_error"
|
|
1633
|
-
} }));
|
|
1634
|
-
else if (!res.writableEnded) try {
|
|
1635
|
-
res.write(`event: error\ndata: ${JSON.stringify({ error: { message: msg } })}\n\n`);
|
|
1636
|
-
res.end();
|
|
1637
|
-
} catch (writeErr) {
|
|
1638
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1639
|
-
}
|
|
1852
|
+
routeError(req, res, err, pathname, { streamEvent: (m) => `event: error\ndata: ${JSON.stringify({ error: { message: m } })}\n\n` });
|
|
1640
1853
|
}
|
|
1641
1854
|
return;
|
|
1642
1855
|
}
|
|
@@ -1644,12 +1857,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1644
1857
|
try {
|
|
1645
1858
|
await require_cohere.handleCohereEmbed(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1646
1859
|
} catch (err) {
|
|
1647
|
-
|
|
1648
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1649
|
-
message: msg,
|
|
1650
|
-
type: "server_error"
|
|
1651
|
-
} }));
|
|
1652
|
-
else if (!res.writableEnded) res.destroy();
|
|
1860
|
+
routeError(req, res, err, pathname);
|
|
1653
1861
|
}
|
|
1654
1862
|
return;
|
|
1655
1863
|
}
|
|
@@ -1669,12 +1877,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1669
1877
|
}
|
|
1670
1878
|
await require_embeddings.handleEmbeddings(req, res, raw, fixtures, journal, defaults, setCorsHeaders, embeddingsProvider);
|
|
1671
1879
|
} catch (err) {
|
|
1672
|
-
|
|
1673
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1674
|
-
message: msg,
|
|
1675
|
-
type: "server_error"
|
|
1676
|
-
} }));
|
|
1677
|
-
else if (!res.writableEnded) res.destroy();
|
|
1880
|
+
routeError(req, res, err, pathname);
|
|
1678
1881
|
}
|
|
1679
1882
|
return;
|
|
1680
1883
|
}
|
|
@@ -1682,12 +1885,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1682
1885
|
try {
|
|
1683
1886
|
await require_images.handleImages(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, "openai", void 0, isBytePlusArk ? "byteplus" : void 0);
|
|
1684
1887
|
} catch (err) {
|
|
1685
|
-
|
|
1686
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1687
|
-
message: msg,
|
|
1688
|
-
type: "server_error"
|
|
1689
|
-
} }));
|
|
1690
|
-
else if (!res.writableEnded) res.destroy();
|
|
1888
|
+
routeError(req, res, err, pathname);
|
|
1691
1889
|
}
|
|
1692
1890
|
return;
|
|
1693
1891
|
}
|
|
@@ -1695,12 +1893,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1695
1893
|
try {
|
|
1696
1894
|
await require_images.handleImageEdit(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1697
1895
|
} catch (err) {
|
|
1698
|
-
|
|
1699
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1700
|
-
message: msg,
|
|
1701
|
-
type: "server_error"
|
|
1702
|
-
} }));
|
|
1703
|
-
else if (!res.writableEnded) res.destroy();
|
|
1896
|
+
routeError(req, res, err, pathname);
|
|
1704
1897
|
}
|
|
1705
1898
|
return;
|
|
1706
1899
|
}
|
|
@@ -1708,12 +1901,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1708
1901
|
try {
|
|
1709
1902
|
await require_images.handleImageVariations(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1710
1903
|
} catch (err) {
|
|
1711
|
-
|
|
1712
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1713
|
-
message: msg,
|
|
1714
|
-
type: "server_error"
|
|
1715
|
-
} }));
|
|
1716
|
-
else if (!res.writableEnded) res.destroy();
|
|
1904
|
+
routeError(req, res, err, pathname);
|
|
1717
1905
|
}
|
|
1718
1906
|
return;
|
|
1719
1907
|
}
|
|
@@ -1721,12 +1909,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1721
1909
|
try {
|
|
1722
1910
|
await require_speech.handleSpeech(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1723
1911
|
} catch (err) {
|
|
1724
|
-
|
|
1725
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1726
|
-
message: msg,
|
|
1727
|
-
type: "server_error"
|
|
1728
|
-
} }));
|
|
1729
|
-
else if (!res.writableEnded) res.destroy();
|
|
1912
|
+
routeError(req, res, err, pathname);
|
|
1730
1913
|
}
|
|
1731
1914
|
return;
|
|
1732
1915
|
}
|
|
@@ -1734,12 +1917,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1734
1917
|
try {
|
|
1735
1918
|
await require_transcription.handleTranscription(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1736
1919
|
} catch (err) {
|
|
1737
|
-
|
|
1738
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1739
|
-
message: msg,
|
|
1740
|
-
type: "server_error"
|
|
1741
|
-
} }));
|
|
1742
|
-
else if (!res.writableEnded) res.destroy();
|
|
1920
|
+
routeError(req, res, err, pathname);
|
|
1743
1921
|
}
|
|
1744
1922
|
return;
|
|
1745
1923
|
}
|
|
@@ -1747,12 +1925,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1747
1925
|
try {
|
|
1748
1926
|
await require_transcription.handleTranscription(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, "translation");
|
|
1749
1927
|
} catch (err) {
|
|
1750
|
-
|
|
1751
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1752
|
-
message: msg,
|
|
1753
|
-
type: "server_error"
|
|
1754
|
-
} }));
|
|
1755
|
-
else if (!res.writableEnded) res.destroy();
|
|
1928
|
+
routeError(req, res, err, pathname);
|
|
1756
1929
|
}
|
|
1757
1930
|
return;
|
|
1758
1931
|
}
|
|
@@ -1761,28 +1934,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1761
1934
|
try {
|
|
1762
1935
|
await require_grok_video.handleGrokVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, grokVideoJobs);
|
|
1763
1936
|
} catch (err) {
|
|
1764
|
-
|
|
1765
|
-
defaults.logger.error(`grok-video submit: ${msg}`);
|
|
1766
|
-
if (!res.headersSent) {
|
|
1767
|
-
try {
|
|
1768
|
-
journal.add({
|
|
1769
|
-
method: req.method ?? "POST",
|
|
1770
|
-
path: req.url ?? pathname,
|
|
1771
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1772
|
-
body: null,
|
|
1773
|
-
response: {
|
|
1774
|
-
status: 500,
|
|
1775
|
-
fixture: null
|
|
1776
|
-
}
|
|
1777
|
-
});
|
|
1778
|
-
} catch (jErr) {
|
|
1779
|
-
defaults.logger.warn(`grok-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1780
|
-
}
|
|
1781
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1782
|
-
message: msg,
|
|
1783
|
-
type: "server_error"
|
|
1784
|
-
} }));
|
|
1785
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1937
|
+
routeError(req, res, err, pathname);
|
|
1786
1938
|
}
|
|
1787
1939
|
return;
|
|
1788
1940
|
}
|
|
@@ -1790,12 +1942,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1790
1942
|
try {
|
|
1791
1943
|
await require_video.handleVideoCreate(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, videoStates);
|
|
1792
1944
|
} catch (err) {
|
|
1793
|
-
|
|
1794
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1795
|
-
message: msg,
|
|
1796
|
-
type: "server_error"
|
|
1797
|
-
} }));
|
|
1798
|
-
else if (!res.writableEnded) res.destroy();
|
|
1945
|
+
routeError(req, res, err, pathname);
|
|
1799
1946
|
}
|
|
1800
1947
|
return;
|
|
1801
1948
|
}
|
|
@@ -1804,28 +1951,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1804
1951
|
try {
|
|
1805
1952
|
await require_grok_video.handleGrokVideoStatus(req, res, grokVideoStatusMatch[1], fixtures, journal, defaults, setCorsHeaders, grokVideoJobs, videoStates);
|
|
1806
1953
|
} catch (err) {
|
|
1807
|
-
|
|
1808
|
-
defaults.logger.error(`grok-video status: ${msg}`);
|
|
1809
|
-
if (!res.headersSent) {
|
|
1810
|
-
try {
|
|
1811
|
-
journal.add({
|
|
1812
|
-
method: req.method ?? "GET",
|
|
1813
|
-
path: req.url ?? pathname,
|
|
1814
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1815
|
-
body: null,
|
|
1816
|
-
response: {
|
|
1817
|
-
status: 500,
|
|
1818
|
-
fixture: null
|
|
1819
|
-
}
|
|
1820
|
-
});
|
|
1821
|
-
} catch (jErr) {
|
|
1822
|
-
defaults.logger.warn(`grok-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1823
|
-
}
|
|
1824
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1825
|
-
message: msg,
|
|
1826
|
-
type: "server_error"
|
|
1827
|
-
} }));
|
|
1828
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1954
|
+
routeError(req, res, err, pathname);
|
|
1829
1955
|
}
|
|
1830
1956
|
return;
|
|
1831
1957
|
}
|
|
@@ -1835,28 +1961,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1835
1961
|
try {
|
|
1836
1962
|
await require_veo_video.handleVeoVideoCreate(req, res, await require_helpers.readBody(req), veoPredictMatch[1], fixtures, journal, defaults, setCorsHeaders, veoVideoJobs);
|
|
1837
1963
|
} catch (err) {
|
|
1838
|
-
|
|
1839
|
-
defaults.logger.error(`veo-video submit: ${msg}`);
|
|
1840
|
-
if (!res.headersSent) {
|
|
1841
|
-
try {
|
|
1842
|
-
journal.add({
|
|
1843
|
-
method: req.method ?? "POST",
|
|
1844
|
-
path: req.url ?? pathname,
|
|
1845
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1846
|
-
body: null,
|
|
1847
|
-
response: {
|
|
1848
|
-
status: 500,
|
|
1849
|
-
fixture: null
|
|
1850
|
-
}
|
|
1851
|
-
});
|
|
1852
|
-
} catch (jErr) {
|
|
1853
|
-
defaults.logger.warn(`veo-video submit: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1854
|
-
}
|
|
1855
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1856
|
-
message: msg,
|
|
1857
|
-
type: "server_error"
|
|
1858
|
-
} }));
|
|
1859
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1964
|
+
routeError(req, res, err, pathname);
|
|
1860
1965
|
}
|
|
1861
1966
|
return;
|
|
1862
1967
|
}
|
|
@@ -1865,28 +1970,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1865
1970
|
try {
|
|
1866
1971
|
await require_veo_video.handleVeoVideoStatus(req, res, veoOperationMatch[1], fixtures, journal, defaults, setCorsHeaders, veoVideoJobs);
|
|
1867
1972
|
} catch (err) {
|
|
1868
|
-
|
|
1869
|
-
defaults.logger.error(`veo-video status: ${msg}`);
|
|
1870
|
-
if (!res.headersSent) {
|
|
1871
|
-
try {
|
|
1872
|
-
journal.add({
|
|
1873
|
-
method: req.method ?? "GET",
|
|
1874
|
-
path: req.url ?? pathname,
|
|
1875
|
-
headers: require_helpers.flattenHeaders(req.headers),
|
|
1876
|
-
body: null,
|
|
1877
|
-
response: {
|
|
1878
|
-
status: 500,
|
|
1879
|
-
fixture: null
|
|
1880
|
-
}
|
|
1881
|
-
});
|
|
1882
|
-
} catch (jErr) {
|
|
1883
|
-
defaults.logger.warn(`veo-video status: journal write failed after handler error: ${jErr instanceof Error ? jErr.message : String(jErr)}`);
|
|
1884
|
-
}
|
|
1885
|
-
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1886
|
-
message: msg,
|
|
1887
|
-
type: "server_error"
|
|
1888
|
-
} }));
|
|
1889
|
-
} else if (!res.writableEnded) res.destroy();
|
|
1973
|
+
routeError(req, res, err, pathname);
|
|
1890
1974
|
}
|
|
1891
1975
|
return;
|
|
1892
1976
|
}
|
|
@@ -1896,12 +1980,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1896
1980
|
try {
|
|
1897
1981
|
await require_images.handleImages(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders, "gemini", predictModel);
|
|
1898
1982
|
} catch (err) {
|
|
1899
|
-
|
|
1900
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1901
|
-
message: msg,
|
|
1902
|
-
type: "server_error"
|
|
1903
|
-
} }));
|
|
1904
|
-
else if (!res.writableEnded) res.destroy();
|
|
1983
|
+
routeError(req, res, err, pathname);
|
|
1905
1984
|
}
|
|
1906
1985
|
return;
|
|
1907
1986
|
}
|
|
@@ -1909,17 +1988,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1909
1988
|
try {
|
|
1910
1989
|
await require_gemini_interactions.handleGeminiInteractions(req, res, await require_helpers.readBody(req), fixtures, journal, defaults, setCorsHeaders);
|
|
1911
1990
|
} catch (err) {
|
|
1912
|
-
|
|
1913
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1914
|
-
message: msg,
|
|
1915
|
-
type: "server_error"
|
|
1916
|
-
} }));
|
|
1917
|
-
else if (!res.writableEnded) try {
|
|
1918
|
-
res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
|
|
1919
|
-
res.end();
|
|
1920
|
-
} catch (writeErr) {
|
|
1921
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1922
|
-
}
|
|
1991
|
+
routeError(req, res, err, pathname, { streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\n\n` });
|
|
1923
1992
|
}
|
|
1924
1993
|
return;
|
|
1925
1994
|
}
|
|
@@ -1929,12 +1998,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1929
1998
|
try {
|
|
1930
1999
|
await require_gemini_embeddings.handleGeminiEmbedContent(req, res, await require_helpers.readBody(req), embedModel, fixtures, journal, defaults, setCorsHeaders);
|
|
1931
2000
|
} catch (err) {
|
|
1932
|
-
|
|
1933
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1934
|
-
message: msg,
|
|
1935
|
-
type: "server_error"
|
|
1936
|
-
} }));
|
|
1937
|
-
else if (!res.writableEnded) res.destroy();
|
|
2001
|
+
routeError(req, res, err, pathname);
|
|
1938
2002
|
}
|
|
1939
2003
|
return;
|
|
1940
2004
|
}
|
|
@@ -1945,17 +2009,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1945
2009
|
try {
|
|
1946
2010
|
await require_gemini.handleGemini(req, res, await require_helpers.readBody(req), geminiModel, streaming, fixtures, journal, defaults, setCorsHeaders);
|
|
1947
2011
|
} catch (err) {
|
|
1948
|
-
|
|
1949
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1950
|
-
message: msg,
|
|
1951
|
-
type: "server_error"
|
|
1952
|
-
} }));
|
|
1953
|
-
else if (!res.writableEnded) try {
|
|
1954
|
-
res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
|
|
1955
|
-
res.end();
|
|
1956
|
-
} catch (writeErr) {
|
|
1957
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1958
|
-
}
|
|
2012
|
+
routeError(req, res, err, pathname, { streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\n\n` });
|
|
1959
2013
|
}
|
|
1960
2014
|
return;
|
|
1961
2015
|
}
|
|
@@ -1966,17 +2020,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1966
2020
|
try {
|
|
1967
2021
|
await require_gemini.handleGemini(req, res, await require_helpers.readBody(req), vertexModel, streaming, fixtures, journal, defaults, setCorsHeaders, "vertexai");
|
|
1968
2022
|
} catch (err) {
|
|
1969
|
-
|
|
1970
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1971
|
-
message: msg,
|
|
1972
|
-
type: "server_error"
|
|
1973
|
-
} }));
|
|
1974
|
-
else if (!res.writableEnded) try {
|
|
1975
|
-
res.write(`data: ${JSON.stringify({ error: { message: msg } })}\n\n`);
|
|
1976
|
-
res.end();
|
|
1977
|
-
} catch (writeErr) {
|
|
1978
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
1979
|
-
}
|
|
2023
|
+
routeError(req, res, err, pathname, { streamEvent: (m) => `data: ${JSON.stringify({ error: { message: m } })}\n\n` });
|
|
1980
2024
|
}
|
|
1981
2025
|
return;
|
|
1982
2026
|
}
|
|
@@ -1986,12 +2030,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
1986
2030
|
try {
|
|
1987
2031
|
await require_bedrock.handleBedrock(req, res, await require_helpers.readBody(req), bedrockModelId, fixtures, journal, defaults, setCorsHeaders);
|
|
1988
2032
|
} catch (err) {
|
|
1989
|
-
|
|
1990
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
1991
|
-
message: msg,
|
|
1992
|
-
type: "server_error"
|
|
1993
|
-
} }));
|
|
1994
|
-
else if (!res.writableEnded) res.destroy();
|
|
2033
|
+
routeError(req, res, err, pathname);
|
|
1995
2034
|
}
|
|
1996
2035
|
return;
|
|
1997
2036
|
}
|
|
@@ -2001,12 +2040,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2001
2040
|
try {
|
|
2002
2041
|
await require_bedrock.handleBedrockStream(req, res, await require_helpers.readBody(req), bedrockModelId, fixtures, journal, defaults, setCorsHeaders);
|
|
2003
2042
|
} catch (err) {
|
|
2004
|
-
|
|
2005
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2006
|
-
message: msg,
|
|
2007
|
-
type: "server_error"
|
|
2008
|
-
} }));
|
|
2009
|
-
else if (!res.writableEnded) res.destroy();
|
|
2043
|
+
routeError(req, res, err, pathname);
|
|
2010
2044
|
}
|
|
2011
2045
|
return;
|
|
2012
2046
|
}
|
|
@@ -2016,12 +2050,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2016
2050
|
try {
|
|
2017
2051
|
await require_bedrock_converse.handleConverse(req, res, await require_helpers.readBody(req), converseModelId, fixtures, journal, defaults, setCorsHeaders);
|
|
2018
2052
|
} catch (err) {
|
|
2019
|
-
|
|
2020
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2021
|
-
message: msg,
|
|
2022
|
-
type: "server_error"
|
|
2023
|
-
} }));
|
|
2024
|
-
else if (!res.writableEnded) res.destroy();
|
|
2053
|
+
routeError(req, res, err, pathname);
|
|
2025
2054
|
}
|
|
2026
2055
|
return;
|
|
2027
2056
|
}
|
|
@@ -2031,12 +2060,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2031
2060
|
try {
|
|
2032
2061
|
await require_bedrock_converse.handleConverseStream(req, res, await require_helpers.readBody(req), converseStreamModelId, fixtures, journal, defaults, setCorsHeaders);
|
|
2033
2062
|
} catch (err) {
|
|
2034
|
-
|
|
2035
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2036
|
-
message: msg,
|
|
2037
|
-
type: "server_error"
|
|
2038
|
-
} }));
|
|
2039
|
-
else if (!res.writableEnded) res.destroy();
|
|
2063
|
+
routeError(req, res, err, pathname);
|
|
2040
2064
|
}
|
|
2041
2065
|
return;
|
|
2042
2066
|
}
|
|
@@ -2044,12 +2068,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2044
2068
|
try {
|
|
2045
2069
|
await require_search.handleSearch(req, res, await require_helpers.readBody(req), serviceFixtures?.search ?? [], journal, defaults, setCorsHeaders);
|
|
2046
2070
|
} catch (err) {
|
|
2047
|
-
|
|
2048
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2049
|
-
message: msg,
|
|
2050
|
-
type: "server_error"
|
|
2051
|
-
} }));
|
|
2052
|
-
else if (!res.writableEnded) res.destroy();
|
|
2071
|
+
routeError(req, res, err, pathname, { service: "search" });
|
|
2053
2072
|
}
|
|
2054
2073
|
return;
|
|
2055
2074
|
}
|
|
@@ -2057,12 +2076,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2057
2076
|
try {
|
|
2058
2077
|
await require_rerank.handleRerank(req, res, await require_helpers.readBody(req), serviceFixtures?.rerank ?? [], journal, defaults, setCorsHeaders);
|
|
2059
2078
|
} catch (err) {
|
|
2060
|
-
|
|
2061
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2062
|
-
message: msg,
|
|
2063
|
-
type: "server_error"
|
|
2064
|
-
} }));
|
|
2065
|
-
else if (!res.writableEnded) res.destroy();
|
|
2079
|
+
routeError(req, res, err, pathname, { service: "rerank" });
|
|
2066
2080
|
}
|
|
2067
2081
|
return;
|
|
2068
2082
|
}
|
|
@@ -2070,12 +2084,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2070
2084
|
try {
|
|
2071
2085
|
await require_moderation.handleModeration(req, res, await require_helpers.readBody(req), serviceFixtures?.moderation ?? [], journal, defaults, setCorsHeaders);
|
|
2072
2086
|
} catch (err) {
|
|
2073
|
-
|
|
2074
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2075
|
-
message: msg,
|
|
2076
|
-
type: "server_error"
|
|
2077
|
-
} }));
|
|
2078
|
-
else if (!res.writableEnded) res.destroy();
|
|
2087
|
+
routeError(req, res, err, pathname, { service: "moderation" });
|
|
2079
2088
|
}
|
|
2080
2089
|
return;
|
|
2081
2090
|
}
|
|
@@ -2084,12 +2093,57 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2084
2093
|
try {
|
|
2085
2094
|
await require_elevenlabs_audio.handleElevenLabsAudio(req, res, await require_helpers.readBody(req), fixtures, defaults, journal, "sound-generation");
|
|
2086
2095
|
} catch (err) {
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2096
|
+
routeError(req, res, err, pathname);
|
|
2097
|
+
}
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
2100
|
+
if (pathname === ELEVENLABS_VOICE_DESIGN_PATH && req.method === "POST") {
|
|
2101
|
+
setCorsHeaders(res);
|
|
2102
|
+
try {
|
|
2103
|
+
await require_elevenlabs_voice.handleElevenLabsVoiceDesign(req, res, await require_helpers.readBody(req), fixtures, defaults, journal);
|
|
2104
|
+
} catch (err) {
|
|
2105
|
+
routeError(req, res, err, pathname, { service: "elevenlabs-voice" });
|
|
2106
|
+
}
|
|
2107
|
+
return;
|
|
2108
|
+
}
|
|
2109
|
+
if (pathname === ELEVENLABS_VOICE_CREATE_PATH && req.method === "POST") {
|
|
2110
|
+
setCorsHeaders(res);
|
|
2111
|
+
try {
|
|
2112
|
+
await require_elevenlabs_voice.handleElevenLabsVoiceCreate(req, res, await require_helpers.readBody(req), fixtures, defaults, journal);
|
|
2113
|
+
} catch (err) {
|
|
2114
|
+
routeError(req, res, err, pathname, { service: "elevenlabs-voice" });
|
|
2115
|
+
}
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
const elevenLabsVoiceMatch = pathname.match(ELEVENLABS_VOICE_RE);
|
|
2119
|
+
if (elevenLabsVoiceMatch && (req.method === "GET" || req.method === "DELETE")) {
|
|
2120
|
+
setCorsHeaders(res);
|
|
2121
|
+
let voiceId;
|
|
2122
|
+
try {
|
|
2123
|
+
voiceId = decodeURIComponent(elevenLabsVoiceMatch[1]);
|
|
2124
|
+
} catch {
|
|
2125
|
+
require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
|
|
2126
|
+
message: `Invalid voice id '${elevenLabsVoiceMatch[1]}': malformed percent-encoding`,
|
|
2127
|
+
type: "invalid_request_error"
|
|
2091
2128
|
} }));
|
|
2092
|
-
|
|
2129
|
+
journal.add({
|
|
2130
|
+
method: req.method ?? "GET",
|
|
2131
|
+
path: req.url ?? pathname,
|
|
2132
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
2133
|
+
service: "elevenlabs-voice",
|
|
2134
|
+
body: null,
|
|
2135
|
+
response: {
|
|
2136
|
+
status: 400,
|
|
2137
|
+
fixture: null
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2142
|
+
try {
|
|
2143
|
+
if (req.method === "GET") await require_elevenlabs_voice.handleElevenLabsVoiceGet(req, res, voiceId, fixtures, defaults, journal);
|
|
2144
|
+
else await require_elevenlabs_voice.handleElevenLabsVoiceDelete(req, res, voiceId, fixtures, defaults, journal);
|
|
2145
|
+
} catch (err) {
|
|
2146
|
+
routeError(req, res, err, pathname, { service: "elevenlabs-voice" });
|
|
2093
2147
|
}
|
|
2094
2148
|
return;
|
|
2095
2149
|
}
|
|
@@ -2100,12 +2154,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2100
2154
|
try {
|
|
2101
2155
|
await require_elevenlabs_audio.handleElevenLabsTTS(req, res, await require_helpers.readBody(req), fixtures, defaults, journal, voiceId);
|
|
2102
2156
|
} catch (err) {
|
|
2103
|
-
|
|
2104
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2105
|
-
message: msg,
|
|
2106
|
-
type: "server_error"
|
|
2107
|
-
} }));
|
|
2108
|
-
else if (!res.writableEnded) res.destroy();
|
|
2157
|
+
routeError(req, res, err, pathname);
|
|
2109
2158
|
}
|
|
2110
2159
|
return;
|
|
2111
2160
|
}
|
|
@@ -2116,42 +2165,38 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2116
2165
|
try {
|
|
2117
2166
|
await require_elevenlabs_audio.handleElevenLabsAudio(req, res, await require_helpers.readBody(req), fixtures, defaults, journal, musicSubType);
|
|
2118
2167
|
} catch (err) {
|
|
2119
|
-
|
|
2120
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2121
|
-
message: msg,
|
|
2122
|
-
type: "server_error"
|
|
2123
|
-
} }));
|
|
2124
|
-
else if (!res.writableEnded) res.destroy();
|
|
2168
|
+
routeError(req, res, err, pathname);
|
|
2125
2169
|
}
|
|
2126
2170
|
return;
|
|
2127
2171
|
}
|
|
2128
2172
|
let falBody;
|
|
2129
|
-
if (
|
|
2173
|
+
if (require_metrics.FAL_ROUTE_RE.test(pathname) && req.headers["x-fal-target-host"]) {
|
|
2130
2174
|
setCorsHeaders(res);
|
|
2131
2175
|
try {
|
|
2132
2176
|
falBody = req.method === "POST" || req.method === "PUT" ? await require_helpers.readBody(req) : "";
|
|
2133
2177
|
const raw = falBody;
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
require_chaos.
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2178
|
+
if (require_fal.falWillHandle(req, pathname)) {
|
|
2179
|
+
const chaosConfig = require_chaos.resolveChaosConfig(null, defaults.chaos, req.headers, defaults.logger, req.url);
|
|
2180
|
+
await require_chaos.awaitChaosLatency(null, defaults.chaos, req.headers, defaults.logger, req.url, res, chaosConfig);
|
|
2181
|
+
const goneAfterLatency = require_chaos.responseGoneReason(res);
|
|
2182
|
+
if (goneAfterLatency !== null) {
|
|
2183
|
+
defaults.logger.debug(`[chaos] ${req.method ?? "GET"} ${pathname}: ${require_chaos.describeUnwritableReason(goneAfterLatency)} after the latency delay — not served, not journalled`);
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
const chaosAction = require_chaos.evaluateChaos(null, defaults.chaos, req.headers, defaults.logger, req.url, chaosConfig);
|
|
2187
|
+
if (chaosAction) {
|
|
2188
|
+
require_chaos.applyChaosAction(chaosAction, res, null, journal, {
|
|
2189
|
+
method: req.method ?? "GET",
|
|
2190
|
+
path: pathname,
|
|
2191
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
2192
|
+
body: null
|
|
2193
|
+
}, "internal", defaults.registry, defaults.logger);
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
2146
2196
|
}
|
|
2147
2197
|
if (await require_fal.handleFal(req, res, raw, pathname, fixtures, defaults, journal) === "handled") return;
|
|
2148
2198
|
} catch (err) {
|
|
2149
|
-
|
|
2150
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2151
|
-
message: msg,
|
|
2152
|
-
type: "server_error"
|
|
2153
|
-
} }));
|
|
2154
|
-
else if (!res.writableEnded) res.destroy();
|
|
2199
|
+
routeError(req, res, err, pathname);
|
|
2155
2200
|
return;
|
|
2156
2201
|
}
|
|
2157
2202
|
}
|
|
@@ -2160,12 +2205,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2160
2205
|
try {
|
|
2161
2206
|
await require_fal_audio.handleFalQueue(req, res, falBody ?? await require_helpers.readBody(req), pathname, fixtures, defaults, journal);
|
|
2162
2207
|
} catch (err) {
|
|
2163
|
-
|
|
2164
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2165
|
-
message: msg,
|
|
2166
|
-
type: "server_error"
|
|
2167
|
-
} }));
|
|
2168
|
-
else if (!res.writableEnded) res.destroy();
|
|
2208
|
+
routeError(req, res, err, pathname);
|
|
2169
2209
|
}
|
|
2170
2210
|
return;
|
|
2171
2211
|
}
|
|
@@ -2173,27 +2213,26 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2173
2213
|
setCorsHeaders(res);
|
|
2174
2214
|
try {
|
|
2175
2215
|
const raw = req.method === "POST" || req.method === "PUT" ? falBody ?? await require_helpers.readBody(req) : "{}";
|
|
2176
|
-
const
|
|
2216
|
+
const chaosConfig = require_chaos.resolveChaosConfig(null, defaults.chaos, req.headers, defaults.logger, req.url);
|
|
2217
|
+
await require_chaos.awaitChaosLatency(null, defaults.chaos, req.headers, defaults.logger, req.url, res, chaosConfig);
|
|
2218
|
+
const goneAfterLatency = require_chaos.responseGoneReason(res);
|
|
2219
|
+
if (goneAfterLatency !== null) {
|
|
2220
|
+
defaults.logger.debug(`[chaos] ${req.method ?? "GET"} ${pathname}: ${require_chaos.describeUnwritableReason(goneAfterLatency)} after the latency delay — not served, not journalled`);
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
const chaosAction = require_chaos.evaluateChaos(null, defaults.chaos, req.headers, defaults.logger, req.url, chaosConfig);
|
|
2177
2224
|
if (chaosAction) {
|
|
2178
2225
|
require_chaos.applyChaosAction(chaosAction, res, null, journal, {
|
|
2179
2226
|
method: req.method ?? "GET",
|
|
2180
2227
|
path: pathname,
|
|
2181
2228
|
headers: require_helpers.flattenHeaders(req.headers),
|
|
2182
|
-
body:
|
|
2183
|
-
|
|
2184
|
-
messages: []
|
|
2185
|
-
}
|
|
2186
|
-
}, "fixture", defaults.registry);
|
|
2229
|
+
body: null
|
|
2230
|
+
}, "internal", defaults.registry, defaults.logger);
|
|
2187
2231
|
return;
|
|
2188
2232
|
}
|
|
2189
2233
|
await require_fal_audio.handleFalQueue(req, res, raw, pathname, fixtures, defaults, journal);
|
|
2190
2234
|
} catch (err) {
|
|
2191
|
-
|
|
2192
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2193
|
-
message: msg,
|
|
2194
|
-
type: "server_error"
|
|
2195
|
-
} }));
|
|
2196
|
-
else if (!res.writableEnded) res.destroy();
|
|
2235
|
+
routeError(req, res, err, pathname);
|
|
2197
2236
|
}
|
|
2198
2237
|
return;
|
|
2199
2238
|
}
|
|
@@ -2202,12 +2241,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2202
2241
|
try {
|
|
2203
2242
|
await require_fal_audio.handleFalQueue(req, res, falBody ?? await require_helpers.readBody(req), pathname, fixtures, defaults, journal);
|
|
2204
2243
|
} catch (err) {
|
|
2205
|
-
|
|
2206
|
-
if (!res.headersSent) require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
2207
|
-
message: msg,
|
|
2208
|
-
type: "server_error"
|
|
2209
|
-
} }));
|
|
2210
|
-
else if (!res.writableEnded) res.destroy();
|
|
2244
|
+
routeError(req, res, err, pathname);
|
|
2211
2245
|
}
|
|
2212
2246
|
return;
|
|
2213
2247
|
}
|
|
@@ -2223,23 +2257,25 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2223
2257
|
try {
|
|
2224
2258
|
await handleCompletions(req, res, fixtures, journal, defaults, azureDeploymentId, completionsProvider, isOpenRouter);
|
|
2225
2259
|
} catch (err) {
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
res.end();
|
|
2237
|
-
} catch (writeErr) {
|
|
2238
|
-
logger.debug("Failed to write error recovery response:", writeErr);
|
|
2239
|
-
}
|
|
2260
|
+
routeError(req, res, err, pathname, {
|
|
2261
|
+
envelope: (m, status) => isOpenRouter ? require_openrouter_chat.serializeOpenRouterError(status, m) : JSON.stringify({ error: {
|
|
2262
|
+
message: m,
|
|
2263
|
+
type: errorTypeForStatus(status)
|
|
2264
|
+
} }),
|
|
2265
|
+
streamEvent: (m, status) => `data: ${isOpenRouter ? require_openrouter_chat.serializeOpenRouterError(status, m) : JSON.stringify({ error: {
|
|
2266
|
+
message: m,
|
|
2267
|
+
type: errorTypeForStatus(status)
|
|
2268
|
+
} })}\n\n`
|
|
2269
|
+
});
|
|
2240
2270
|
}
|
|
2241
2271
|
}
|
|
2242
2272
|
const activeConnections = /* @__PURE__ */ new Set();
|
|
2273
|
+
const liveLimits = require_live_fixture.normalizeLiveOptions(options?.live);
|
|
2274
|
+
const liveSessions = /* @__PURE__ */ new Map();
|
|
2275
|
+
const closeLiveSessions = (testId) => {
|
|
2276
|
+
for (const session of [...liveSessions.values()]) if (testId === void 0 || session.testId === testId) session.dispose();
|
|
2277
|
+
};
|
|
2278
|
+
liveClosers.set(defaults, closeLiveSessions);
|
|
2243
2279
|
server.on("upgrade", (req, socket, head) => {
|
|
2244
2280
|
handleUpgradeRequest(req, socket, head).catch((err) => {
|
|
2245
2281
|
const msg = err instanceof Error ? err.message : "Internal error";
|
|
@@ -2302,17 +2338,38 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2302
2338
|
}
|
|
2303
2339
|
}
|
|
2304
2340
|
if (!pathname.match(AZURE_DEPLOYMENT_RE)) pathname = normalizeCompatPath(pathname, logger);
|
|
2305
|
-
if (pathname !== RESPONSES_PATH && pathname !== REALTIME_PATH && pathname !== GEMINI_LIVE_PATH) {
|
|
2341
|
+
if (pathname !== RESPONSES_PATH && pathname !== REALTIME_PATH && pathname !== GEMINI_LIVE_PATH && pathname !== LIVE_PATH) {
|
|
2306
2342
|
socket.write("HTTP/1.1 404 Not Found\r\n\r\n");
|
|
2307
2343
|
socket.destroy();
|
|
2308
2344
|
return;
|
|
2309
2345
|
}
|
|
2346
|
+
let liveId;
|
|
2347
|
+
if (pathname === LIVE_PATH) {
|
|
2348
|
+
if (req.method !== "GET" || parsedUrl.searchParams.has("model")) {
|
|
2349
|
+
socket.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
if (liveSessions.size >= liveLimits.maxSessions) {
|
|
2353
|
+
socket.end("HTTP/1.1 429 Too Many Requests\r\nConnection: close\r\n\r\n");
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
liveId = Symbol("live-session");
|
|
2357
|
+
const reservedId = liveId;
|
|
2358
|
+
liveSessions.set(reservedId, {
|
|
2359
|
+
testId: require_helpers.getTestId(req),
|
|
2360
|
+
dispose: () => {
|
|
2361
|
+
socket.destroy();
|
|
2362
|
+
liveSessions.delete(reservedId);
|
|
2363
|
+
}
|
|
2364
|
+
});
|
|
2365
|
+
}
|
|
2310
2366
|
if (head.length > 0) socket.unshift(head);
|
|
2311
2367
|
let ws;
|
|
2312
2368
|
try {
|
|
2313
|
-
ws = require_ws_framing.upgradeToWebSocket(req, socket);
|
|
2369
|
+
ws = require_ws_framing.upgradeToWebSocket(req, socket, pathname === LIVE_PATH ? liveLimits : void 0);
|
|
2314
2370
|
} catch (err) {
|
|
2315
2371
|
const msg = err instanceof Error ? err.message : "WebSocket upgrade failed";
|
|
2372
|
+
if (liveId !== void 0) liveSessions.delete(liveId);
|
|
2316
2373
|
logger.error(`WebSocket upgrade error: ${msg}`);
|
|
2317
2374
|
if (!socket.destroyed) socket.destroy();
|
|
2318
2375
|
return;
|
|
@@ -2326,7 +2383,24 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2326
2383
|
activeConnections.delete(ws);
|
|
2327
2384
|
});
|
|
2328
2385
|
const wsTestId = require_helpers.getTestId(req);
|
|
2329
|
-
if (pathname ===
|
|
2386
|
+
if (pathname === LIVE_PATH && liveId !== void 0) {
|
|
2387
|
+
const sessionId = liveId;
|
|
2388
|
+
const dispose = require_ws_live.handleLiveSession(ws, fixtures, journal, {
|
|
2389
|
+
defaults,
|
|
2390
|
+
limits: liveLimits,
|
|
2391
|
+
localApiKeys: resolvedAuth.publicConfig?.apiKeys,
|
|
2392
|
+
testId: wsTestId,
|
|
2393
|
+
headers: req.headers,
|
|
2394
|
+
onDispose: () => {
|
|
2395
|
+
liveSessions.delete(sessionId);
|
|
2396
|
+
activeConnections.delete(ws);
|
|
2397
|
+
}
|
|
2398
|
+
});
|
|
2399
|
+
liveSessions.set(sessionId, {
|
|
2400
|
+
testId: wsTestId,
|
|
2401
|
+
dispose
|
|
2402
|
+
});
|
|
2403
|
+
} else if (pathname === RESPONSES_PATH) require_ws_responses.handleWebSocketResponses(ws, fixtures, journal, {
|
|
2330
2404
|
...defaults,
|
|
2331
2405
|
model: "gpt-4",
|
|
2332
2406
|
testId: wsTestId,
|
|
@@ -2351,6 +2425,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2351
2425
|
}
|
|
2352
2426
|
const originalClose = server.close.bind(server);
|
|
2353
2427
|
server.close = function(callback) {
|
|
2428
|
+
closeLiveSessions();
|
|
2354
2429
|
for (const ws of activeConnections) ws.close(1001, "Server shutting down");
|
|
2355
2430
|
activeConnections.clear();
|
|
2356
2431
|
videoStates.clear();
|
|
@@ -2374,6 +2449,7 @@ async function createServerWithResolvedAuth(fixtures, options, resolvedAuth, mou
|
|
|
2374
2449
|
for (const { path: mountPath, handler } of mounts) if (handler.setBaseUrl) handler.setBaseUrl(url + mountPath);
|
|
2375
2450
|
}
|
|
2376
2451
|
resolve({
|
|
2452
|
+
closeLiveSessions,
|
|
2377
2453
|
server,
|
|
2378
2454
|
journal,
|
|
2379
2455
|
url,
|