@copilotkit/aimock 1.25.0 → 1.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +22 -0
  4. package/README.md +5 -0
  5. package/dist/agui-types.d.cts.map +1 -1
  6. package/dist/aws-event-stream.cjs +2 -1
  7. package/dist/aws-event-stream.cjs.map +1 -1
  8. package/dist/aws-event-stream.d.cts +3 -1
  9. package/dist/aws-event-stream.d.cts.map +1 -1
  10. package/dist/aws-event-stream.d.ts +3 -1
  11. package/dist/aws-event-stream.d.ts.map +1 -1
  12. package/dist/aws-event-stream.js +2 -1
  13. package/dist/aws-event-stream.js.map +1 -1
  14. package/dist/bedrock-converse.cjs +8 -0
  15. package/dist/bedrock-converse.cjs.map +1 -1
  16. package/dist/bedrock-converse.d.cts.map +1 -1
  17. package/dist/bedrock-converse.d.ts.map +1 -1
  18. package/dist/bedrock-converse.js +9 -1
  19. package/dist/bedrock-converse.js.map +1 -1
  20. package/dist/bedrock.cjs +8 -0
  21. package/dist/bedrock.cjs.map +1 -1
  22. package/dist/bedrock.d.cts.map +1 -1
  23. package/dist/bedrock.d.ts.map +1 -1
  24. package/dist/bedrock.js +9 -1
  25. package/dist/bedrock.js.map +1 -1
  26. package/dist/cli.cjs +11 -0
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +11 -0
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +11 -2
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +12 -3
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.d.cts.map +1 -1
  37. package/dist/elevenlabs-audio.cjs +4 -2
  38. package/dist/elevenlabs-audio.cjs.map +1 -1
  39. package/dist/elevenlabs-audio.d.cts.map +1 -1
  40. package/dist/elevenlabs-audio.d.ts.map +1 -1
  41. package/dist/elevenlabs-audio.js +5 -3
  42. package/dist/elevenlabs-audio.js.map +1 -1
  43. package/dist/embeddings.cjs +2 -1
  44. package/dist/embeddings.cjs.map +1 -1
  45. package/dist/embeddings.d.cts.map +1 -1
  46. package/dist/embeddings.d.ts.map +1 -1
  47. package/dist/embeddings.js +3 -2
  48. package/dist/embeddings.js.map +1 -1
  49. package/dist/fal-audio.cjs +4 -2
  50. package/dist/fal-audio.cjs.map +1 -1
  51. package/dist/fal-audio.d.cts.map +1 -1
  52. package/dist/fal-audio.d.ts.map +1 -1
  53. package/dist/fal-audio.js +5 -3
  54. package/dist/fal-audio.js.map +1 -1
  55. package/dist/fal.cjs +2 -1
  56. package/dist/fal.cjs.map +1 -1
  57. package/dist/fal.d.cts.map +1 -1
  58. package/dist/fal.d.ts.map +1 -1
  59. package/dist/fal.js +3 -2
  60. package/dist/fal.js.map +1 -1
  61. package/dist/fixture-loader.cjs +25 -6
  62. package/dist/fixture-loader.cjs.map +1 -1
  63. package/dist/fixture-loader.d.cts.map +1 -1
  64. package/dist/fixture-loader.d.ts.map +1 -1
  65. package/dist/fixture-loader.js +25 -6
  66. package/dist/fixture-loader.js.map +1 -1
  67. package/dist/gemini-embeddings.cjs +2 -1
  68. package/dist/gemini-embeddings.cjs.map +1 -1
  69. package/dist/gemini-embeddings.js +3 -2
  70. package/dist/gemini-embeddings.js.map +1 -1
  71. package/dist/gemini-interactions.cjs +10 -1
  72. package/dist/gemini-interactions.cjs.map +1 -1
  73. package/dist/gemini-interactions.d.cts.map +1 -1
  74. package/dist/gemini-interactions.d.ts.map +1 -1
  75. package/dist/gemini-interactions.js +11 -2
  76. package/dist/gemini-interactions.js.map +1 -1
  77. package/dist/gemini.cjs +12 -1
  78. package/dist/gemini.cjs.map +1 -1
  79. package/dist/gemini.d.cts.map +1 -1
  80. package/dist/gemini.d.ts.map +1 -1
  81. package/dist/gemini.js +13 -2
  82. package/dist/gemini.js.map +1 -1
  83. package/dist/helpers.cjs +7 -0
  84. package/dist/helpers.cjs.map +1 -1
  85. package/dist/helpers.d.cts.map +1 -1
  86. package/dist/helpers.d.ts.map +1 -1
  87. package/dist/helpers.js +7 -1
  88. package/dist/helpers.js.map +1 -1
  89. package/dist/images.cjs +6 -5
  90. package/dist/images.cjs.map +1 -1
  91. package/dist/images.d.cts.map +1 -1
  92. package/dist/images.d.ts.map +1 -1
  93. package/dist/images.js +7 -6
  94. package/dist/images.js.map +1 -1
  95. package/dist/llmock.cjs +1 -1
  96. package/dist/llmock.cjs.map +1 -1
  97. package/dist/llmock.js +1 -1
  98. package/dist/llmock.js.map +1 -1
  99. package/dist/messages.cjs +9 -1
  100. package/dist/messages.cjs.map +1 -1
  101. package/dist/messages.d.cts.map +1 -1
  102. package/dist/messages.d.ts.map +1 -1
  103. package/dist/messages.js +10 -2
  104. package/dist/messages.js.map +1 -1
  105. package/dist/ndjson-writer.cjs +2 -1
  106. package/dist/ndjson-writer.cjs.map +1 -1
  107. package/dist/ndjson-writer.d.cts +3 -2
  108. package/dist/ndjson-writer.d.cts.map +1 -1
  109. package/dist/ndjson-writer.d.ts +3 -2
  110. package/dist/ndjson-writer.d.ts.map +1 -1
  111. package/dist/ndjson-writer.js +2 -1
  112. package/dist/ndjson-writer.js.map +1 -1
  113. package/dist/ollama.cjs +12 -1
  114. package/dist/ollama.cjs.map +1 -1
  115. package/dist/ollama.d.cts.map +1 -1
  116. package/dist/ollama.d.ts.map +1 -1
  117. package/dist/ollama.js +13 -2
  118. package/dist/ollama.js.map +1 -1
  119. package/dist/recorder.cjs +42 -4
  120. package/dist/recorder.cjs.map +1 -1
  121. package/dist/recorder.d.cts.map +1 -1
  122. package/dist/recorder.d.ts.map +1 -1
  123. package/dist/recorder.js +42 -4
  124. package/dist/recorder.js.map +1 -1
  125. package/dist/responses.cjs +11 -1
  126. package/dist/responses.cjs.map +1 -1
  127. package/dist/responses.d.cts.map +1 -1
  128. package/dist/responses.d.ts.map +1 -1
  129. package/dist/responses.js +12 -2
  130. package/dist/responses.js.map +1 -1
  131. package/dist/router.cjs +3 -0
  132. package/dist/router.cjs.map +1 -1
  133. package/dist/router.js +3 -0
  134. package/dist/router.js.map +1 -1
  135. package/dist/server.cjs +12 -4
  136. package/dist/server.cjs.map +1 -1
  137. package/dist/server.d.cts.map +1 -1
  138. package/dist/server.d.ts.map +1 -1
  139. package/dist/server.js +13 -5
  140. package/dist/server.js.map +1 -1
  141. package/dist/speech.cjs +2 -1
  142. package/dist/speech.cjs.map +1 -1
  143. package/dist/speech.d.cts.map +1 -1
  144. package/dist/speech.d.ts.map +1 -1
  145. package/dist/speech.js +3 -2
  146. package/dist/speech.js.map +1 -1
  147. package/dist/sse-writer.cjs +28 -8
  148. package/dist/sse-writer.cjs.map +1 -1
  149. package/dist/sse-writer.d.cts +4 -2
  150. package/dist/sse-writer.d.cts.map +1 -1
  151. package/dist/sse-writer.d.ts +4 -2
  152. package/dist/sse-writer.d.ts.map +1 -1
  153. package/dist/sse-writer.js +28 -8
  154. package/dist/sse-writer.js.map +1 -1
  155. package/dist/transcription.cjs +2 -1
  156. package/dist/transcription.cjs.map +1 -1
  157. package/dist/transcription.d.cts.map +1 -1
  158. package/dist/transcription.d.ts.map +1 -1
  159. package/dist/transcription.js +3 -2
  160. package/dist/transcription.js.map +1 -1
  161. package/dist/types.d.cts +21 -1
  162. package/dist/types.d.cts.map +1 -1
  163. package/dist/types.d.ts +21 -1
  164. package/dist/types.d.ts.map +1 -1
  165. package/dist/video.cjs +2 -1
  166. package/dist/video.cjs.map +1 -1
  167. package/dist/video.d.cts.map +1 -1
  168. package/dist/video.d.ts.map +1 -1
  169. package/dist/video.js +3 -2
  170. package/dist/video.js.map +1 -1
  171. package/dist/ws-gemini-live.cjs +18 -5
  172. package/dist/ws-gemini-live.cjs.map +1 -1
  173. package/dist/ws-gemini-live.d.cts +1 -0
  174. package/dist/ws-gemini-live.d.cts.map +1 -1
  175. package/dist/ws-gemini-live.d.ts +1 -0
  176. package/dist/ws-gemini-live.d.ts.map +1 -1
  177. package/dist/ws-gemini-live.js +19 -6
  178. package/dist/ws-gemini-live.js.map +1 -1
  179. package/dist/ws-realtime.cjs +25 -5
  180. package/dist/ws-realtime.cjs.map +1 -1
  181. package/dist/ws-realtime.d.cts +1 -0
  182. package/dist/ws-realtime.d.cts.map +1 -1
  183. package/dist/ws-realtime.d.ts +1 -0
  184. package/dist/ws-realtime.d.ts.map +1 -1
  185. package/dist/ws-realtime.js +26 -6
  186. package/dist/ws-realtime.js.map +1 -1
  187. package/dist/ws-responses.cjs +10 -5
  188. package/dist/ws-responses.cjs.map +1 -1
  189. package/dist/ws-responses.d.cts +1 -0
  190. package/dist/ws-responses.d.cts.map +1 -1
  191. package/dist/ws-responses.d.ts +1 -0
  192. package/dist/ws-responses.d.ts.map +1 -1
  193. package/dist/ws-responses.js +11 -6
  194. package/dist/ws-responses.js.map +1 -1
  195. package/package.json +1 -1
package/dist/types.d.cts CHANGED
@@ -56,6 +56,8 @@ interface ChatCompletionRequest {
56
56
  embeddingInput?: string;
57
57
  /** Endpoint type, set by handlers for fixture endpoint filtering. */
58
58
  _endpointType?: string;
59
+ /** Context identifier, set by handlers for fixture context routing. */
60
+ _context?: string;
59
61
  [key: string]: unknown;
60
62
  }
61
63
  interface ToolDefinition {
@@ -94,6 +96,7 @@ interface FixtureMatch {
94
96
  turnIndex?: number;
95
97
  hasToolResult?: boolean;
96
98
  endpoint?: "chat" | "image" | "speech" | "transcription" | "translation" | "video" | "embedding" | "audio-gen" | "elevenlabs-tts" | "fal-audio" | "fal" | "realtime" | "realtime-transcription" | "realtime-translation";
99
+ context?: string;
97
100
  }
98
101
  /**
99
102
  * Fields that override auto-generated envelope values in the built response.
@@ -218,6 +221,16 @@ interface StreamingProfile {
218
221
  tps?: number;
219
222
  jitter?: number;
220
223
  }
224
+ /**
225
+ * Per-frame arrival timestamps captured during proxy recording.
226
+ * Used during replay to reproduce real-world streaming timing instead of
227
+ * the synthetic model (StreamingProfile / flat latency).
228
+ */
229
+ interface RecordedTimings {
230
+ ttftMs: number;
231
+ interChunkDelaysMs: number[];
232
+ totalDurationMs: number;
233
+ }
221
234
  /**
222
235
  * Probabilistic chaos injection rates.
223
236
  *
@@ -242,6 +255,8 @@ interface Fixture {
242
255
  truncateAfterChunks?: number;
243
256
  disconnectAfterMs?: number;
244
257
  streamingProfile?: StreamingProfile;
258
+ recordedTimings?: RecordedTimings;
259
+ replaySpeed?: number;
245
260
  chaos?: ChaosConfig;
246
261
  metadata?: {
247
262
  systemHash?: string;
@@ -295,6 +310,7 @@ interface FixtureFileEntry {
295
310
  turnIndex?: number;
296
311
  hasToolResult?: boolean;
297
312
  endpoint?: "chat" | "image" | "speech" | "transcription" | "translation" | "video" | "embedding" | "audio-gen" | "elevenlabs-tts" | "fal-audio" | "fal" | "realtime" | "realtime-transcription" | "realtime-translation";
313
+ context?: string;
298
314
  };
299
315
  response: FixtureFileResponse;
300
316
  latency?: number;
@@ -302,6 +318,8 @@ interface FixtureFileEntry {
302
318
  truncateAfterChunks?: number;
303
319
  disconnectAfterMs?: number;
304
320
  streamingProfile?: StreamingProfile;
321
+ recordedTimings?: RecordedTimings;
322
+ replaySpeed?: number;
305
323
  chaos?: ChaosConfig;
306
324
  metadata?: {
307
325
  systemHash?: string;
@@ -439,6 +457,7 @@ interface MockServerOptions {
439
457
  host?: string;
440
458
  latency?: number;
441
459
  chunkSize?: number;
460
+ replaySpeed?: number;
442
461
  /** Log verbosity. CLI default is "info"; programmatic default (when omitted) is "silent". */
443
462
  logLevel?: "silent" | "warn" | "info" | "debug";
444
463
  chaos?: ChaosConfig;
@@ -513,6 +532,7 @@ interface FalQueueConfig {
513
532
  interface HandlerDefaults {
514
533
  latency: number;
515
534
  chunkSize: number;
535
+ replaySpeed: number;
516
536
  logger: Logger;
517
537
  chaos?: ChaosConfig;
518
538
  registry?: MetricsRegistry;
@@ -523,5 +543,5 @@ interface HandlerDefaults {
523
543
  }
524
544
  //# sourceMappingURL=types.d.ts.map
525
545
  //#endregion
526
- export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
546
+ export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, RecordedTimings, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
527
547
  //# sourceMappingURL=types.d.cts.map
@@ -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
@@ -56,6 +56,8 @@ interface ChatCompletionRequest {
56
56
  embeddingInput?: string;
57
57
  /** Endpoint type, set by handlers for fixture endpoint filtering. */
58
58
  _endpointType?: string;
59
+ /** Context identifier, set by handlers for fixture context routing. */
60
+ _context?: string;
59
61
  [key: string]: unknown;
60
62
  }
61
63
  interface ToolDefinition {
@@ -94,6 +96,7 @@ interface FixtureMatch {
94
96
  turnIndex?: number;
95
97
  hasToolResult?: boolean;
96
98
  endpoint?: "chat" | "image" | "speech" | "transcription" | "translation" | "video" | "embedding" | "audio-gen" | "elevenlabs-tts" | "fal-audio" | "fal" | "realtime" | "realtime-transcription" | "realtime-translation";
99
+ context?: string;
97
100
  }
98
101
  /**
99
102
  * Fields that override auto-generated envelope values in the built response.
@@ -218,6 +221,16 @@ interface StreamingProfile {
218
221
  tps?: number;
219
222
  jitter?: number;
220
223
  }
224
+ /**
225
+ * Per-frame arrival timestamps captured during proxy recording.
226
+ * Used during replay to reproduce real-world streaming timing instead of
227
+ * the synthetic model (StreamingProfile / flat latency).
228
+ */
229
+ interface RecordedTimings {
230
+ ttftMs: number;
231
+ interChunkDelaysMs: number[];
232
+ totalDurationMs: number;
233
+ }
221
234
  /**
222
235
  * Probabilistic chaos injection rates.
223
236
  *
@@ -242,6 +255,8 @@ interface Fixture {
242
255
  truncateAfterChunks?: number;
243
256
  disconnectAfterMs?: number;
244
257
  streamingProfile?: StreamingProfile;
258
+ recordedTimings?: RecordedTimings;
259
+ replaySpeed?: number;
245
260
  chaos?: ChaosConfig;
246
261
  metadata?: {
247
262
  systemHash?: string;
@@ -295,6 +310,7 @@ interface FixtureFileEntry {
295
310
  turnIndex?: number;
296
311
  hasToolResult?: boolean;
297
312
  endpoint?: "chat" | "image" | "speech" | "transcription" | "translation" | "video" | "embedding" | "audio-gen" | "elevenlabs-tts" | "fal-audio" | "fal" | "realtime" | "realtime-transcription" | "realtime-translation";
313
+ context?: string;
298
314
  };
299
315
  response: FixtureFileResponse;
300
316
  latency?: number;
@@ -302,6 +318,8 @@ interface FixtureFileEntry {
302
318
  truncateAfterChunks?: number;
303
319
  disconnectAfterMs?: number;
304
320
  streamingProfile?: StreamingProfile;
321
+ recordedTimings?: RecordedTimings;
322
+ replaySpeed?: number;
305
323
  chaos?: ChaosConfig;
306
324
  metadata?: {
307
325
  systemHash?: string;
@@ -439,6 +457,7 @@ interface MockServerOptions {
439
457
  host?: string;
440
458
  latency?: number;
441
459
  chunkSize?: number;
460
+ replaySpeed?: number;
442
461
  /** Log verbosity. CLI default is "info"; programmatic default (when omitted) is "silent". */
443
462
  logLevel?: "silent" | "warn" | "info" | "debug";
444
463
  chaos?: ChaosConfig;
@@ -513,6 +532,7 @@ interface FalQueueConfig {
513
532
  interface HandlerDefaults {
514
533
  latency: number;
515
534
  chunkSize: number;
535
+ replaySpeed: number;
516
536
  logger: Logger;
517
537
  chaos?: ChaosConfig;
518
538
  registry?: MetricsRegistry;
@@ -523,5 +543,5 @@ interface HandlerDefaults {
523
543
  }
524
544
  //# sourceMappingURL=types.d.ts.map
525
545
  //#endregion
526
- export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
546
+ export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, ContentWithToolCallsResponse, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileContentWithToolCallsResponse, FixtureFileEntry, FixtureFileResponse, FixtureFileTextResponse, FixtureFileToolCall, FixtureFileToolCallResponse, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RawJSONResponse, RecordConfig, RecordProviderKey, RecordedTimings, ResponseFactory, ResponseOverrides, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
527
547
  //# sourceMappingURL=types.d.ts.map
@@ -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":";;;;;;;UAQiB,SAAA;qBAER,MAAA,CAAK,sBACL,MAAA,CAAK,mCAET;EALY,aAAS,EAAA,MAAA,EAMD,GAAA,CAAI,MANH,EAAA,IAAA,EAMiB,MANjB,EAAA,QAAA,EAAA,MAAA,CAAA,EAM4C,OAN5C,CAAA,OAAA,CAAA;EAAA,MAAA,GAAA,EAAA;IAEjB,MAAK,EAAA,MAAA;IACL,CAAA,GAAA,EAAK,MAAA,CAAA,EAAA,OAAA;;YAGe,EAAA,OAAA,EAEN,OAFM,CAAA,EAAA,IAAA;YAAc,EAAA,GAAA,EAAA,MAAA,CAAA,EAAA,IAAA;aAA2B,EAAA,QAAA,EAI7C,eAJ6C,CAAA,EAAA,IAAA;;AAI7C,UAGR,WAAA,CAHQ;EAAe,IAAA,EAAA,MAAA;EAGvB,IAAA,CAAA,EAAA,MAAA;EAMA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAW,OAAA;;AAER,UAFH,WAAA,CAEG;MAEL,EAAA,QAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;EAAe,OAAA,EAAA,MAAA,GAFV,WAEU,EAAA,GAAA,IAAA;EAIb,IAAA,CAAA,EAAA,MAAA;EAMA,UAAA,CAAA,EAVF,eAUuB,EAAA;EAAA,YAAA,CAAA,EAAA,MAAA;;AAO5B,UAbO,eAAA,CAaP;EAAc,EAAA,EAAA,MAAA;EAYP,IAAA,EAAA,UAAA;EAOA,QAAA,EAAA;IAAY,IAAA,EAAA,MAAA;IACJ,SAAA,EAAA,MAAA;;;AAmBN,UA9CF,qBAAA,CA8CE;OAEC,EAAA,MAAA;EAAqB,QAAA,EA9C7B,WA8C6B,EAAA;EAwCxB,MAAA,CAAA,EAAA,OAAA;EAmBA,cAAA,CAAa,EAAA;IAMb,aAAQ,CAAA,EAAA,OAAA;IAMR,CAAA,GAAA,EAAA,MAAA,CAAA,EAAiB,OAAA;EAAA,CAAA;aACrB,CAAA,EAAA,MAAA;YAD6B,CAAA,EAAA,MAAA;EAAiB,KAAA,CAAA,EAhHjD,cAgHiD,EAAA;EAK1C,WAAA,CAAA,EAAA,MAAA,GAAA,MAAA;EAA6B,eAAA,CAAA,EAAA;IAEjC,IAAA,EAAA,MAAA;IAFyC,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAAiB,CAAA;EAOtD;EAOA,cAAA,CAAA,EAAA,MAAiB;EAIjB;EAMA,aAAA,CAAA,EAAa,MAAA;EAAA;UACpB,CAAA,EAAA,MAAA;MACC,EAAA,MAAA,CAAA,EAAA,OAAA;;AAGM,UAtIA,cAAA,CAsIa;EAKb,IAAA,EAAA,UAAA;EAAqB,QAAA,EAAA;IAK1B,IAAA,EAAA,MAAA;IACG,WAAA,CAAA,EAAA,MAAA;IAAK,UAAA,CAAA,EAAA,MAAA;EAIH,CAAA;AAajB;AAKY,UAhKK,YAAA,CAgKU;EAAA,WAAA,CAAA,EAAA,MAAA,GA/JF,MA+JE;;;;;;;;;;;;AAwC3B;AAWA;AAeA;EAMY,aAAA,CAAW,EAAA,MAAA,GAAA,MAAA,EAAA,GAxNe,MAwNf;EAIX,SAAA,CAAA,EAAA,MAAe,GA3NJ,MA2NI;EAAA,UAAA,CAAA,EAAA,MAAA;UACpB,CAAA,EAAA,MAAA;OACF,CAAA,EAAA,MAAA,GA1Nc,MA0Nd;gBAA0B,CAAA,EAAA,MAAA;WAAR,CAAA,EAAA,CAAA,GAAA,EAxNH,qBAwNG,EAAA,GAAA,OAAA;EAAO;EAIb,aAAO,CAAA,EAAA,MAAA;EAAA,SAAA,CAAA,EAAA,MAAA;eACf,CAAA,EAAA,OAAA;UACG,CAAA,EAAA,MAAA,GAAA,OAAA,GAAA,QAAA,GAAA,eAAA,GAAA,aAAA,GAAA,OAAA,GAAA,WAAA,GAAA,WAAA,GAAA,gBAAA,GAAA,WAAA,GAAA,KAAA,GAAA,UAAA,GAAA,wBAAA,GAAA,sBAAA;SAAkB,CAAA,EAAA,MAAA;;;;;AAe9B;;;;;AACA;;;;;AASA;AAOA;AAA6C,UAtN5B,iBAAA,CAsN4B;KAChC,EAAA,MAAA;SADwC,CAAA,EAAA,MAAA;EAAiB,KAAA,CAAA,EAAA,MAAA;EAKrD,KAAA,CAAA,EAAA;IAAwB,aAAA,CAAA,EAAA,MAAA;IAErB,iBAAA,CAAA,EAAA,MAAA;IAF6B,YAAA,CAAA,EAAA,MAAA;IAAiB,YAAA,CAAA,EAAA,MAAA;IAOjD,aAAA,CAAA,EAAA,MAAA;IAAwC,gBAAA,CAAA,EAAA,MAAA;IAErC,oBAAA,CAAA,EAAA,MAAA;IACP,eAAA,CAAA,EAAA,MAAA;;EAHqE,iBAAA,CAAA,EAAA,MAAA;EAQtE,YAAA,CAAA,EAAA,MAAA;EAAmB,IAAA,CAAA,EAAA,MAAA;;AAE3B,UAzNa,YAAA,SAAqB,iBAyNlC,CAAA;SACA,EAAA,MAAA;WACA,CAAA,EAAA,MAAA;aACA,CAAA,EAAA,MAAA,EAAA;;AAEA,UAxNa,QAAA,CAwNb;MACA,EAAA,MAAA;WACA,EAAA,MAAA;KACA,EAAA,MAAA;;AAEa,UAvNA,gBAAA,SAAyB,iBAwNd,CAAA;EAGX,SAAA,EA1NJ,QA0NoB,EAAA;EAAA,WAAA,CAAA,EAAA,MAAA,EAAA;;AAwCZ,UA9PJ,4BAAA,SAAqC,iBA8PjC,CAAA;SACD,EAAA,MAAA;WAEV,EA/PG,QA+PH,EAAA;EAAW,SAAA,CAAA,EAAA,MAAA;EASJ,WAAA,CAAA,EAAA,MAAY,EAAA;;AAKlB,UAxQM,aAAA,CAwQN;OACH,EAAA;IAIK,OAAA,EAAA,MAAA;IAUK,IAAA,CAAA,EAAA,MAAA;IAAW,KAAA,CAAA,EAAA,MAAA,GAAA,IAAA;IAQZ,IAAA,CAAA,EAAQ,MAAA;EAUR,CAAA;EAOA,MAAA,CAAA,EAAA,MAAQ;EAOR;EASA,UAAA,CAAA,EAAA,MAAc;AAU/B;AAOiB,UA1UA,iBAAA,CA0UqB;EAU1B,SAAA,EAAA,MAAA,EAAA;AAaZ;AAA6B,UA7VZ,SAAA,CA6VY;KACD,CAAA,EAAA,MAAA;SAAP,CAAA,EAAA,MAAA;eAAR,CAAA,EAAA,MAAA;;AAgBU,UAxWN,aAAA,CAwWM;EAkBN,KAAA,CAAA,EAzXP,SAyXO;EAOA,MAAA,CAAA,EA/XN,SA+XM,EAAiB;;AAQxB,UApYO,aAAA,CAoYP;OAMC,EAAA,MAAA,GAAA;IAkCgB,OAAA,EAAA,MAAA;IAA0B,WAAA,CAAA,EAAA,MAAA;;EAW1B,MAAA,CAAA,EAAA,MAAA;AAG3B;AAqBiB,UA1cA,qBAAA,CA0ce;EAAA,aAAA,EAAA;IAItB,IAAA,EAAA,MAAA;IACA,QAAA,CAAA,EAAA,MAAA;IACG,QAAA,CAAA,EAAA,MAAA;IACF,KAAA,CAAA,EA5cC,KA4cD,CAAA;MAEgB,IAAA,EAAA,MAAA;MAA0B,KAAA,EAAA,MAAA;MACxC,GAAA,EAAA,MAAA;IAAc,CAAA,CAAA;eA9cZ;;;;;;;;UAIE,aAAA;;;;;;;;;;;;UAaA,eAAA,SAAwB;;;;KAK7B,eAAA,GACR,eACA,mBACA,+BACA,gBACA,oBACA,gBACA,gBACA,wBACA,gBACA;UA8Ba,gBAAA;;;;;;;;;;UAWA,eAAA;;;;;;;;;;;;;;UAeA,WAAA;;;;;KAML,WAAA;KAIA,eAAA,SACL,0BACF,kBAAkB,QAAQ;UAId,OAAA;SACR;YACG,kBAAkB;;;;;qBAKT;oBACD;;UAEV;;;;;;KAOE,WAAA,GAAc,KAAK;KACnB,oBAAA,GAAuB,KAAK;UASvB,mBAAA;;;sBAGK;;;UAIL,2BAAA,SAAoC;aACxC;;;UAII,uBAAA,SAAgC;;oBAE7B;;;;UAKH,uCAAA,SAAgD;;oBAE7C;aACP;;;;KAKD,mBAAA,GACR,0BACA,8BACA,0CACA,gBACA,oBACA,gBACA,gBACA,wBACA,gBACA;UAEa,WAAA;YACL;;UAGK,gBAAA;;;;;;;;;;;;;;;;;;;;YAmCL;;;;;qBAKS;oBACD;;UAEV;;;;;;UASO,YAAA;;;;;WAKN;QACH;;;;aAIK;;;;;;;;;;kBAUK;;;;;UAQD,QAAA;;;;;WAKN;;;;;;;;UAKM,SAAA;;SAER;;;;UAKQ,QAAA;;;;eAIF;;UAGE,gBAAA;;;;;;;;;UASA,cAAA;;;;;WAKN;;;;;;;;UAKM,oBAAA;;WAEN;;;;UAKM,qBAAA;;;;;eAKF;;KAKH,iBAAA;UAaK,YAAA;aACJ,QAAQ,OAAO;;;;;;;;;;;;;;;;QAgBpB;;;;;;;;;;;;;;;;;UAkBS,eAAA;;;;;;UAOA,iBAAA;;;;;;;;UAQP;;;;;;WAMC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAkCgB,0BAA0B;;;;;;;;;;;aAWxC;;UAGI,cAAA;;;;;;;;;;;;;;;;UAqBA,eAAA;;;;UAIP;UACA;aACG;WACF;;2BAEgB,0BAA0B;aACxC"}
package/dist/video.cjs CHANGED
@@ -115,7 +115,8 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
115
115
  role: "user",
116
116
  content: videoReq.prompt
117
117
  }],
118
- _endpointType: "video"
118
+ _endpointType: "video",
119
+ _context: require_helpers.getContext(req)
119
120
  };
120
121
  const testId = require_helpers.getTestId(req);
121
122
  const fixture = require_router.matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
@@ -1 +1 @@
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 retryAfter: response.retryAfter,\n });\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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"}
1
+ {"version":3,"file":"video.cjs","names":["flattenHeaders","getContext","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 getContext,\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 _context: getContext(req),\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 retryAfter: response.retryAfter,\n });\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":";;;;;;;AA2BA,MAAM,0BAA0B;AAChC,MAAM,qBAAqB;;;;;;;AAa3B,IAAa,gBAAb,MAA2B;CACzB,AAAiB,0BAAU,IAAI,KAA8B;CAC7D,AAAiB;CAEjB,cAAc;AAEZ,OAAK,aAAa,kBAAkB;GAClC,MAAM,MAAM,KAAK,KAAK;AACtB,QAAK,MAAM,CAAC,KAAK,UAAU,KAAK,QAC9B,KAAI,MAAM,MAAM,YAAY,mBAC1B,MAAK,QAAQ,OAAO,IAAI;KAG3B,IAAO;AAEV,MAAI,KAAK,WAAW,MAClB,MAAK,WAAW,OAAO;;CAI3B,SAAS,KAAmF;EAC1F,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI;AACnC,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,KAAK,KAAK,GAAG,MAAM,YAAY,oBAAoB;AACrD,QAAK,QAAQ,OAAO,IAAI;AACxB;;AAEF,SAAO;GAAE,OAAO,MAAM;GAAO,eAAe,KAAK,MAAM,MAAM,YAAY,IAAK;GAAE;;CAGlF,iBAAiB,KAAiC;AAEhD,SADU,KAAK,SAAS,IAAI,EAClB;;CAGZ,IAAI,KAAa,OAAqC;AACpD,OAAK,QAAQ,IAAI,KAAK;GAAE;GAAO,WAAW,KAAK,KAAK;GAAE,CAAC;AAEvD,MAAI,KAAK,QAAQ,OAAO,yBAAyB;GAC/C,MAAM,SAAS,KAAK,QAAQ,OAAO;GACnC,MAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;IAC/B,MAAM,OAAO,KAAK,MAAM;AACxB,QAAI,CAAC,KAAK,KAAM,MAAK,QAAQ,OAAO,KAAK,MAAM;;;;CAKrD,OAAO,KAAsB;AAC3B,SAAO,KAAK,QAAQ,OAAO,IAAI;;CAGjC,QAAc;AACZ,OAAK,QAAQ,OAAO;;CAGtB,UAAgB;AACd,gBAAc,KAAK,WAAW;AAC9B,OAAK,QAAQ,OAAO;;CAGtB,IAAI,OAAe;AACjB,SAAO,KAAK,QAAQ;;;AAIxB,eAAsB,kBACpB,KACA,KACA,KACA,UACA,SACA,UACA,gBACA,aACe;AACf,gBAAe,IAAI;CACnB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,SAAS,IAAI,UAAU;CAE7B,IAAI;AACJ,KAAI;AACF,aAAW,KAAK,MAAM,IAAI;UACnB,UAAU;EACjB,MAAM,SAAS,oBAAoB,QAAQ,SAAS,UAAU;AAC9D,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS,mBAAmB;GAC5B,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;AAGF,KAAI,CAAC,SAAS,QAAQ;AACpB,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GAAE,SAAS;GAAwC,MAAM;GAAyB,EAC1F,CAAC,CACH;AACD;;CAGF,MAAM,eAAsC;EAC1C,OAAO,SAAS,SAAS;EACzB,UAAU,CAAC;GAAE,MAAM;GAAQ,SAAS,SAAS;GAAQ,CAAC;EACtD,eAAe;EACf,UAAUC,2BAAW,IAAI;EAC1B;CAED,MAAM,SAASC,0BAAU,IAAI;CAC7B,MAAM,UAAUC,4BACd,UACA,cACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,iBACV;AAED,KAAI,SAAS;AACX,UAAQ,2BAA2B,SAAS,UAAU,OAAO;AAC7D,WAAS,OAAO,MAAM,oBAAoB,KAAK,UAAU,QAAQ,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG;OAExF,UAAS,OAAO,MAAM,iCAAiC;AAGzD,KACEC,yBACE,KACA,SACA,SAAS,OACT,IAAI,SACJ,SACA;EAAE;EAAQ;EAAM,SAASJ,+BAAe,IAAI,QAAQ;EAAE,MAAM;EAAc,EAC1E,UAAU,YAAY,SACtB,SAAS,UACT,SAAS,OACV,CAED;AAEF,KAAI,CAAC,SAAS;AAEZ,MADwBK,kCAAkB,SAAS,QAAQ,IAAI,QAAQ,EAClD;AACnB,WAAQ,IAAI;IACV;IACA;IACA,SAASL,+BAAe,IAAI,QAAQ;IACpC,MAAM;IACN,UAAU;KACR,QAAQ;KACR,SAAS;KACT,GAAGM,oCAAoB,SAAS,QAAQ,IAAI,QAAQ;KACrD;IACF,CAAC;AACF,yCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;IACL,SAAS;IACT,MAAM;IACN,MAAM;IACP,EACF,CAAC,CACH;AACD;;AAEF,MAAI,SAAS,QAAQ;GACnB,MAAM,UAAU,MAAMC,gCACpB,KACA,KACA,cACA,UACA,IAAI,OAAO,cACX,UACA,UACA,IACD;AACD,OAAI,YAAY,kBAAmB;AACnC,OAAI,YAAY,kBAAkB;AAChC,YAAQ,IAAI;KACV;KACA;KACA,SAASP,+BAAe,IAAI,QAAQ;KACpC,MAAM;KACN,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM,QAAQ;MAAS;KAC5E,CAAC;AACF;;;AAIJ,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IACR,QAAQ;IACR,SAAS;IACT,GAAGM,oCAAoB,SAAS,QAAQ,IAAI,QAAQ;IACrD;GACF,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GACL,SAAS;GACT,MAAM;GACN,MAAM;GACP,EACF,CAAC,CACH;AACD;;CAGF,MAAM,WAAW,MAAME,gCAAgB,SAAS,aAAa;AAE7D,KAAIC,gCAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV;GACA;GACA,SAAST,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,wCAAmB,KAAK,QAAQU,uCAAuB,SAAS,EAAE,EAChE,YAAY,SAAS,YACtB,CAAC;AACF;;AAGF,KAAI,CAACC,gCAAgB,SAAS,EAAE;AAC9B,UAAQ,IAAI;GACV;GACA;GACA,SAASX,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK;IAAS;GACnC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EACb,OAAO;GAAE,SAAS;GAAwC,MAAM;GAAgB,EACjF,CAAC,CACH;AACD;;AAGF,SAAQ,IAAI;EACV;EACA;EACA,SAASA,+BAAe,IAAI,QAAQ;EACpC,MAAM;EACN,UAAU;GAAE,QAAQ;GAAK;GAAS;EACnC,CAAC;CAEF,MAAM,QAAQ,SAAS;CAGvB,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM;AACpC,aAAY,IAAI,UAAU,MAAM;CAChC,MAAM,aAAa,YAAY,iBAAiB,SAAS;AAEzD,KAAI,MAAM,WAAW,aAAa;AAChC,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU;GAAE,IAAI,MAAM;GAAI,QAAQ,MAAM;GAAQ,KAAK,MAAM;GAAK;GAAY,CAAC,CAAC;QACtF;AACL,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU;GAAE,IAAI,MAAM;GAAI,QAAQ,MAAM;GAAQ;GAAY,CAAC,CAAC;;;AAI/E,SAAgB,kBACd,KACA,KACA,SACA,SACA,UACA,gBACA,aACM;AACN,gBAAe,IAAI;CACnB,MAAM,OAAO,IAAI,OAAO,cAAc;CACtC,MAAM,SAAS,IAAI,UAAU;AAE7B,KACEI,yBACE,KACA,MACA,SAAS,OACT,IAAI,SACJ,SACA;EAAE;EAAQ;EAAM,SAASJ,+BAAe,IAAI,QAAQ;EAAE,MAAM;EAAM,EAClE,YACA,SAAS,UACT,SAAS,OACV,CAED;CAGF,MAAM,WAAW,GADFE,0BAAU,IAAI,CACF,GAAG;CAC9B,MAAM,QAAQ,YAAY,SAAS,SAAS;AAE5C,KAAI,CAAC,OAAO;AACV,UAAQ,IAAI;GACV;GACA;GACA,SAASF,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAK,SAAS;IAAM;GACzC,CAAC;AACF,wCACE,KACA,KACA,KAAK,UAAU,EAAE,OAAO;GAAE,SAAS,SAAS,QAAQ;GAAa,MAAM;GAAa,EAAE,CAAC,CACxF;AACD;;CAGF,MAAM,EAAE,OAAO,eAAe,eAAe;AAE7C,SAAQ,IAAI;EACV;EACA;EACA,SAASA,+BAAe,IAAI,QAAQ;EACpC,MAAM;EACN,UAAU;GAAE,QAAQ;GAAK,SAAS;GAAM;EACzC,CAAC;CAEF,MAAM,OAAgC;EACpC,IAAI,MAAM;EACV,QAAQ,MAAM;EACd;EACD;AACD,KAAI,MAAM,IAAK,MAAK,MAAM,MAAM;AAEhC,KAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,KAAI,IAAI,KAAK,UAAU,KAAK,CAAC"}
@@ -1 +1 @@
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;EA4NM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBAvOe,iBAAA,CAuOV,GAAA,EAtOL,MAAA,CAAK,eAsOA,EAAA,GAAA,EArOL,MAAA,CAAK,cAqOA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAnOA,OAmOA,EAAA,EAAA,OAAA,EAlOD,OAkOC,EAAA,QAAA,EAjOA,eAiOA,EAAA,cAAA,EAAA,CAAA,GAAA,EAhOY,MAAA,CAAK,cAgOjB,EAAA,GAAA,IAAA,EAAA,WAAA,EA/NG,aA+NH,CAAA,EA9NT,OA8NS,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"}
1
+ {"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAyCA;;;;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;EA6NM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBAxOe,iBAAA,CAwOV,GAAA,EAvOL,MAAA,CAAK,eAuOA,EAAA,GAAA,EAtOL,MAAA,CAAK,cAsOA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EApOA,OAoOA,EAAA,EAAA,OAAA,EAnOD,OAmOC,EAAA,QAAA,EAlOA,eAkOA,EAAA,cAAA,EAAA,CAAA,GAAA,EAjOY,MAAA,CAAK,cAiOjB,EAAA,GAAA,IAAA,EAAA,WAAA,EAhOG,aAgOH,CAAA,EA/NT,OA+NS,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"}
@@ -1 +1 @@
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;EA4NM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBAvOe,iBAAA,CAuOV,GAAA,EAtOL,MAAA,CAAK,eAsOA,EAAA,GAAA,EArOL,MAAA,CAAK,cAqOA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAnOA,OAmOA,EAAA,EAAA,OAAA,EAlOD,OAkOC,EAAA,QAAA,EAjOA,eAiOA,EAAA,cAAA,EAAA,CAAA,GAAA,EAhOY,MAAA,CAAK,cAgOjB,EAAA,GAAA,IAAA,EAAA,WAAA,EA/NG,aA+NH,CAAA,EA9NT,OA8NS,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"}
1
+ {"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAyCA;;;;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;EA6NM,OAAA,CAAA,CAAA,EAAA,IAAA;EAAiB,IAAA,IAAA,CAAA,CAAA,EAAA,MAAA;;AAE1B,iBAxOe,iBAAA,CAwOV,GAAA,EAvOL,MAAA,CAAK,eAuOA,EAAA,GAAA,EAtOL,MAAA,CAAK,cAsOA,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EApOA,OAoOA,EAAA,EAAA,OAAA,EAnOD,OAmOC,EAAA,QAAA,EAlOA,eAkOA,EAAA,cAAA,EAAA,CAAA,GAAA,EAjOY,MAAA,CAAK,cAiOjB,EAAA,GAAA,IAAA,EAAA,WAAA,EAhOG,aAgOH,CAAA,EA/NT,OA+NS,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, serializeErrorResponse, strictOverrideField } from "./helpers.js";
1
+ import { flattenHeaders, getContext, 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";
@@ -115,7 +115,8 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
115
115
  role: "user",
116
116
  content: videoReq.prompt
117
117
  }],
118
- _endpointType: "video"
118
+ _endpointType: "video",
119
+ _context: getContext(req)
119
120
  };
120
121
  const testId = getTestId(req);
121
122
  const fixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
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 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 retryAfter: response.retryAfter,\n });\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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"}
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 getContext,\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 _context: getContext(req),\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 retryAfter: response.retryAfter,\n });\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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"}
@@ -189,12 +189,15 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
189
189
  } }));
190
190
  return;
191
191
  }
192
+ const geminiContextHeader = defaults.upgradeHeaders?.["x-aimock-context"];
193
+ const geminiContext = typeof geminiContextHeader === "string" ? geminiContextHeader : Array.isArray(geminiContextHeader) && geminiContextHeader.length > 0 ? geminiContextHeader[0] : void 0;
192
194
  const completionReq = {
193
195
  model: session.model,
194
196
  messages: [...session.conversationHistory, ...newMessages],
195
197
  stream: true,
196
198
  tools: session.tools.length > 0 ? session.tools : void 0,
197
- _endpointType: "chat"
199
+ _endpointType: "chat",
200
+ _context: geminiContext
198
201
  };
199
202
  const testId = defaults.testId ?? require_constants.DEFAULT_TEST_ID;
200
203
  const fixture = require_router.matchFixture(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
@@ -307,12 +310,15 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
307
310
  const chunkList = [];
308
311
  for (let i = 0; i < content.length; i += chunkSize) chunkList.push(content.slice(i, i + chunkSize));
309
312
  const interruption = require_interruption.createInterruptionSignal(fixture);
313
+ const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
314
+ const { recordedTimings } = fixture;
310
315
  let interrupted = false;
311
316
  if (content.length === 0) {
312
317
  if (!ws.isClosed) ws.send(JSON.stringify({ serverContent: { modelTurn: { parts: [{ text: "" }] } } }));
313
318
  } else for (let i = 0; i < chunkList.length; i++) {
314
319
  if (ws.isClosed) break;
315
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
320
+ const chunkDelay = require_sse_writer.calculateDelay(i, void 0, latency, recordedTimings, replaySpeed);
321
+ if (chunkDelay > 0) await require_sse_writer.delay(chunkDelay, interruption?.signal);
316
322
  if (interruption?.signal.aborted) {
317
323
  interrupted = true;
318
324
  break;
@@ -337,7 +343,8 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
337
343
  resolvedId: tc.id ?? require_helpers.generateToolCallId()
338
344
  }));
339
345
  if (!ws.isClosed) {
340
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
346
+ const tcDelay = require_sse_writer.calculateDelay(chunkList.length, void 0, latency, recordedTimings, replaySpeed);
347
+ if (tcDelay > 0) await require_sse_writer.delay(tcDelay, interruption?.signal);
341
348
  if (interruption?.signal.aborted) {
342
349
  ws.destroy();
343
350
  journalEntry.response.interrupted = true;
@@ -406,10 +413,13 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
406
413
  const chunks = [];
407
414
  for (let i = 0; i < content.length; i += chunkSize) chunks.push(content.slice(i, i + chunkSize));
408
415
  const interruption = require_interruption.createInterruptionSignal(fixture);
416
+ const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
417
+ const { recordedTimings } = fixture;
409
418
  let interrupted = false;
410
419
  for (let i = 0; i < chunks.length; i++) {
411
420
  if (ws.isClosed) break;
412
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
421
+ const chunkDelay = require_sse_writer.calculateDelay(i, void 0, latency, recordedTimings, replaySpeed);
422
+ if (chunkDelay > 0) await require_sse_writer.delay(chunkDelay, interruption?.signal);
413
423
  if (interruption?.signal.aborted) {
414
424
  interrupted = true;
415
425
  break;
@@ -449,11 +459,14 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
449
459
  }
450
460
  });
451
461
  const interruption = require_interruption.createInterruptionSignal(fixture);
462
+ const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
463
+ const { recordedTimings } = fixture;
452
464
  if (ws.isClosed) {
453
465
  interruption?.cleanup();
454
466
  return;
455
467
  }
456
- if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
468
+ const tcDelay = require_sse_writer.calculateDelay(0, void 0, latency, recordedTimings, replaySpeed);
469
+ if (tcDelay > 0) await require_sse_writer.delay(tcDelay, interruption?.signal);
457
470
  if (interruption?.signal.aborted) {
458
471
  ws.destroy();
459
472
  journalEntry.response.interrupted = true;