@copilotkit/aimock 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +37 -0
  4. package/README.md +10 -10
  5. package/dist/agui-types.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +0 -0
  7. package/dist/aimock-cli.js +0 -0
  8. package/dist/bedrock-converse.cjs +62 -22
  9. package/dist/bedrock-converse.cjs.map +1 -1
  10. package/dist/bedrock-converse.d.cts.map +1 -1
  11. package/dist/bedrock-converse.d.ts.map +1 -1
  12. package/dist/bedrock-converse.js +62 -22
  13. package/dist/bedrock-converse.js.map +1 -1
  14. package/dist/bedrock.cjs +59 -20
  15. package/dist/bedrock.cjs.map +1 -1
  16. package/dist/bedrock.d.cts.map +1 -1
  17. package/dist/bedrock.d.ts.map +1 -1
  18. package/dist/bedrock.js +59 -20
  19. package/dist/bedrock.js.map +1 -1
  20. package/dist/cli.cjs +8 -2
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +8 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/cohere.cjs +29 -9
  25. package/dist/cohere.cjs.map +1 -1
  26. package/dist/cohere.d.cts.map +1 -1
  27. package/dist/cohere.d.ts.map +1 -1
  28. package/dist/cohere.js +30 -10
  29. package/dist/cohere.js.map +1 -1
  30. package/dist/config-loader.d.cts.map +1 -1
  31. package/dist/constants.cjs +8 -0
  32. package/dist/constants.cjs.map +1 -0
  33. package/dist/constants.d.cts +8 -0
  34. package/dist/constants.d.cts.map +1 -0
  35. package/dist/constants.d.ts +8 -0
  36. package/dist/constants.d.ts.map +1 -0
  37. package/dist/constants.js +7 -0
  38. package/dist/constants.js.map +1 -0
  39. package/dist/elevenlabs-audio.cjs +41 -18
  40. package/dist/elevenlabs-audio.cjs.map +1 -1
  41. package/dist/elevenlabs-audio.d.cts.map +1 -1
  42. package/dist/elevenlabs-audio.d.ts.map +1 -1
  43. package/dist/elevenlabs-audio.js +42 -19
  44. package/dist/elevenlabs-audio.js.map +1 -1
  45. package/dist/embeddings.cjs +19 -17
  46. package/dist/embeddings.cjs.map +1 -1
  47. package/dist/embeddings.d.cts.map +1 -1
  48. package/dist/embeddings.d.ts.map +1 -1
  49. package/dist/embeddings.js +20 -18
  50. package/dist/embeddings.js.map +1 -1
  51. package/dist/fal-audio.cjs +128 -39
  52. package/dist/fal-audio.cjs.map +1 -1
  53. package/dist/fal-audio.d.cts.map +1 -1
  54. package/dist/fal-audio.d.ts.map +1 -1
  55. package/dist/fal-audio.js +129 -40
  56. package/dist/fal-audio.js.map +1 -1
  57. package/dist/fal.cjs +25 -8
  58. package/dist/fal.cjs.map +1 -1
  59. package/dist/fal.d.cts.map +1 -1
  60. package/dist/fal.d.ts.map +1 -1
  61. package/dist/fal.js +26 -9
  62. package/dist/fal.js.map +1 -1
  63. package/dist/fixture-loader.cjs +11 -2
  64. package/dist/fixture-loader.cjs.map +1 -1
  65. package/dist/fixture-loader.d.cts.map +1 -1
  66. package/dist/fixture-loader.d.ts.map +1 -1
  67. package/dist/fixture-loader.js +11 -2
  68. package/dist/fixture-loader.js.map +1 -1
  69. package/dist/gemini-interactions.cjs +29 -7
  70. package/dist/gemini-interactions.cjs.map +1 -1
  71. package/dist/gemini-interactions.js +28 -8
  72. package/dist/gemini-interactions.js.map +1 -1
  73. package/dist/gemini.cjs +45 -19
  74. package/dist/gemini.cjs.map +1 -1
  75. package/dist/gemini.d.cts.map +1 -1
  76. package/dist/gemini.d.ts.map +1 -1
  77. package/dist/gemini.js +45 -19
  78. package/dist/gemini.js.map +1 -1
  79. package/dist/helpers.cjs +52 -8
  80. package/dist/helpers.cjs.map +1 -1
  81. package/dist/helpers.d.cts +6 -0
  82. package/dist/helpers.d.cts.map +1 -1
  83. package/dist/helpers.d.ts +6 -0
  84. package/dist/helpers.d.ts.map +1 -1
  85. package/dist/helpers.js +52 -9
  86. package/dist/helpers.js.map +1 -1
  87. package/dist/images.cjs +26 -8
  88. package/dist/images.cjs.map +1 -1
  89. package/dist/images.d.cts.map +1 -1
  90. package/dist/images.d.ts.map +1 -1
  91. package/dist/images.js +27 -9
  92. package/dist/images.js.map +1 -1
  93. package/dist/index.cjs +2 -1
  94. package/dist/index.d.cts +2 -1
  95. package/dist/index.d.ts +2 -1
  96. package/dist/index.js +2 -1
  97. package/dist/journal.cjs +17 -7
  98. package/dist/journal.cjs.map +1 -1
  99. package/dist/journal.d.cts +2 -3
  100. package/dist/journal.d.cts.map +1 -1
  101. package/dist/journal.d.ts +2 -3
  102. package/dist/journal.d.ts.map +1 -1
  103. package/dist/journal.js +15 -4
  104. package/dist/journal.js.map +1 -1
  105. package/dist/messages.cjs +33 -12
  106. package/dist/messages.cjs.map +1 -1
  107. package/dist/messages.d.cts.map +1 -1
  108. package/dist/messages.d.ts.map +1 -1
  109. package/dist/messages.js +33 -12
  110. package/dist/messages.js.map +1 -1
  111. package/dist/model-utils.cjs +11 -0
  112. package/dist/model-utils.cjs.map +1 -0
  113. package/dist/model-utils.js +10 -0
  114. package/dist/model-utils.js.map +1 -0
  115. package/dist/ollama.cjs +59 -18
  116. package/dist/ollama.cjs.map +1 -1
  117. package/dist/ollama.d.cts.map +1 -1
  118. package/dist/ollama.d.ts.map +1 -1
  119. package/dist/ollama.js +60 -19
  120. package/dist/ollama.js.map +1 -1
  121. package/dist/recorder.cjs +30 -11
  122. package/dist/recorder.cjs.map +1 -1
  123. package/dist/recorder.d.cts.map +1 -1
  124. package/dist/recorder.d.ts.map +1 -1
  125. package/dist/recorder.js +30 -11
  126. package/dist/recorder.js.map +1 -1
  127. package/dist/responses.cjs +61 -52
  128. package/dist/responses.cjs.map +1 -1
  129. package/dist/responses.d.cts +1 -1
  130. package/dist/responses.d.cts.map +1 -1
  131. package/dist/responses.d.ts +1 -1
  132. package/dist/responses.d.ts.map +1 -1
  133. package/dist/responses.js +62 -53
  134. package/dist/responses.js.map +1 -1
  135. package/dist/router.cjs +7 -3
  136. package/dist/router.cjs.map +1 -1
  137. package/dist/router.js +7 -3
  138. package/dist/router.js.map +1 -1
  139. package/dist/server.cjs +64 -180
  140. package/dist/server.cjs.map +1 -1
  141. package/dist/server.d.cts.map +1 -1
  142. package/dist/server.d.ts.map +1 -1
  143. package/dist/server.js +40 -156
  144. package/dist/server.js.map +1 -1
  145. package/dist/speech.cjs +26 -8
  146. package/dist/speech.cjs.map +1 -1
  147. package/dist/speech.d.cts.map +1 -1
  148. package/dist/speech.d.ts.map +1 -1
  149. package/dist/speech.js +27 -9
  150. package/dist/speech.js.map +1 -1
  151. package/dist/transcription.cjs +57 -19
  152. package/dist/transcription.cjs.map +1 -1
  153. package/dist/transcription.d.cts.map +1 -1
  154. package/dist/transcription.d.ts.map +1 -1
  155. package/dist/transcription.js +58 -20
  156. package/dist/transcription.js.map +1 -1
  157. package/dist/types.d.cts +19 -2
  158. package/dist/types.d.cts.map +1 -1
  159. package/dist/types.d.ts +19 -2
  160. package/dist/types.d.ts.map +1 -1
  161. package/dist/video.cjs +50 -14
  162. package/dist/video.cjs.map +1 -1
  163. package/dist/video.d.cts +8 -1
  164. package/dist/video.d.cts.map +1 -1
  165. package/dist/video.d.ts +8 -1
  166. package/dist/video.d.ts.map +1 -1
  167. package/dist/video.js +51 -15
  168. package/dist/video.js.map +1 -1
  169. package/dist/ws-gemini-live.cjs +34 -27
  170. package/dist/ws-gemini-live.cjs.map +1 -1
  171. package/dist/ws-gemini-live.d.cts +2 -2
  172. package/dist/ws-gemini-live.d.cts.map +1 -1
  173. package/dist/ws-gemini-live.d.ts.map +1 -1
  174. package/dist/ws-gemini-live.js +34 -27
  175. package/dist/ws-gemini-live.js.map +1 -1
  176. package/dist/ws-realtime.cjs +776 -175
  177. package/dist/ws-realtime.cjs.map +1 -1
  178. package/dist/ws-realtime.d.cts +2 -2
  179. package/dist/ws-realtime.d.cts.map +1 -1
  180. package/dist/ws-realtime.d.ts.map +1 -1
  181. package/dist/ws-realtime.js +776 -175
  182. package/dist/ws-realtime.js.map +1 -1
  183. package/dist/ws-responses.cjs +48 -12
  184. package/dist/ws-responses.cjs.map +1 -1
  185. package/dist/ws-responses.d.cts.map +1 -1
  186. package/dist/ws-responses.d.ts.map +1 -1
  187. package/dist/ws-responses.js +49 -13
  188. package/dist/ws-responses.js.map +1 -1
  189. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -89,7 +89,7 @@ interface FixtureMatch {
89
89
  sequenceIndex?: number;
90
90
  turnIndex?: number;
91
91
  hasToolResult?: boolean;
92
- endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding" | "audio-gen" | "fal-audio" | "fal";
92
+ endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding" | "audio-gen" | "fal-audio" | "fal" | "realtime" | "realtime-transcription" | "realtime-translation";
93
93
  }
94
94
  /**
95
95
  * Fields that override auto-generated envelope values in the built response.
@@ -136,6 +136,7 @@ interface ToolCall {
136
136
  }
137
137
  interface ToolCallResponse extends ResponseOverrides {
138
138
  toolCalls: ToolCall[];
139
+ webSearches?: string[];
139
140
  }
140
141
  interface ContentWithToolCallsResponse extends ResponseOverrides {
141
142
  content: string;
@@ -147,6 +148,7 @@ interface ErrorResponse {
147
148
  error: {
148
149
  message: string;
149
150
  type?: string;
151
+ param?: string | null;
150
152
  code?: string;
151
153
  };
152
154
  status?: number;
@@ -235,6 +237,10 @@ interface Fixture {
235
237
  disconnectAfterMs?: number;
236
238
  streamingProfile?: StreamingProfile;
237
239
  chaos?: ChaosConfig;
240
+ metadata?: {
241
+ systemHash?: string;
242
+ toolsHash?: string;
243
+ };
238
244
  }
239
245
  type FixtureOpts = Omit<Fixture, "match" | "response">;
240
246
  type EmbeddingFixtureOpts = Pick<FixtureOpts, "latency" | "chaos">;
@@ -246,6 +252,7 @@ interface FixtureFileToolCall {
246
252
  }
247
253
  interface FixtureFileToolCallResponse extends ResponseOverrides {
248
254
  toolCalls: FixtureFileToolCall[];
255
+ webSearches?: string[];
249
256
  }
250
257
  interface FixtureFileTextResponse extends ResponseOverrides {
251
258
  /** Accepts a JSON object or array (structured output) — the loader will JSON.stringify it. */
@@ -281,7 +288,7 @@ interface FixtureFileEntry {
281
288
  sequenceIndex?: number;
282
289
  turnIndex?: number;
283
290
  hasToolResult?: boolean;
284
- endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding" | "audio-gen" | "fal-audio" | "fal";
291
+ endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding" | "audio-gen" | "fal-audio" | "fal" | "realtime" | "realtime-transcription" | "realtime-translation";
285
292
  };
286
293
  response: FixtureFileResponse;
287
294
  latency?: number;
@@ -290,6 +297,10 @@ interface FixtureFileEntry {
290
297
  disconnectAfterMs?: number;
291
298
  streamingProfile?: StreamingProfile;
292
299
  chaos?: ChaosConfig;
300
+ metadata?: {
301
+ systemHash?: string;
302
+ toolsHash?: string;
303
+ };
293
304
  }
294
305
  interface JournalEntry {
295
306
  id: string;
@@ -377,6 +388,12 @@ interface RecordConfig {
377
388
  fixturePath?: string;
378
389
  /** Proxy unmatched requests without saving fixtures or caching in memory. */
379
390
  proxyOnly?: boolean;
391
+ /**
392
+ * When true, record the exact model version string returned by the provider
393
+ * (e.g. "gpt-4o-2024-08-06") instead of stripping the date suffix to a
394
+ * canonical alias (e.g. "gpt-4o"). Default: false.
395
+ */
396
+ recordFullModelVersion?: boolean;
380
397
  }
381
398
  interface MockServerOptions {
382
399
  port?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/video.cjs CHANGED
@@ -15,14 +15,28 @@ const VIDEO_STATE_TTL_MS = 36e5;
15
15
  */
16
16
  var VideoStateMap = class {
17
17
  entries = /* @__PURE__ */ new Map();
18
- get(key) {
18
+ sweepTimer;
19
+ constructor() {
20
+ this.sweepTimer = setInterval(() => {
21
+ const now = Date.now();
22
+ for (const [key, entry] of this.entries) if (now - entry.createdAt > VIDEO_STATE_TTL_MS) this.entries.delete(key);
23
+ }, 6e4);
24
+ if (this.sweepTimer.unref) this.sweepTimer.unref();
25
+ }
26
+ getEntry(key) {
19
27
  const entry = this.entries.get(key);
20
28
  if (!entry) return void 0;
21
29
  if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {
22
30
  this.entries.delete(key);
23
31
  return;
24
32
  }
25
- return entry.video;
33
+ return {
34
+ video: entry.video,
35
+ createdAtUnix: Math.floor(entry.createdAt / 1e3)
36
+ };
37
+ }
38
+ getCreatedAtUnix(key) {
39
+ return this.getEntry(key)?.createdAtUnix;
26
40
  }
27
41
  set(key, video) {
28
42
  this.entries.set(key, {
@@ -44,6 +58,10 @@ var VideoStateMap = class {
44
58
  clear() {
45
59
  this.entries.clear();
46
60
  }
61
+ destroy() {
62
+ clearInterval(this.sweepTimer);
63
+ this.entries.clear();
64
+ }
47
65
  get size() {
48
66
  return this.entries.size;
49
67
  }
@@ -112,8 +130,29 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
112
130
  body: syntheticReq
113
131
  }, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
114
132
  if (!fixture) {
133
+ if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
134
+ journal.add({
135
+ method,
136
+ path,
137
+ headers: require_helpers.flattenHeaders(req.headers),
138
+ body: syntheticReq,
139
+ response: {
140
+ status: 503,
141
+ fixture: null,
142
+ ...require_helpers.strictOverrideField(defaults.strict, req.headers)
143
+ }
144
+ });
145
+ require_sse_writer.writeErrorResponse(res, 503, JSON.stringify({ error: {
146
+ message: "Strict mode: no fixture matched",
147
+ type: "invalid_request_error",
148
+ code: "no_fixture_match"
149
+ } }));
150
+ return;
151
+ }
115
152
  if (defaults.record) {
116
- if (await require_recorder.proxyAndRecord(req, res, syntheticReq, "openai", req.url ?? "/v1/videos", fixtures, defaults, raw) !== "not_configured") {
153
+ const outcome = await require_recorder.proxyAndRecord(req, res, syntheticReq, "openai", req.url ?? "/v1/videos", fixtures, defaults, raw);
154
+ if (outcome === "handled_by_hook") return;
155
+ if (outcome !== "not_configured") {
117
156
  journal.add({
118
157
  method,
119
158
  path,
@@ -128,22 +167,19 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
128
167
  return;
129
168
  }
130
169
  }
131
- const effectiveStrict = require_helpers.resolveStrictMode(defaults.strict, req.headers);
132
- const strictStatus = effectiveStrict ? 503 : 404;
133
- const strictMessage = effectiveStrict ? "Strict mode: no fixture matched" : "No fixture matched";
134
170
  journal.add({
135
171
  method,
136
172
  path,
137
173
  headers: require_helpers.flattenHeaders(req.headers),
138
174
  body: syntheticReq,
139
175
  response: {
140
- status: strictStatus,
176
+ status: 404,
141
177
  fixture: null,
142
178
  ...require_helpers.strictOverrideField(defaults.strict, req.headers)
143
179
  }
144
180
  });
145
- require_sse_writer.writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
146
- message: strictMessage,
181
+ require_sse_writer.writeErrorResponse(res, 404, JSON.stringify({ error: {
182
+ message: "No fixture matched",
147
183
  type: "invalid_request_error",
148
184
  code: "no_fixture_match"
149
185
  } }));
@@ -162,7 +198,7 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
162
198
  fixture
163
199
  }
164
200
  });
165
- require_sse_writer.writeErrorResponse(res, status, JSON.stringify(response));
201
+ require_sse_writer.writeErrorResponse(res, status, require_helpers.serializeErrorResponse(response));
166
202
  return;
167
203
  }
168
204
  if (!require_helpers.isVideoResponse(response)) {
@@ -193,9 +229,9 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
193
229
  }
194
230
  });
195
231
  const video = response.video;
196
- const created_at = Math.floor(Date.now() / 1e3);
197
232
  const stateKey = `${testId}:${video.id}`;
198
233
  videoStates.set(stateKey, video);
234
+ const created_at = videoStates.getCreatedAtUnix(stateKey);
199
235
  if (video.status === "completed") {
200
236
  res.writeHead(200, { "Content-Type": "application/json" });
201
237
  res.end(JSON.stringify({
@@ -224,8 +260,8 @@ function handleVideoStatus(req, res, videoId, journal, defaults, setCorsHeaders,
224
260
  body: null
225
261
  }, "internal", defaults.registry, defaults.logger)) return;
226
262
  const stateKey = `${require_helpers.getTestId(req)}:${videoId}`;
227
- const video = videoStates.get(stateKey);
228
- if (!video) {
263
+ const entry = videoStates.getEntry(stateKey);
264
+ if (!entry) {
229
265
  journal.add({
230
266
  method,
231
267
  path,
@@ -242,6 +278,7 @@ function handleVideoStatus(req, res, videoId, journal, defaults, setCorsHeaders,
242
278
  } }));
243
279
  return;
244
280
  }
281
+ const { video, createdAtUnix: created_at } = entry;
245
282
  journal.add({
246
283
  method,
247
284
  path,
@@ -252,7 +289,6 @@ function handleVideoStatus(req, res, videoId, journal, defaults, setCorsHeaders,
252
289
  fixture: null
253
290
  }
254
291
  });
255
- const created_at = Math.floor(Date.now() / 1e3);
256
292
  const body = {
257
293
  id: video.id,
258
294
  status: video.status,
@@ -1 +1 @@
1
- {"version":3,"file":"video.cjs","names":["flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","resolveStrictMode","strictOverrideField","resolveResponse","isErrorResponse","isVideoResponse"],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\ninterface VideoRequest {\n model?: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n// ─── VideoStateMap with TTL and size bound ────────────────────────────────\n\nconst VIDEO_STATE_MAX_ENTRIES = 10_000;\nconst VIDEO_STATE_TTL_MS = 3_600_000; // 1 hour\n\ninterface VideoStateEntry {\n video: VideoResponse[\"video\"];\n createdAt: number;\n}\n\n/**\n * A Map wrapper for video state that enforces a maximum size and per-entry TTL.\n * Entries older than VIDEO_STATE_TTL_MS are lazily evicted on `get`.\n * When the map exceeds VIDEO_STATE_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class VideoStateMap {\n private readonly entries = new Map<string, VideoStateEntry>();\n\n get(key: string): VideoResponse[\"video\"] | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.video;\n }\n\n set(key: string, video: VideoResponse[\"video\"]): void {\n this.entries.set(key, { video, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > VIDEO_STATE_MAX_ENTRIES) {\n const excess = this.entries.size - VIDEO_STATE_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\nexport async function handleVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/videos\";\n const method = req.method ?? \"POST\";\n\n let videoReq: VideoRequest;\n try {\n videoReq = JSON.parse(raw) as VideoRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n if (!videoReq.prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Missing required parameter: 'prompt'\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model: videoReq.model ?? \"sora-2\",\n messages: [{ role: \"user\", content: videoReq.prompt }],\n _endpointType: \"video\",\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const strictStatus = effectiveStrict ? 503 : 404;\n const strictMessage = effectiveStrict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: { message: strictMessage, type: \"invalid_request_error\", code: \"no_fixture_match\" },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n if (!isVideoResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not a video type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const video = response.video;\n const created_at = Math.floor(Date.now() / 1000);\n\n // Store for GET status checks\n const stateKey = `${testId}:${video.id}`;\n videoStates.set(stateKey, video);\n\n if (video.status === \"completed\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, url: video.url, created_at }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, created_at }));\n }\n}\n\nexport function handleVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n videoId: string,\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): void {\n setCorsHeaders(res);\n const path = req.url ?? `/v1/videos/${videoId}`;\n const method = req.method ?? \"GET\";\n\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const stateKey = `${testId}:${videoId}`;\n const video = videoStates.get(stateKey);\n\n if (!video) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({ error: { message: `Video ${videoId} not found`, type: \"not_found\" } }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n const created_at = Math.floor(Date.now() / 1000);\n const body: Record<string, unknown> = {\n id: video.id,\n status: video.status,\n created_at,\n };\n if (video.url) body.url = video.url;\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"video.cjs","names":["flattenHeaders","getTestId","matchFixture","applyChaos","resolveStrictMode","strictOverrideField","proxyAndRecord","resolveResponse","isErrorResponse","serializeErrorResponse","isVideoResponse"],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\ninterface VideoRequest {\n model?: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n// ─── VideoStateMap with TTL and size bound ────────────────────────────────\n\nconst VIDEO_STATE_MAX_ENTRIES = 10_000;\nconst VIDEO_STATE_TTL_MS = 3_600_000; // 1 hour\n\ninterface VideoStateEntry {\n video: VideoResponse[\"video\"];\n createdAt: number;\n}\n\n/**\n * A Map wrapper for video state that enforces a maximum size and per-entry TTL.\n * Entries older than VIDEO_STATE_TTL_MS are lazily evicted on `get`.\n * When the map exceeds VIDEO_STATE_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class VideoStateMap {\n private readonly entries = new Map<string, VideoStateEntry>();\n private readonly sweepTimer: ReturnType<typeof setInterval>;\n\n constructor() {\n // Proactive sweep every 60 seconds to evict expired entries\n this.sweepTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of this.entries) {\n if (now - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n }\n }\n }, 60_000);\n // Allow the process to exit even if the timer is still running\n if (this.sweepTimer.unref) {\n this.sweepTimer.unref();\n }\n }\n\n getEntry(key: string): { video: VideoResponse[\"video\"]; createdAtUnix: number } | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return { video: entry.video, createdAtUnix: Math.floor(entry.createdAt / 1000) };\n }\n\n getCreatedAtUnix(key: string): number | undefined {\n const e = this.getEntry(key);\n return e?.createdAtUnix;\n }\n\n set(key: string, video: VideoResponse[\"video\"]): void {\n this.entries.set(key, { video, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > VIDEO_STATE_MAX_ENTRIES) {\n const excess = this.entries.size - VIDEO_STATE_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\nexport async function handleVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/videos\";\n const method = req.method ?? \"POST\";\n\n let videoReq: VideoRequest;\n try {\n videoReq = JSON.parse(raw) as VideoRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n if (!videoReq.prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Missing required parameter: 'prompt'\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model: videoReq.model ?? \"sora-2\",\n messages: [{ role: \"user\", content: videoReq.prompt }],\n _endpointType: \"video\",\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: \"Strict mode: no fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response));\n return;\n }\n\n if (!isVideoResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not a video type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const video = response.video;\n\n // Store for GET status checks\n const stateKey = `${testId}:${video.id}`;\n videoStates.set(stateKey, video);\n const created_at = videoStates.getCreatedAtUnix(stateKey)!;\n\n if (video.status === \"completed\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, url: video.url, created_at }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, created_at }));\n }\n}\n\nexport function handleVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n videoId: string,\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): void {\n setCorsHeaders(res);\n const path = req.url ?? `/v1/videos/${videoId}`;\n const method = req.method ?? \"GET\";\n\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const stateKey = `${testId}:${videoId}`;\n const entry = videoStates.getEntry(stateKey);\n\n if (!entry) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({ error: { message: `Video ${videoId} not found`, type: \"not_found\" } }),\n );\n return;\n }\n\n const { video, createdAtUnix: created_at } = entry;\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n const body: Record<string, unknown> = {\n id: video.id,\n status: video.status,\n created_at,\n };\n if (video.url) body.url = video.url;\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
package/dist/video.d.cts CHANGED
@@ -12,10 +12,17 @@ import * as http$1 from "node:http";
12
12
  */
13
13
  declare class VideoStateMap {
14
14
  private readonly entries;
15
- get(key: string): VideoResponse["video"] | undefined;
15
+ private readonly sweepTimer;
16
+ constructor();
17
+ getEntry(key: string): {
18
+ video: VideoResponse["video"];
19
+ createdAtUnix: number;
20
+ } | undefined;
21
+ getCreatedAtUnix(key: string): number | undefined;
16
22
  set(key: string, video: VideoResponse["video"]): void;
17
23
  delete(key: string): boolean;
18
24
  clear(): void;
25
+ destroy(): void;
19
26
  get size(): number;
20
27
  }
21
28
  declare function handleVideoCreate(req: http$1.IncomingMessage, res: http$1.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http$1.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAuCA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAA,MAAK,EAAA,KAAA,EA3Bc,aA2Bd,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA,OAAA;OAEA,CAAA,CAAA,EAAA,IAAA;MACD,IAAA,CAAA,CAAA,EAAA,MAAA;;AAEa,iBAPF,iBAAA,CAOO,GAAA,EANtB,MAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,MAAA,CAAK,cAKiB,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAHjB,OAGiB,EAAA,EAAA,OAAA,EAFlB,OAEkB,EAAA,QAAA,EADjB,eACiB,EAAA,cAAA,EAAA,CAAA,GAAA,EAAL,MAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,iBAiMC,iBAAA,CAjMD,GAAA,EAkMR,MAAA,CAAK,eAlMG,EAAA,GAAA,EAmMR,MAAA,CAAK,cAnMG,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAqMJ,OArMI,EAAA,QAAA,EAsMH,eAtMG,EAAA,cAAA,EAAA,CAAA,GAAA,EAuMS,MAAA,CAAK,cAvMd,EAAA,GAAA,IAAA,EAAA,WAAA,EAwMA,aAxMA,CAAA,EAAA,IAAA"}
1
+ {"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAwCA;;;;AAmCuC,cAnC1B,aAAA,CAmC0B;EA+BjB,iBAAA,OAAiB;EAAA,iBAAA,UAAA;aAC3B,CAAA;UACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA;IAEA,KAAA,EAlDsB,aAkDtB,CAAA,OAAA,CAAA;IACD,aAAA,EAAA,MAAA;MACC,SAAA;kBACiB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,SAAA;KACd,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAvCW,aAuCX,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACZ,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAO,KAAA,CAAA,CAAA,EAAA,IAAA;EA0NM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBArOe,iBAAA,CAqOV,GAAA,EApOL,MAAA,CAAK,eAoOA,EAAA,GAAA,EAnOL,MAAA,CAAK,cAmOA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAjOA,OAiOA,EAAA,EAAA,OAAA,EAhOD,OAgOC,EAAA,QAAA,EA/NA,eA+NA,EAAA,cAAA,EAAA,CAAA,GAAA,EA9NY,MAAA,CAAK,cA8NjB,EAAA,GAAA,IAAA,EAAA,WAAA,EA7NG,aA6NH,CAAA,EA5NT,OA4NS,CAAA,IAAA,CAAA;AAED,iBAJK,iBAAA,CAIL,GAAA,EAHJ,MAAA,CAAK,eAGD,EAAA,GAAA,EAFJ,MAAA,CAAK,cAED,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAAA,QAAA,EACC,eADD,EAAA,cAAA,EAAA,CAAA,GAAA,EAEa,MAAA,CAAK,cAFlB,EAAA,GAAA,IAAA,EAAA,WAAA,EAGI,aAHJ,CAAA,EAAA,IAAA"}
package/dist/video.d.ts CHANGED
@@ -12,10 +12,17 @@ import * as http$1 from "node:http";
12
12
  */
13
13
  declare class VideoStateMap {
14
14
  private readonly entries;
15
- get(key: string): VideoResponse["video"] | undefined;
15
+ private readonly sweepTimer;
16
+ constructor();
17
+ getEntry(key: string): {
18
+ video: VideoResponse["video"];
19
+ createdAtUnix: number;
20
+ } | undefined;
21
+ getCreatedAtUnix(key: string): number | undefined;
16
22
  set(key: string, video: VideoResponse["video"]): void;
17
23
  delete(key: string): boolean;
18
24
  clear(): void;
25
+ destroy(): void;
19
26
  get size(): number;
20
27
  }
21
28
  declare function handleVideoCreate(req: http$1.IncomingMessage, res: http$1.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http$1.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAuCA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAA,MAAK,EAAA,KAAA,EA3Bc,aA2Bd,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA,OAAA;OAEA,CAAA,CAAA,EAAA,IAAA;MACD,IAAA,CAAA,CAAA,EAAA,MAAA;;AAEa,iBAPF,iBAAA,CAOO,GAAA,EANtB,MAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,MAAA,CAAK,cAKiB,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAHjB,OAGiB,EAAA,EAAA,OAAA,EAFlB,OAEkB,EAAA,QAAA,EADjB,eACiB,EAAA,cAAA,EAAA,CAAA,GAAA,EAAL,MAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,iBAiMC,iBAAA,CAjMD,GAAA,EAkMR,MAAA,CAAK,eAlMG,EAAA,GAAA,EAmMR,MAAA,CAAK,cAnMG,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAqMJ,OArMI,EAAA,QAAA,EAsMH,eAtMG,EAAA,cAAA,EAAA,CAAA,GAAA,EAuMS,MAAA,CAAK,cAvMd,EAAA,GAAA,IAAA,EAAA,WAAA,EAwMA,aAxMA,CAAA,EAAA,IAAA"}
1
+ {"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAwCA;;;;AAmCuC,cAnC1B,aAAA,CAmC0B;EA+BjB,iBAAA,OAAiB;EAAA,iBAAA,UAAA;aAC3B,CAAA;UACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA;IAEA,KAAA,EAlDsB,aAkDtB,CAAA,OAAA,CAAA;IACD,aAAA,EAAA,MAAA;MACC,SAAA;kBACiB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,SAAA;KACd,CAAA,GAAA,EAAA,MAAA,EAAA,KAAA,EAvCW,aAuCX,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACZ,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAO,KAAA,CAAA,CAAA,EAAA,IAAA;EA0NM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBArOe,iBAAA,CAqOV,GAAA,EApOL,MAAA,CAAK,eAoOA,EAAA,GAAA,EAnOL,MAAA,CAAK,cAmOA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAjOA,OAiOA,EAAA,EAAA,OAAA,EAhOD,OAgOC,EAAA,QAAA,EA/NA,eA+NA,EAAA,cAAA,EAAA,CAAA,GAAA,EA9NY,MAAA,CAAK,cA8NjB,EAAA,GAAA,IAAA,EAAA,WAAA,EA7NG,aA6NH,CAAA,EA5NT,OA4NS,CAAA,IAAA,CAAA;AAED,iBAJK,iBAAA,CAIL,GAAA,EAHJ,MAAA,CAAK,eAGD,EAAA,GAAA,EAFJ,MAAA,CAAK,cAED,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,OAAA,EAAA,QAAA,EACC,eADD,EAAA,cAAA,EAAA,CAAA,GAAA,EAEa,MAAA,CAAK,cAFlB,EAAA,GAAA,IAAA,EAAA,WAAA,EAGI,aAHJ,CAAA,EAAA,IAAA"}
package/dist/video.js CHANGED
@@ -1,4 +1,4 @@
1
- import { flattenHeaders, getTestId, isErrorResponse, isVideoResponse, resolveResponse, resolveStrictMode, strictOverrideField } from "./helpers.js";
1
+ import { flattenHeaders, getTestId, isErrorResponse, isVideoResponse, resolveResponse, resolveStrictMode, serializeErrorResponse, strictOverrideField } from "./helpers.js";
2
2
  import { matchFixture } from "./router.js";
3
3
  import { writeErrorResponse } from "./sse-writer.js";
4
4
  import { applyChaos } from "./chaos.js";
@@ -15,14 +15,28 @@ const VIDEO_STATE_TTL_MS = 36e5;
15
15
  */
16
16
  var VideoStateMap = class {
17
17
  entries = /* @__PURE__ */ new Map();
18
- get(key) {
18
+ sweepTimer;
19
+ constructor() {
20
+ this.sweepTimer = setInterval(() => {
21
+ const now = Date.now();
22
+ for (const [key, entry] of this.entries) if (now - entry.createdAt > VIDEO_STATE_TTL_MS) this.entries.delete(key);
23
+ }, 6e4);
24
+ if (this.sweepTimer.unref) this.sweepTimer.unref();
25
+ }
26
+ getEntry(key) {
19
27
  const entry = this.entries.get(key);
20
28
  if (!entry) return void 0;
21
29
  if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {
22
30
  this.entries.delete(key);
23
31
  return;
24
32
  }
25
- return entry.video;
33
+ return {
34
+ video: entry.video,
35
+ createdAtUnix: Math.floor(entry.createdAt / 1e3)
36
+ };
37
+ }
38
+ getCreatedAtUnix(key) {
39
+ return this.getEntry(key)?.createdAtUnix;
26
40
  }
27
41
  set(key, video) {
28
42
  this.entries.set(key, {
@@ -44,6 +58,10 @@ var VideoStateMap = class {
44
58
  clear() {
45
59
  this.entries.clear();
46
60
  }
61
+ destroy() {
62
+ clearInterval(this.sweepTimer);
63
+ this.entries.clear();
64
+ }
47
65
  get size() {
48
66
  return this.entries.size;
49
67
  }
@@ -112,8 +130,29 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
112
130
  body: syntheticReq
113
131
  }, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
114
132
  if (!fixture) {
133
+ if (resolveStrictMode(defaults.strict, req.headers)) {
134
+ journal.add({
135
+ method,
136
+ path,
137
+ headers: flattenHeaders(req.headers),
138
+ body: syntheticReq,
139
+ response: {
140
+ status: 503,
141
+ fixture: null,
142
+ ...strictOverrideField(defaults.strict, req.headers)
143
+ }
144
+ });
145
+ writeErrorResponse(res, 503, JSON.stringify({ error: {
146
+ message: "Strict mode: no fixture matched",
147
+ type: "invalid_request_error",
148
+ code: "no_fixture_match"
149
+ } }));
150
+ return;
151
+ }
115
152
  if (defaults.record) {
116
- if (await proxyAndRecord(req, res, syntheticReq, "openai", req.url ?? "/v1/videos", fixtures, defaults, raw) !== "not_configured") {
153
+ const outcome = await proxyAndRecord(req, res, syntheticReq, "openai", req.url ?? "/v1/videos", fixtures, defaults, raw);
154
+ if (outcome === "handled_by_hook") return;
155
+ if (outcome !== "not_configured") {
117
156
  journal.add({
118
157
  method,
119
158
  path,
@@ -128,22 +167,19 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
128
167
  return;
129
168
  }
130
169
  }
131
- const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);
132
- const strictStatus = effectiveStrict ? 503 : 404;
133
- const strictMessage = effectiveStrict ? "Strict mode: no fixture matched" : "No fixture matched";
134
170
  journal.add({
135
171
  method,
136
172
  path,
137
173
  headers: flattenHeaders(req.headers),
138
174
  body: syntheticReq,
139
175
  response: {
140
- status: strictStatus,
176
+ status: 404,
141
177
  fixture: null,
142
178
  ...strictOverrideField(defaults.strict, req.headers)
143
179
  }
144
180
  });
145
- writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
146
- message: strictMessage,
181
+ writeErrorResponse(res, 404, JSON.stringify({ error: {
182
+ message: "No fixture matched",
147
183
  type: "invalid_request_error",
148
184
  code: "no_fixture_match"
149
185
  } }));
@@ -162,7 +198,7 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
162
198
  fixture
163
199
  }
164
200
  });
165
- writeErrorResponse(res, status, JSON.stringify(response));
201
+ writeErrorResponse(res, status, serializeErrorResponse(response));
166
202
  return;
167
203
  }
168
204
  if (!isVideoResponse(response)) {
@@ -193,9 +229,9 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
193
229
  }
194
230
  });
195
231
  const video = response.video;
196
- const created_at = Math.floor(Date.now() / 1e3);
197
232
  const stateKey = `${testId}:${video.id}`;
198
233
  videoStates.set(stateKey, video);
234
+ const created_at = videoStates.getCreatedAtUnix(stateKey);
199
235
  if (video.status === "completed") {
200
236
  res.writeHead(200, { "Content-Type": "application/json" });
201
237
  res.end(JSON.stringify({
@@ -224,8 +260,8 @@ function handleVideoStatus(req, res, videoId, journal, defaults, setCorsHeaders,
224
260
  body: null
225
261
  }, "internal", defaults.registry, defaults.logger)) return;
226
262
  const stateKey = `${getTestId(req)}:${videoId}`;
227
- const video = videoStates.get(stateKey);
228
- if (!video) {
263
+ const entry = videoStates.getEntry(stateKey);
264
+ if (!entry) {
229
265
  journal.add({
230
266
  method,
231
267
  path,
@@ -242,6 +278,7 @@ function handleVideoStatus(req, res, videoId, journal, defaults, setCorsHeaders,
242
278
  } }));
243
279
  return;
244
280
  }
281
+ const { video, createdAtUnix: created_at } = entry;
245
282
  journal.add({
246
283
  method,
247
284
  path,
@@ -252,7 +289,6 @@ function handleVideoStatus(req, res, videoId, journal, defaults, setCorsHeaders,
252
289
  fixture: null
253
290
  }
254
291
  });
255
- const created_at = Math.floor(Date.now() / 1e3);
256
292
  const body = {
257
293
  id: video.id,
258
294
  status: video.status,
package/dist/video.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"video.js","names":[],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\ninterface VideoRequest {\n model?: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n// ─── VideoStateMap with TTL and size bound ────────────────────────────────\n\nconst VIDEO_STATE_MAX_ENTRIES = 10_000;\nconst VIDEO_STATE_TTL_MS = 3_600_000; // 1 hour\n\ninterface VideoStateEntry {\n video: VideoResponse[\"video\"];\n createdAt: number;\n}\n\n/**\n * A Map wrapper for video state that enforces a maximum size and per-entry TTL.\n * Entries older than VIDEO_STATE_TTL_MS are lazily evicted on `get`.\n * When the map exceeds VIDEO_STATE_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class VideoStateMap {\n private readonly entries = new Map<string, VideoStateEntry>();\n\n get(key: string): VideoResponse[\"video\"] | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.video;\n }\n\n set(key: string, video: VideoResponse[\"video\"]): void {\n this.entries.set(key, { video, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > VIDEO_STATE_MAX_ENTRIES) {\n const excess = this.entries.size - VIDEO_STATE_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\nexport async function handleVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/videos\";\n const method = req.method ?? \"POST\";\n\n let videoReq: VideoRequest;\n try {\n videoReq = JSON.parse(raw) as VideoRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n if (!videoReq.prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Missing required parameter: 'prompt'\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model: videoReq.model ?? \"sora-2\",\n messages: [{ role: \"user\", content: videoReq.prompt }],\n _endpointType: \"video\",\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n const strictStatus = effectiveStrict ? 503 : 404;\n const strictMessage = effectiveStrict\n ? \"Strict mode: no fixture matched\"\n : \"No fixture matched\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: strictStatus,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: { message: strictMessage, type: \"invalid_request_error\", code: \"no_fixture_match\" },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, JSON.stringify(response));\n return;\n }\n\n if (!isVideoResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not a video type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const video = response.video;\n const created_at = Math.floor(Date.now() / 1000);\n\n // Store for GET status checks\n const stateKey = `${testId}:${video.id}`;\n videoStates.set(stateKey, video);\n\n if (video.status === \"completed\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, url: video.url, created_at }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, created_at }));\n }\n}\n\nexport function handleVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n videoId: string,\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): void {\n setCorsHeaders(res);\n const path = req.url ?? `/v1/videos/${videoId}`;\n const method = req.method ?? \"GET\";\n\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const stateKey = `${testId}:${videoId}`;\n const video = videoStates.get(stateKey);\n\n if (!video) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({ error: { message: `Video ${videoId} not found`, type: \"not_found\" } }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n const created_at = Math.floor(Date.now() / 1000);\n const body: Record<string, unknown> = {\n id: video.id,\n status: video.status,\n created_at,\n };\n if (video.url) body.url = video.url;\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"video.js","names":[],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport {\n isVideoResponse,\n isErrorResponse,\n serializeErrorResponse,\n flattenHeaders,\n getTestId,\n resolveResponse,\n resolveStrictMode,\n strictOverrideField,\n} from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\ninterface VideoRequest {\n model?: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n// ─── VideoStateMap with TTL and size bound ────────────────────────────────\n\nconst VIDEO_STATE_MAX_ENTRIES = 10_000;\nconst VIDEO_STATE_TTL_MS = 3_600_000; // 1 hour\n\ninterface VideoStateEntry {\n video: VideoResponse[\"video\"];\n createdAt: number;\n}\n\n/**\n * A Map wrapper for video state that enforces a maximum size and per-entry TTL.\n * Entries older than VIDEO_STATE_TTL_MS are lazily evicted on `get`.\n * When the map exceeds VIDEO_STATE_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class VideoStateMap {\n private readonly entries = new Map<string, VideoStateEntry>();\n private readonly sweepTimer: ReturnType<typeof setInterval>;\n\n constructor() {\n // Proactive sweep every 60 seconds to evict expired entries\n this.sweepTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of this.entries) {\n if (now - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n }\n }\n }, 60_000);\n // Allow the process to exit even if the timer is still running\n if (this.sweepTimer.unref) {\n this.sweepTimer.unref();\n }\n }\n\n getEntry(key: string): { video: VideoResponse[\"video\"]; createdAtUnix: number } | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.createdAt > VIDEO_STATE_TTL_MS) {\n this.entries.delete(key);\n return undefined;\n }\n return { video: entry.video, createdAtUnix: Math.floor(entry.createdAt / 1000) };\n }\n\n getCreatedAtUnix(key: string): number | undefined {\n const e = this.getEntry(key);\n return e?.createdAtUnix;\n }\n\n set(key: string, video: VideoResponse[\"video\"]): void {\n this.entries.set(key, { video, createdAt: Date.now() });\n // Evict oldest entries if over capacity\n if (this.entries.size > VIDEO_STATE_MAX_ENTRIES) {\n const excess = this.entries.size - VIDEO_STATE_MAX_ENTRIES;\n const iter = this.entries.keys();\n for (let i = 0; i < excess; i++) {\n const next = iter.next();\n if (!next.done) this.entries.delete(next.value);\n }\n }\n }\n\n delete(key: string): boolean {\n return this.entries.delete(key);\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n destroy(): void {\n clearInterval(this.sweepTimer);\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\nexport async function handleVideoCreate(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n raw: string,\n fixtures: Fixture[],\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/videos\";\n const method = req.method ?? \"POST\";\n\n let videoReq: VideoRequest;\n try {\n videoReq = JSON.parse(raw) as VideoRequest;\n } catch (parseErr) {\n const detail = parseErr instanceof Error ? parseErr.message : \"unknown\";\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: {\n message: `Malformed JSON: ${detail}`,\n type: \"invalid_request_error\",\n code: \"invalid_json\",\n },\n }),\n );\n return;\n }\n\n if (!videoReq.prompt) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 400, fixture: null },\n });\n writeErrorResponse(\n res,\n 400,\n JSON.stringify({\n error: { message: \"Missing required parameter: 'prompt'\", type: \"invalid_request_error\" },\n }),\n );\n return;\n }\n\n const syntheticReq: ChatCompletionRequest = {\n model: videoReq.model ?? \"sora-2\",\n messages: [{ role: \"user\", content: videoReq.prompt }],\n _endpointType: \"video\",\n };\n\n const testId = getTestId(req);\n const fixture = matchFixture(\n fixtures,\n syntheticReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);\n } else {\n defaults.logger.debug(`No fixture matched for request`);\n }\n\n if (\n applyChaos(\n res,\n fixture,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: syntheticReq },\n fixture ? \"fixture\" : \"proxy\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n const effectiveStrict = resolveStrictMode(defaults.strict, req.headers);\n if (effectiveStrict) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 503,\n JSON.stringify({\n error: {\n message: \"Strict mode: no fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n if (defaults.record) {\n const outcome = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (outcome === \"handled_by_hook\") return;\n if (outcome !== \"not_configured\") {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: res.statusCode ?? 200, fixture: null, source: \"proxy\" },\n });\n return;\n }\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: {\n status: 404,\n fixture: null,\n ...strictOverrideField(defaults.strict, req.headers),\n },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({\n error: {\n message: \"No fixture matched\",\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = await resolveResponse(fixture, syntheticReq);\n\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status, fixture },\n });\n writeErrorResponse(res, status, serializeErrorResponse(response));\n return;\n }\n\n if (!isVideoResponse(response)) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 500, fixture },\n });\n writeErrorResponse(\n res,\n 500,\n JSON.stringify({\n error: { message: \"Fixture response is not a video type\", type: \"server_error\" },\n }),\n );\n return;\n }\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: syntheticReq,\n response: { status: 200, fixture },\n });\n\n const video = response.video;\n\n // Store for GET status checks\n const stateKey = `${testId}:${video.id}`;\n videoStates.set(stateKey, video);\n const created_at = videoStates.getCreatedAtUnix(stateKey)!;\n\n if (video.status === \"completed\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, url: video.url, created_at }));\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ id: video.id, status: video.status, created_at }));\n }\n}\n\nexport function handleVideoStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n videoId: string,\n journal: Journal,\n defaults: HandlerDefaults,\n setCorsHeaders: (res: http.ServerResponse) => void,\n videoStates: VideoStateMap,\n): void {\n setCorsHeaders(res);\n const path = req.url ?? `/v1/videos/${videoId}`;\n const method = req.method ?? \"GET\";\n\n if (\n applyChaos(\n res,\n null,\n defaults.chaos,\n req.headers,\n journal,\n { method, path, headers: flattenHeaders(req.headers), body: null },\n \"internal\",\n defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n const testId = getTestId(req);\n const stateKey = `${testId}:${videoId}`;\n const entry = videoStates.getEntry(stateKey);\n\n if (!entry) {\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 404, fixture: null },\n });\n writeErrorResponse(\n res,\n 404,\n JSON.stringify({ error: { message: `Video ${videoId} not found`, type: \"not_found\" } }),\n );\n return;\n }\n\n const { video, createdAtUnix: created_at } = entry;\n\n journal.add({\n method,\n path,\n headers: flattenHeaders(req.headers),\n body: null,\n response: { status: 200, fixture: null },\n });\n\n const body: Record<string, unknown> = {\n id: video.id,\n status: video.status,\n created_at,\n };\n if (video.url) body.url = video.url;\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n"],"mappings":"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"}