@copilotkit/aimock 1.16.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +15 -0
- package/dist/bedrock-converse.cjs +4 -0
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +4 -0
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +4 -0
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +4 -0
- package/dist/bedrock.js.map +1 -1
- package/dist/cohere.cjs +4 -1
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.js +4 -1
- package/dist/cohere.js.map +1 -1
- package/dist/embeddings.cjs +4 -1
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.js +4 -1
- package/dist/embeddings.js.map +1 -1
- package/dist/gemini.cjs +2 -0
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.js +2 -0
- package/dist/gemini.js.map +1 -1
- package/dist/images.cjs +4 -1
- package/dist/images.cjs.map +1 -1
- package/dist/images.js +4 -1
- package/dist/images.js.map +1 -1
- package/dist/messages.cjs +8 -1
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.js +8 -1
- package/dist/messages.js.map +1 -1
- package/dist/ollama.cjs +8 -2
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +8 -2
- package/dist/ollama.js.map +1 -1
- package/dist/responses.cjs +87 -13
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +87 -13
- package/dist/responses.js.map +1 -1
- package/dist/server.cjs +8 -1
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -1
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +4 -1
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.js +4 -1
- package/dist/speech.js.map +1 -1
- package/dist/transcription.cjs +4 -1
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.js +4 -1
- package/dist/transcription.js.map +1 -1
- package/dist/video.cjs +4 -1
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +4 -1
- package/dist/video.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcription.js","names":[],"sources":["../src/transcription.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport { isTranscriptionResponse, isErrorResponse, flattenHeaders, getTestId } from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n/**\n * Extract a text field from multipart form data using regex.\n * NOTE: This runs against the full body including binary audio data.\n * It works because text metadata fields (model, response_format, etc.)\n * appear before the binary audio part in standard multipart encoding.\n * A proper multipart parser would be more robust but is overkill for\n * the small set of fields we extract.\n */\nfunction extractFormField(raw: string, fieldName: string): string | undefined {\n const pattern = new RegExp(\n `Content-Disposition:\\\\s*form-data;[^\\\\r\\\\n]*name=\"${fieldName}\"[^\\\\r\\\\n]*\\\\r\\\\n\\\\r\\\\n([^\\\\r\\\\n]*)`,\n \"i\",\n );\n const match = raw.match(pattern);\n return match?.[1];\n}\n\nexport async function handleTranscription(\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): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/audio/transcriptions\";\n const method = req.method ?? \"POST\";\n\n const model = extractFormField(raw, \"model\") ?? \"whisper-1\";\n const responseFormat = extractFormField(raw, \"response_format\") ?? \"json\";\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [],\n _endpointType: \"transcription\",\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 }\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 defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const proxied = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/audio/transcriptions\",\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\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: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = fixture.response;\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 (!isTranscriptionResponse(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: {\n message: \"Fixture response is not a transcription type\",\n type: \"server_error\",\n },\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 t = response.transcription;\n const useVerbose = responseFormat === \"verbose_json\" || t.words != null || t.segments != null;\n\n if (useVerbose) {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n task: \"transcribe\",\n language: t.language ?? \"english\",\n duration: t.duration ?? 0,\n text: t.text,\n words: t.words ?? [],\n segments: t.segments ?? [],\n }),\n );\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ text: t.text }));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAS,iBAAiB,KAAa,WAAuC;CAC5E,MAAM,UAAU,IAAI,OAClB,qDAAqD,UAAU,sCAC/D,IACD;AAED,QADc,IAAI,MAAM,QAAQ,GACjB;;AAGjB,eAAsB,oBACpB,KACA,KACA,KACA,UACA,SACA,UACA,gBACe;AACf,gBAAe,IAAI;CACnB,MAAM,OAAO,IAAI,OAAO;CACxB,MAAM,SAAS,IAAI,UAAU;CAE7B,MAAM,QAAQ,iBAAiB,KAAK,QAAQ,IAAI;CAChD,MAAM,iBAAiB,iBAAiB,KAAK,kBAAkB,IAAI;CAEnE,MAAM,eAAsC;EAC1C;EACA,UAAU,EAAE;EACZ,eAAe;EAChB;CAED,MAAM,SAAS,UAAU,IAAI;CAC7B,MAAM,UAAU,aACd,UACA,cACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,iBACV;AAED,KAAI,
|
|
1
|
+
{"version":3,"file":"transcription.js","names":[],"sources":["../src/transcription.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport { isTranscriptionResponse, isErrorResponse, flattenHeaders, getTestId } from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { writeErrorResponse } from \"./sse-writer.js\";\nimport type { Journal } from \"./journal.js\";\nimport { applyChaos } from \"./chaos.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\n\n/**\n * Extract a text field from multipart form data using regex.\n * NOTE: This runs against the full body including binary audio data.\n * It works because text metadata fields (model, response_format, etc.)\n * appear before the binary audio part in standard multipart encoding.\n * A proper multipart parser would be more robust but is overkill for\n * the small set of fields we extract.\n */\nfunction extractFormField(raw: string, fieldName: string): string | undefined {\n const pattern = new RegExp(\n `Content-Disposition:\\\\s*form-data;[^\\\\r\\\\n]*name=\"${fieldName}\"[^\\\\r\\\\n]*\\\\r\\\\n\\\\r\\\\n([^\\\\r\\\\n]*)`,\n \"i\",\n );\n const match = raw.match(pattern);\n return match?.[1];\n}\n\nexport async function handleTranscription(\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): Promise<void> {\n setCorsHeaders(res);\n const path = req.url ?? \"/v1/audio/transcriptions\";\n const method = req.method ?? \"POST\";\n\n const model = extractFormField(raw, \"model\") ?? \"whisper-1\";\n const responseFormat = extractFormField(raw, \"response_format\") ?? \"json\";\n\n const syntheticReq: ChatCompletionRequest = {\n model,\n messages: [],\n _endpointType: \"transcription\",\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 defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const proxied = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/audio/transcriptions\",\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\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: { status: strictStatus, fixture: null },\n });\n writeErrorResponse(\n res,\n strictStatus,\n JSON.stringify({\n error: {\n message: strictMessage,\n type: \"invalid_request_error\",\n code: \"no_fixture_match\",\n },\n }),\n );\n return;\n }\n\n const response = fixture.response;\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 (!isTranscriptionResponse(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: {\n message: \"Fixture response is not a transcription type\",\n type: \"server_error\",\n },\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 t = response.transcription;\n const useVerbose = responseFormat === \"verbose_json\" || t.words != null || t.segments != null;\n\n if (useVerbose) {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n task: \"transcribe\",\n language: t.language ?? \"english\",\n duration: t.duration ?? 0,\n text: t.text,\n words: t.words ?? [],\n segments: t.segments ?? [],\n }),\n );\n } else {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ text: t.text }));\n }\n}\n"],"mappings":"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"}
|
package/dist/video.cjs
CHANGED
|
@@ -100,7 +100,10 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
|
|
|
100
100
|
};
|
|
101
101
|
const testId = require_helpers.getTestId(req);
|
|
102
102
|
const fixture = require_router.matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
103
|
-
if (fixture)
|
|
103
|
+
if (fixture) {
|
|
104
|
+
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
105
|
+
defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
106
|
+
} else defaults.logger.debug(`No fixture matched for request`);
|
|
104
107
|
if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
|
|
105
108
|
method,
|
|
106
109
|
path,
|
package/dist/video.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.cjs","names":["flattenHeaders","getTestId","matchFixture","applyChaos","proxyAndRecord","isErrorResponse","isVideoResponse"],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport { isVideoResponse, isErrorResponse, flattenHeaders, getTestId } 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 {\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: \"Malformed JSON\", type: \"invalid_request_error\", code: \"invalid_json\" },\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 }\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 defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const proxied = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\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: { status: strictStatus, fixture: null },\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 = fixture.response;\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 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 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","proxyAndRecord","isErrorResponse","isVideoResponse"],"sources":["../src/video.ts"],"sourcesContent":["import type * as http from \"node:http\";\nimport type { ChatCompletionRequest, Fixture, HandlerDefaults, VideoResponse } from \"./types.js\";\nimport { isVideoResponse, isErrorResponse, flattenHeaders, getTestId } 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 {\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: \"Malformed JSON\", type: \"invalid_request_error\", code: \"invalid_json\" },\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 defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const proxied = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\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: { status: strictStatus, fixture: null },\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 = fixture.response;\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 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 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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"}
|
package/dist/video.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAK,MAAA,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,IAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,IAAA,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,IAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,
|
|
1
|
+
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAK,MAAA,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,IAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,IAAA,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,IAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,iBAsLC,iBAAA,CAtLD,GAAA,EAuLR,IAAA,CAAK,eAvLG,EAAA,GAAA,EAwLR,IAAA,CAAK,cAxLG,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EA0LJ,OA1LI,EAAA,cAAA,EAAA,CAAA,GAAA,EA2LS,IAAA,CAAK,cA3Ld,EAAA,GAAA,IAAA,EAAA,WAAA,EA4LA,aA5LA,CAAA,EAAA,IAAA"}
|
package/dist/video.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAK,MAAA,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,IAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,IAAA,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,IAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,
|
|
1
|
+
{"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAK,MAAA,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,IAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,IAAA,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,IAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,iBAsLC,iBAAA,CAtLD,GAAA,EAuLR,IAAA,CAAK,eAvLG,EAAA,GAAA,EAwLR,IAAA,CAAK,cAxLG,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EA0LJ,OA1LI,EAAA,cAAA,EAAA,CAAA,GAAA,EA2LS,IAAA,CAAK,cA3Ld,EAAA,GAAA,IAAA,EAAA,WAAA,EA4LA,aA5LA,CAAA,EAAA,IAAA"}
|
package/dist/video.js
CHANGED
|
@@ -100,7 +100,10 @@ async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, set
|
|
|
100
100
|
};
|
|
101
101
|
const testId = getTestId(req);
|
|
102
102
|
const fixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
103
|
-
if (fixture)
|
|
103
|
+
if (fixture) {
|
|
104
|
+
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
105
|
+
defaults.logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
|
|
106
|
+
} else defaults.logger.debug(`No fixture matched for request`);
|
|
104
107
|
if (applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
|
|
105
108
|
method,
|
|
106
109
|
path,
|
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 { isVideoResponse, isErrorResponse, flattenHeaders, getTestId } 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 {\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: \"Malformed JSON\", type: \"invalid_request_error\", code: \"invalid_json\" },\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 }\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 defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const proxied = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\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: { status: strictStatus, fixture: null },\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 = fixture.response;\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 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 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 { isVideoResponse, isErrorResponse, flattenHeaders, getTestId } 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 {\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: \"Malformed JSON\", type: \"invalid_request_error\", code: \"invalid_json\" },\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 defaults.registry,\n defaults.logger,\n )\n )\n return;\n\n if (!fixture) {\n if (defaults.record) {\n const proxied = await proxyAndRecord(\n req,\n res,\n syntheticReq,\n \"openai\",\n req.url ?? \"/v1/videos\",\n fixtures,\n defaults,\n raw,\n );\n if (proxied) {\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 strictStatus = defaults.strict ? 503 : 404;\n const strictMessage = defaults.strict\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: { status: strictStatus, fixture: null },\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 = fixture.response;\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 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 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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/aimock",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "Mock infrastructure for AI application testing — LLM APIs, image generation, text-to-speech, transcription, video generation, MCP tools, A2A agents, AG-UI event streams, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|