@copilotkit/aimock 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +4 -2
- package/dist/a2a-types.d.cts.map +1 -1
- package/dist/a2a-types.d.ts.map +1 -1
- package/dist/agui-handler.cjs +340 -0
- package/dist/agui-handler.cjs.map +1 -0
- package/dist/agui-handler.d.cts +96 -0
- package/dist/agui-handler.d.cts.map +1 -0
- package/dist/agui-handler.d.ts +96 -0
- package/dist/agui-handler.d.ts.map +1 -0
- package/dist/agui-handler.js +326 -0
- package/dist/agui-handler.js.map +1 -0
- package/dist/agui-mock.cjs +190 -0
- package/dist/agui-mock.cjs.map +1 -0
- package/dist/agui-mock.d.cts +50 -0
- package/dist/agui-mock.d.cts.map +1 -0
- package/dist/agui-mock.d.ts +50 -0
- package/dist/agui-mock.d.ts.map +1 -0
- package/dist/agui-mock.js +188 -0
- package/dist/agui-mock.js.map +1 -0
- package/dist/agui-recorder.cjs +153 -0
- package/dist/agui-recorder.cjs.map +1 -0
- package/dist/agui-recorder.d.cts +19 -0
- package/dist/agui-recorder.d.cts.map +1 -0
- package/dist/agui-recorder.d.ts +19 -0
- package/dist/agui-recorder.d.ts.map +1 -0
- package/dist/agui-recorder.js +147 -0
- package/dist/agui-recorder.js.map +1 -0
- package/dist/agui-types.d.cts +231 -0
- package/dist/agui-types.d.cts.map +1 -0
- package/dist/agui-types.d.ts +231 -0
- package/dist/agui-types.d.ts.map +1 -0
- package/dist/bedrock-converse.cjs +2 -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 +2 -0
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +2 -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 +2 -0
- package/dist/bedrock.js.map +1 -1
- package/dist/cli.cjs +32 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +32 -1
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +1 -0
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.js +1 -0
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.cjs +19 -0
- package/dist/config-loader.cjs.map +1 -1
- package/dist/config-loader.d.cts +16 -0
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +16 -0
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +19 -0
- package/dist/config-loader.js.map +1 -1
- package/dist/embeddings.cjs +2 -1
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.js +2 -1
- package/dist/embeddings.js.map +1 -1
- package/dist/gemini.cjs +1 -0
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.js +1 -0
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +16 -0
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +6 -2
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +6 -2
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +13 -1
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +166 -0
- package/dist/images.cjs.map +1 -0
- package/dist/images.d.cts +11 -0
- package/dist/images.d.cts.map +1 -0
- package/dist/images.d.ts +11 -0
- package/dist/images.d.ts.map +1 -0
- package/dist/images.js +166 -0
- package/dist/images.js.map +1 -0
- package/dist/index.cjs +32 -0
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +9 -2
- package/dist/llmock.cjs +37 -1
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +5 -1
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +5 -1
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +37 -1
- package/dist/llmock.js.map +1 -1
- package/dist/messages.cjs +1 -0
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.js +1 -0
- package/dist/messages.js.map +1 -1
- package/dist/ollama.cjs +2 -0
- 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 +2 -0
- package/dist/ollama.js.map +1 -1
- package/dist/recorder.cjs +50 -7
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.js +50 -7
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +1 -0
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.js +1 -0
- package/dist/responses.js.map +1 -1
- package/dist/router.cjs +8 -0
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +9 -0
- package/dist/router.js.map +1 -1
- package/dist/server.cjs +80 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -0
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +80 -3
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +144 -0
- package/dist/speech.cjs.map +1 -0
- package/dist/speech.d.cts +11 -0
- package/dist/speech.d.cts.map +1 -0
- package/dist/speech.d.ts +11 -0
- package/dist/speech.d.ts.map +1 -0
- package/dist/speech.js +144 -0
- package/dist/speech.js.map +1 -0
- package/dist/suite.cjs +8 -0
- package/dist/suite.cjs.map +1 -1
- package/dist/suite.d.cts +4 -0
- package/dist/suite.d.cts.map +1 -1
- package/dist/suite.d.ts +4 -0
- package/dist/suite.d.ts.map +1 -1
- package/dist/suite.js +8 -0
- package/dist/suite.js.map +1 -1
- package/dist/transcription.cjs +134 -0
- package/dist/transcription.cjs.map +1 -0
- package/dist/transcription.d.cts +11 -0
- package/dist/transcription.d.cts.map +1 -0
- package/dist/transcription.d.ts +11 -0
- package/dist/transcription.d.ts.map +1 -0
- package/dist/transcription.js +134 -0
- package/dist/transcription.js.map +1 -0
- package/dist/types.d.cts +44 -2
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +44 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/video.cjs +196 -0
- package/dist/video.cjs.map +1 -0
- package/dist/video.d.cts +14 -0
- package/dist/video.d.cts.map +1 -0
- package/dist/video.d.ts +14 -0
- package/dist/video.d.ts.map +1 -0
- package/dist/video.js +195 -0
- package/dist/video.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcription.cjs","names":["getTestId","matchFixture","applyChaos","flattenHeaders","proxyAndRecord","isErrorResponse","isTranscriptionResponse"],"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 named field value from a multipart/form-data body.\n * Lightweight parser — scans for Content-Disposition headers\n * to find simple string field values.\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 },\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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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Journal } from "./journal.cjs";
|
|
2
|
+
import { Fixture, HandlerDefaults } from "./types.cjs";
|
|
3
|
+
import * as http from "node:http";
|
|
4
|
+
|
|
5
|
+
//#region src/transcription.d.ts
|
|
6
|
+
declare function handleTranscription(req: http.IncomingMessage, res: http.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http.ServerResponse) => void): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=transcription.d.ts.map
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { handleTranscription };
|
|
11
|
+
//# sourceMappingURL=transcription.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcription.d.cts","names":[],"sources":["../src/transcription.ts"],"sourcesContent":[],"mappings":";;;;;iBAuBsB,mBAAA,MACf,IAAA,CAAK,sBACL,IAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,IAAA,CAAK,0BAC1B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Journal } from "./journal.js";
|
|
2
|
+
import { Fixture, HandlerDefaults } from "./types.js";
|
|
3
|
+
import * as http from "node:http";
|
|
4
|
+
|
|
5
|
+
//#region src/transcription.d.ts
|
|
6
|
+
declare function handleTranscription(req: http.IncomingMessage, res: http.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http.ServerResponse) => void): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=transcription.d.ts.map
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { handleTranscription };
|
|
11
|
+
//# sourceMappingURL=transcription.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcription.d.ts","names":[],"sources":["../src/transcription.ts"],"sourcesContent":[],"mappings":";;;;;iBAuBsB,mBAAA,MACf,IAAA,CAAK,sBACL,IAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,IAAA,CAAK,0BAC1B"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { flattenHeaders, getTestId, isErrorResponse, isTranscriptionResponse } from "./helpers.js";
|
|
2
|
+
import { matchFixture } from "./router.js";
|
|
3
|
+
import { writeErrorResponse } from "./sse-writer.js";
|
|
4
|
+
import { applyChaos } from "./chaos.js";
|
|
5
|
+
import { proxyAndRecord } from "./recorder.js";
|
|
6
|
+
|
|
7
|
+
//#region src/transcription.ts
|
|
8
|
+
/**
|
|
9
|
+
* Extract a named field value from a multipart/form-data body.
|
|
10
|
+
* Lightweight parser — scans for Content-Disposition headers
|
|
11
|
+
* to find simple string field values.
|
|
12
|
+
*/
|
|
13
|
+
function extractFormField(raw, fieldName) {
|
|
14
|
+
const pattern = new RegExp(`Content-Disposition:\\s*form-data;[^\\r\\n]*name="${fieldName}"[^\\r\\n]*\\r\\n\\r\\n([^\\r\\n]*)`, "i");
|
|
15
|
+
return raw.match(pattern)?.[1];
|
|
16
|
+
}
|
|
17
|
+
async function handleTranscription(req, res, raw, fixtures, journal, defaults, setCorsHeaders) {
|
|
18
|
+
setCorsHeaders(res);
|
|
19
|
+
const path = req.url ?? "/v1/audio/transcriptions";
|
|
20
|
+
const method = req.method ?? "POST";
|
|
21
|
+
const model = extractFormField(raw, "model") ?? "whisper-1";
|
|
22
|
+
const responseFormat = extractFormField(raw, "response_format") ?? "json";
|
|
23
|
+
const syntheticReq = {
|
|
24
|
+
model,
|
|
25
|
+
messages: [],
|
|
26
|
+
_endpointType: "transcription"
|
|
27
|
+
};
|
|
28
|
+
const testId = getTestId(req);
|
|
29
|
+
const fixture = matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
30
|
+
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
31
|
+
if (applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
|
|
32
|
+
method,
|
|
33
|
+
path,
|
|
34
|
+
headers: flattenHeaders(req.headers),
|
|
35
|
+
body: syntheticReq
|
|
36
|
+
}, defaults.registry, defaults.logger)) return;
|
|
37
|
+
if (!fixture) {
|
|
38
|
+
if (defaults.record) {
|
|
39
|
+
if (await proxyAndRecord(req, res, syntheticReq, "openai", req.url ?? "/v1/audio/transcriptions", fixtures, defaults, raw)) {
|
|
40
|
+
journal.add({
|
|
41
|
+
method,
|
|
42
|
+
path,
|
|
43
|
+
headers: flattenHeaders(req.headers),
|
|
44
|
+
body: syntheticReq,
|
|
45
|
+
response: {
|
|
46
|
+
status: res.statusCode ?? 200,
|
|
47
|
+
fixture: null
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const strictStatus = defaults.strict ? 503 : 404;
|
|
54
|
+
const strictMessage = defaults.strict ? "Strict mode: no fixture matched" : "No fixture matched";
|
|
55
|
+
journal.add({
|
|
56
|
+
method,
|
|
57
|
+
path,
|
|
58
|
+
headers: flattenHeaders(req.headers),
|
|
59
|
+
body: syntheticReq,
|
|
60
|
+
response: {
|
|
61
|
+
status: strictStatus,
|
|
62
|
+
fixture: null
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
|
|
66
|
+
message: strictMessage,
|
|
67
|
+
type: "invalid_request_error",
|
|
68
|
+
code: "no_fixture_match"
|
|
69
|
+
} }));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const response = fixture.response;
|
|
73
|
+
if (isErrorResponse(response)) {
|
|
74
|
+
const status = response.status ?? 500;
|
|
75
|
+
journal.add({
|
|
76
|
+
method,
|
|
77
|
+
path,
|
|
78
|
+
headers: flattenHeaders(req.headers),
|
|
79
|
+
body: syntheticReq,
|
|
80
|
+
response: {
|
|
81
|
+
status,
|
|
82
|
+
fixture
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
writeErrorResponse(res, status, JSON.stringify(response));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (!isTranscriptionResponse(response)) {
|
|
89
|
+
journal.add({
|
|
90
|
+
method,
|
|
91
|
+
path,
|
|
92
|
+
headers: flattenHeaders(req.headers),
|
|
93
|
+
body: syntheticReq,
|
|
94
|
+
response: {
|
|
95
|
+
status: 500,
|
|
96
|
+
fixture
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
100
|
+
message: "Fixture response is not a transcription type",
|
|
101
|
+
type: "server_error"
|
|
102
|
+
} }));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
journal.add({
|
|
106
|
+
method,
|
|
107
|
+
path,
|
|
108
|
+
headers: flattenHeaders(req.headers),
|
|
109
|
+
body: syntheticReq,
|
|
110
|
+
response: {
|
|
111
|
+
status: 200,
|
|
112
|
+
fixture
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const t = response.transcription;
|
|
116
|
+
if (responseFormat === "verbose_json" || t.words != null || t.segments != null) {
|
|
117
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
118
|
+
res.end(JSON.stringify({
|
|
119
|
+
task: "transcribe",
|
|
120
|
+
language: t.language ?? "english",
|
|
121
|
+
duration: t.duration ?? 0,
|
|
122
|
+
text: t.text,
|
|
123
|
+
words: t.words ?? [],
|
|
124
|
+
segments: t.segments ?? []
|
|
125
|
+
}));
|
|
126
|
+
} else {
|
|
127
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
128
|
+
res.end(JSON.stringify({ text: t.text }));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
export { handleTranscription };
|
|
134
|
+
//# sourceMappingURL=transcription.js.map
|
|
@@ -0,0 +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 named field value from a multipart/form-data body.\n * Lightweight parser — scans for Content-Disposition headers\n * to find simple string field values.\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 },\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/types.d.cts
CHANGED
|
@@ -50,6 +50,8 @@ interface ChatCompletionRequest {
|
|
|
50
50
|
};
|
|
51
51
|
/** Embedding input text, set by the embeddings handler for fixture matching. */
|
|
52
52
|
embeddingInput?: string;
|
|
53
|
+
/** Endpoint type, set by handlers for fixture endpoint filtering. */
|
|
54
|
+
_endpointType?: string;
|
|
53
55
|
[key: string]: unknown;
|
|
54
56
|
}
|
|
55
57
|
interface ToolDefinition {
|
|
@@ -70,6 +72,7 @@ interface FixtureMatch {
|
|
|
70
72
|
predicate?: (req: ChatCompletionRequest) => boolean;
|
|
71
73
|
/** Which occurrence of this match to respond to (0-indexed). Undefined means match any. */
|
|
72
74
|
sequenceIndex?: number;
|
|
75
|
+
endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding";
|
|
73
76
|
}
|
|
74
77
|
interface TextResponse {
|
|
75
78
|
content: string;
|
|
@@ -106,7 +109,45 @@ interface ErrorResponse {
|
|
|
106
109
|
interface EmbeddingResponse {
|
|
107
110
|
embedding: number[];
|
|
108
111
|
}
|
|
109
|
-
|
|
112
|
+
interface ImageItem {
|
|
113
|
+
url?: string;
|
|
114
|
+
b64Json?: string;
|
|
115
|
+
revisedPrompt?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ImageResponse {
|
|
118
|
+
image?: ImageItem;
|
|
119
|
+
images?: ImageItem[];
|
|
120
|
+
}
|
|
121
|
+
interface AudioResponse {
|
|
122
|
+
audio: string;
|
|
123
|
+
format?: string;
|
|
124
|
+
}
|
|
125
|
+
interface TranscriptionResponse {
|
|
126
|
+
transcription: {
|
|
127
|
+
text: string;
|
|
128
|
+
language?: string;
|
|
129
|
+
duration?: number;
|
|
130
|
+
words?: Array<{
|
|
131
|
+
word: string;
|
|
132
|
+
start: number;
|
|
133
|
+
end: number;
|
|
134
|
+
}>;
|
|
135
|
+
segments?: Array<{
|
|
136
|
+
id: number;
|
|
137
|
+
text: string;
|
|
138
|
+
start: number;
|
|
139
|
+
end: number;
|
|
140
|
+
}>;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
interface VideoResponse {
|
|
144
|
+
video: {
|
|
145
|
+
id: string;
|
|
146
|
+
status: "processing" | "completed" | "failed";
|
|
147
|
+
url?: string;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
type FixtureResponse = TextResponse | ToolCallResponse | ContentWithToolCallsResponse | ErrorResponse | EmbeddingResponse | ImageResponse | AudioResponse | TranscriptionResponse | VideoResponse;
|
|
110
151
|
interface StreamingProfile {
|
|
111
152
|
ttft?: number;
|
|
112
153
|
tps?: number;
|
|
@@ -142,6 +183,7 @@ interface FixtureFileEntry {
|
|
|
142
183
|
model?: string;
|
|
143
184
|
responseFormat?: string;
|
|
144
185
|
sequenceIndex?: number;
|
|
186
|
+
endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding";
|
|
145
187
|
};
|
|
146
188
|
response: FixtureResponse;
|
|
147
189
|
latency?: number;
|
|
@@ -262,5 +304,5 @@ interface HandlerDefaults {
|
|
|
262
304
|
}
|
|
263
305
|
//# sourceMappingURL=types.d.ts.map
|
|
264
306
|
//#endregion
|
|
265
|
-
export { ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileEntry, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, JournalEntry, MockServerOptions, Mountable, RecordConfig, RecordProviderKey, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition };
|
|
307
|
+
export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileEntry, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RecordConfig, RecordProviderKey, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
|
|
266
308
|
//# sourceMappingURL=types.d.cts.map
|
package/dist/types.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;UAQiB,SAAA;qBAER,IAAA,CAAK,sBACL,IAAA,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,GAAK,EAAA,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;;AAM5B,UAZO,eAAA,CAYP;EAAc,EAAA,EAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;UAQiB,SAAA;qBAER,IAAA,CAAK,sBACL,IAAA,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,GAAK,EAAA,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;;AAM5B,UAZO,eAAA,CAYP;EAAc,EAAA,EAAA,MAAA;EAUP,IAAA,EAAA,UAAA;EAOA,QAAA,EAAA;IAAY,IAAA,EAAA,MAAA;IACJ,SAAA,EAAA,MAAA;;;AAML,UA9BH,qBAAA,CA8BG;EAAqB,KAAA,EAAA,MAAA;EAQxB,QAAA,EApCL,WAoCiB,EAAA;EAQZ,MAAA,CAAA,EAAA,OAAQ;EAMR,WAAA,CAAA,EAAA,MAAgB;EAKhB,UAAA,CAAA,EAAA,MAAA;EASA,KAAA,CAAA,EA5DP,cA4DoB,EAAA;EAKb,WAAA,CAAA,EAAA,MAAiB,GAAA,MAAA;EAIjB,eAAS,CAAA,EAAA;IAMT,IAAA,EAAA,MAAa;IAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;;EAEV,cAAA,CAAA,EAAA,MAAA;EAGH;EAKA,aAAA,CAAA,EAAA,MAAA;EAAqB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;AAMvB,UAjFE,cAAA,CAiFF;EAAK,IAAA,EAAA,UAAA;EAIH,QAAA,EAAA;IAQL,IAAA,EAAA,MAAA;IAAe,WAAA,CAAA,EAAA,MAAA;IACvB,UAAA,CAAA,EAAA,MAAA;;;AAGA,UA1Fa,YAAA,CA0Fb;aACA,CAAA,EAAA,MAAA,GA1FqB,MA0FrB;WACA,CAAA,EAAA,MAAA,GA1FmB,MA0FnB;YACA,CAAA,EAAA,MAAA;UACA,CAAA,EAAA,MAAA;OACA,CAAA,EAAA,MAAA,GA1Fe,MA0Ff;EAAa,cAAA,CAAA,EAAA,MAAA;EAIA,SAAA,CAAA,EAAA,CAAA,GAAA,EA5FG,qBA4Fa,EAAA,GAAA,OAAA;EAMhB;EAML,aAAA,CAAW,EAAA,MAAA;EAIN,QAAA,CAAA,EAAO,MAAA,GAAA,OAAA,GAAA,QAAA,GAAA,eAAA,GAAA,OAAA,GAAA,WAAA;;AACf,UArGQ,YAAA,CAqGR;SACG,EAAA,MAAA;WAKS,CAAA,EAAA,MAAA;aACX,CAAA,EAAA,MAAA,EAAA;EAAW,IAAA,CAAA,EAAA,MAAA;EAGT,YAAA,CAAA,EAAW,MAAA;;AAAQ,UAvGd,QAAA,CAuGc;MAAL,EAAA,MAAA;EAAI,SAAA,EAAA,MAAA;EAClB,EAAA,CAAA,EAAA,MAAA;;AAA4B,UAlGvB,gBAAA,CAkGuB;WAAL,EAjGtB,QAiGsB,EAAA;EAAI,YAAA,CAAA,EAAA,MAAA;AAIvC;AAIiB,UArGA,4BAAA,CAqGgB;EAAA,OAAA,EAAA,MAAA;WAYrB,EA/GC,QA+GD,EAAA;WAKS,CAAA,EAAA,MAAA;aACX,CAAA,EAAA,MAAA,EAAA;EAAW,IAAA,CAAA,EAAA,MAAA;EAKJ,YAAA,CAAA,EAAY,MAAA;;AAKlB,UAxHM,aAAA,CAwHN;OACH,EAAA;IAIK,OAAA,EAAA,MAAA;IAGK,IAAA,CAAA,EAAA,MAAA;IAAW,IAAA,CAAA,EAAA,MAAA;EAMZ,CAAA;EAQA,MAAA,CAAA,EAAA,MAAS;AAM1B;AAOiB,UAtJA,iBAAA,CAsJgB;EAShB,SAAA,EAAA,MAAc,EAAA;AAS/B;AAMiB,UA1KA,SAAA,CA0KA;EAUL,GAAA,CAAA,EAAA,MAAA;EAUK,OAAA,CAAA,EAAA,MAAY;EAAA,aAAA,CAAA,EAAA,MAAA;;AACR,UAzLJ,aAAA,CAyLI;OAAR,CAAA,EAxLH,SAwLG;EAAO,MAAA,CAAA,EAvLT,SAuLS,EAAA;AAMpB;AAAkC,UA1LjB,aAAA,CA0LiB;OAOxB,EAAA,MAAA;QAMC,CAAA,EAAA,MAAA;;AAU0C,UA5MpC,qBAAA,CA4MoC;EAAqB,aAAA,EAAA;IAOzD,IAAA,EAAA,MAAA;IAAe,QAAA,CAAA,EAAA,MAAA;IAGtB,QAAA,CAAA,EAAA,MAAA;IACA,KAAA,CAAA,EAlNE,KAkNF,CAAA;MACG,IAAA,EAAA,MAAA;MACF,KAAA,EAAA,MAAA;MAEgB,GAAA,EAAA,MAAA;IAA0B,CAAA,CAAA;IAAqB,QAAA,CAAA,EArN3D,KAqN2D,CAAA;;;;;;;;UAjNzD,aAAA;;;;;;;KAQL,eAAA,GACR,eACA,mBACA,+BACA,gBACA,oBACA,gBACA,gBACA,wBACA;UAIa,gBAAA;;;;;UAMA,WAAA;;;;;KAML,WAAA;UAIK,OAAA;SACR;YACG;;;;;qBAKS;UACX;;KAGE,WAAA,GAAc,KAAK;KACnB,oBAAA,GAAuB,KAAK;UAIvB,WAAA;YACL;;UAGK,gBAAA;;;;;;;;;;;YAYL;;;;;qBAKS;UACX;;UAKO,YAAA;;;;;WAKN;QACH;;;;aAIK;;;kBAGK;;;UAMD,QAAA;;;;;WAKN;;UAGM,SAAA;;SAER;;;UAIQ,QAAA;;;;eAIF;;UAGE,gBAAA;;;;;;;;;UASA,cAAA;;;;;WAKN;;;;;;;UAIM,oBAAA;;WAEN;;;UAIM,qBAAA;;;;;eAKF;;KAKH,iBAAA;UAUK,YAAA;aACJ,QAAQ,OAAO;;;;;UAMX,iBAAA;;;;;;;UAOP;;;;;;WAMC;;;;;;;;;;2BAUgB,0BAA0B;;UAOpC,eAAA;;;UAGP;UACA;aACG;WACF;;2BAEgB,0BAA0B"}
|
package/dist/types.d.ts
CHANGED
|
@@ -50,6 +50,8 @@ interface ChatCompletionRequest {
|
|
|
50
50
|
};
|
|
51
51
|
/** Embedding input text, set by the embeddings handler for fixture matching. */
|
|
52
52
|
embeddingInput?: string;
|
|
53
|
+
/** Endpoint type, set by handlers for fixture endpoint filtering. */
|
|
54
|
+
_endpointType?: string;
|
|
53
55
|
[key: string]: unknown;
|
|
54
56
|
}
|
|
55
57
|
interface ToolDefinition {
|
|
@@ -70,6 +72,7 @@ interface FixtureMatch {
|
|
|
70
72
|
predicate?: (req: ChatCompletionRequest) => boolean;
|
|
71
73
|
/** Which occurrence of this match to respond to (0-indexed). Undefined means match any. */
|
|
72
74
|
sequenceIndex?: number;
|
|
75
|
+
endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding";
|
|
73
76
|
}
|
|
74
77
|
interface TextResponse {
|
|
75
78
|
content: string;
|
|
@@ -106,7 +109,45 @@ interface ErrorResponse {
|
|
|
106
109
|
interface EmbeddingResponse {
|
|
107
110
|
embedding: number[];
|
|
108
111
|
}
|
|
109
|
-
|
|
112
|
+
interface ImageItem {
|
|
113
|
+
url?: string;
|
|
114
|
+
b64Json?: string;
|
|
115
|
+
revisedPrompt?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ImageResponse {
|
|
118
|
+
image?: ImageItem;
|
|
119
|
+
images?: ImageItem[];
|
|
120
|
+
}
|
|
121
|
+
interface AudioResponse {
|
|
122
|
+
audio: string;
|
|
123
|
+
format?: string;
|
|
124
|
+
}
|
|
125
|
+
interface TranscriptionResponse {
|
|
126
|
+
transcription: {
|
|
127
|
+
text: string;
|
|
128
|
+
language?: string;
|
|
129
|
+
duration?: number;
|
|
130
|
+
words?: Array<{
|
|
131
|
+
word: string;
|
|
132
|
+
start: number;
|
|
133
|
+
end: number;
|
|
134
|
+
}>;
|
|
135
|
+
segments?: Array<{
|
|
136
|
+
id: number;
|
|
137
|
+
text: string;
|
|
138
|
+
start: number;
|
|
139
|
+
end: number;
|
|
140
|
+
}>;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
interface VideoResponse {
|
|
144
|
+
video: {
|
|
145
|
+
id: string;
|
|
146
|
+
status: "processing" | "completed" | "failed";
|
|
147
|
+
url?: string;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
type FixtureResponse = TextResponse | ToolCallResponse | ContentWithToolCallsResponse | ErrorResponse | EmbeddingResponse | ImageResponse | AudioResponse | TranscriptionResponse | VideoResponse;
|
|
110
151
|
interface StreamingProfile {
|
|
111
152
|
ttft?: number;
|
|
112
153
|
tps?: number;
|
|
@@ -142,6 +183,7 @@ interface FixtureFileEntry {
|
|
|
142
183
|
model?: string;
|
|
143
184
|
responseFormat?: string;
|
|
144
185
|
sequenceIndex?: number;
|
|
186
|
+
endpoint?: "chat" | "image" | "speech" | "transcription" | "video" | "embedding";
|
|
145
187
|
};
|
|
146
188
|
response: FixtureResponse;
|
|
147
189
|
latency?: number;
|
|
@@ -262,5 +304,5 @@ interface HandlerDefaults {
|
|
|
262
304
|
}
|
|
263
305
|
//# sourceMappingURL=types.d.ts.map
|
|
264
306
|
//#endregion
|
|
265
|
-
export { ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileEntry, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, JournalEntry, MockServerOptions, Mountable, RecordConfig, RecordProviderKey, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition };
|
|
307
|
+
export { AudioResponse, ChaosAction, ChaosConfig, ChatCompletion, ChatCompletionChoice, ChatCompletionMessage, ChatCompletionRequest, ChatMessage, ContentPart, EmbeddingFixtureOpts, EmbeddingResponse, ErrorResponse, Fixture, FixtureFile, FixtureFileEntry, FixtureMatch, FixtureOpts, FixtureResponse, HandlerDefaults, ImageItem, ImageResponse, JournalEntry, MockServerOptions, Mountable, RecordConfig, RecordProviderKey, SSEChoice, SSEChunk, SSEDelta, SSEToolCallDelta, StreamingProfile, TextResponse, ToolCall, ToolCallMessage, ToolCallResponse, ToolDefinition, TranscriptionResponse, VideoResponse };
|
|
266
308
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;;UAQiB,SAAA;qBAER,IAAA,CAAK,sBACL,IAAA,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,GAAK,EAAA,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;;AAM5B,UAZO,eAAA,CAYP;EAAc,EAAA,EAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,
|
|
1
|
+
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMJ,CAAA;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
|
package/dist/video.cjs
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
const require_helpers = require('./helpers.cjs');
|
|
2
|
+
const require_router = require('./router.cjs');
|
|
3
|
+
const require_sse_writer = require('./sse-writer.cjs');
|
|
4
|
+
const require_chaos = require('./chaos.cjs');
|
|
5
|
+
const require_recorder = require('./recorder.cjs');
|
|
6
|
+
|
|
7
|
+
//#region src/video.ts
|
|
8
|
+
async function handleVideoCreate(req, res, raw, fixtures, journal, defaults, setCorsHeaders, videoStates) {
|
|
9
|
+
setCorsHeaders(res);
|
|
10
|
+
const path = req.url ?? "/v1/videos";
|
|
11
|
+
const method = req.method ?? "POST";
|
|
12
|
+
let videoReq;
|
|
13
|
+
try {
|
|
14
|
+
videoReq = JSON.parse(raw);
|
|
15
|
+
} catch {
|
|
16
|
+
journal.add({
|
|
17
|
+
method,
|
|
18
|
+
path,
|
|
19
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
20
|
+
body: null,
|
|
21
|
+
response: {
|
|
22
|
+
status: 400,
|
|
23
|
+
fixture: null
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
|
|
27
|
+
message: "Malformed JSON",
|
|
28
|
+
type: "invalid_request_error",
|
|
29
|
+
code: "invalid_json"
|
|
30
|
+
} }));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const syntheticReq = {
|
|
34
|
+
model: videoReq.model ?? "sora-2",
|
|
35
|
+
messages: [{
|
|
36
|
+
role: "user",
|
|
37
|
+
content: videoReq.prompt
|
|
38
|
+
}],
|
|
39
|
+
_endpointType: "video"
|
|
40
|
+
};
|
|
41
|
+
const testId = require_helpers.getTestId(req);
|
|
42
|
+
const fixture = require_router.matchFixture(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
43
|
+
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
44
|
+
if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
|
|
45
|
+
method,
|
|
46
|
+
path,
|
|
47
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
48
|
+
body: syntheticReq
|
|
49
|
+
}, defaults.registry, defaults.logger)) return;
|
|
50
|
+
if (!fixture) {
|
|
51
|
+
if (defaults.record) {
|
|
52
|
+
if (await require_recorder.proxyAndRecord(req, res, syntheticReq, "openai", req.url ?? "/v1/videos", fixtures, defaults, raw)) {
|
|
53
|
+
journal.add({
|
|
54
|
+
method,
|
|
55
|
+
path,
|
|
56
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
57
|
+
body: syntheticReq,
|
|
58
|
+
response: {
|
|
59
|
+
status: res.statusCode ?? 200,
|
|
60
|
+
fixture: null
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const strictStatus = defaults.strict ? 503 : 404;
|
|
67
|
+
const strictMessage = defaults.strict ? "Strict mode: no fixture matched" : "No fixture matched";
|
|
68
|
+
journal.add({
|
|
69
|
+
method,
|
|
70
|
+
path,
|
|
71
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
72
|
+
body: syntheticReq,
|
|
73
|
+
response: {
|
|
74
|
+
status: strictStatus,
|
|
75
|
+
fixture: null
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
require_sse_writer.writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
|
|
79
|
+
message: strictMessage,
|
|
80
|
+
type: "invalid_request_error",
|
|
81
|
+
code: "no_fixture_match"
|
|
82
|
+
} }));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const response = fixture.response;
|
|
86
|
+
if (require_helpers.isErrorResponse(response)) {
|
|
87
|
+
const status = response.status ?? 500;
|
|
88
|
+
journal.add({
|
|
89
|
+
method,
|
|
90
|
+
path,
|
|
91
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
92
|
+
body: syntheticReq,
|
|
93
|
+
response: {
|
|
94
|
+
status,
|
|
95
|
+
fixture
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
require_sse_writer.writeErrorResponse(res, status, JSON.stringify(response));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!require_helpers.isVideoResponse(response)) {
|
|
102
|
+
journal.add({
|
|
103
|
+
method,
|
|
104
|
+
path,
|
|
105
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
106
|
+
body: syntheticReq,
|
|
107
|
+
response: {
|
|
108
|
+
status: 500,
|
|
109
|
+
fixture
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
|
|
113
|
+
message: "Fixture response is not a video type",
|
|
114
|
+
type: "server_error"
|
|
115
|
+
} }));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
journal.add({
|
|
119
|
+
method,
|
|
120
|
+
path,
|
|
121
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
122
|
+
body: syntheticReq,
|
|
123
|
+
response: {
|
|
124
|
+
status: 200,
|
|
125
|
+
fixture
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
const video = response.video;
|
|
129
|
+
const created_at = Math.floor(Date.now() / 1e3);
|
|
130
|
+
const stateKey = `${testId}:${video.id}`;
|
|
131
|
+
videoStates.set(stateKey, video);
|
|
132
|
+
if (video.status === "completed") {
|
|
133
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
134
|
+
res.end(JSON.stringify({
|
|
135
|
+
id: video.id,
|
|
136
|
+
status: video.status,
|
|
137
|
+
url: video.url,
|
|
138
|
+
created_at
|
|
139
|
+
}));
|
|
140
|
+
} else {
|
|
141
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
142
|
+
res.end(JSON.stringify({
|
|
143
|
+
id: video.id,
|
|
144
|
+
status: video.status,
|
|
145
|
+
created_at
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function handleVideoStatus(req, res, videoId, journal, setCorsHeaders, videoStates) {
|
|
150
|
+
setCorsHeaders(res);
|
|
151
|
+
const path = req.url ?? `/v1/videos/${videoId}`;
|
|
152
|
+
const method = req.method ?? "GET";
|
|
153
|
+
const stateKey = `${require_helpers.getTestId(req)}:${videoId}`;
|
|
154
|
+
const video = videoStates.get(stateKey);
|
|
155
|
+
if (!video) {
|
|
156
|
+
journal.add({
|
|
157
|
+
method,
|
|
158
|
+
path,
|
|
159
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
160
|
+
body: null,
|
|
161
|
+
response: {
|
|
162
|
+
status: 404,
|
|
163
|
+
fixture: null
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
require_sse_writer.writeErrorResponse(res, 404, JSON.stringify({ error: {
|
|
167
|
+
message: `Video ${videoId} not found`,
|
|
168
|
+
type: "not_found"
|
|
169
|
+
} }));
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
journal.add({
|
|
173
|
+
method,
|
|
174
|
+
path,
|
|
175
|
+
headers: require_helpers.flattenHeaders(req.headers),
|
|
176
|
+
body: null,
|
|
177
|
+
response: {
|
|
178
|
+
status: 200,
|
|
179
|
+
fixture: null
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const created_at = Math.floor(Date.now() / 1e3);
|
|
183
|
+
const body = {
|
|
184
|
+
id: video.id,
|
|
185
|
+
status: video.status,
|
|
186
|
+
created_at
|
|
187
|
+
};
|
|
188
|
+
if (video.url) body.url = video.url;
|
|
189
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
190
|
+
res.end(JSON.stringify(body));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
exports.handleVideoCreate = handleVideoCreate;
|
|
195
|
+
exports.handleVideoStatus = handleVideoStatus;
|
|
196
|
+
//# sourceMappingURL=video.cjs.map
|
|
@@ -0,0 +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/** Stored video state for GET status checks. Key: `${testId}:${videoId}` */\nexport type VideoStateMap = Map<string, VideoResponse[\"video\"]>;\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 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 },\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":";;;;;;;AAkBA,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;SACpB;AACN,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;GAAkB,MAAM;GAAyB,MAAM;GAAgB,EAC1F,CAAC,CACH;AACD;;CAGF,MAAM,eAAsC;EAC1C,OAAO,SAAS,SAAS;EACzB,UAAU,CAAC;GAAE,MAAM;GAAQ,SAAS,SAAS;GAAQ,CAAC;EACtD,eAAe;EAChB;CAED,MAAM,SAASC,0BAAU,IAAI;CAC7B,MAAM,UAAUC,4BACd,UACA,cACA,QAAQ,6BAA6B,OAAO,EAC5C,SAAS,iBACV;AAED,KAAI,QACF,SAAQ,2BAA2B,SAAS,UAAU,OAAO;AAG/D,KACEC,yBACE,KACA,SACA,SAAS,OACT,IAAI,SACJ,SACA;EAAE;EAAQ;EAAM,SAASH,+BAAe,IAAI,QAAQ;EAAE,MAAM;EAAc,EAC1E,SAAS,UACT,SAAS,OACV,CAED;AAEF,KAAI,CAAC,SAAS;AACZ,MAAI,SAAS,QAWX;OAVgB,MAAMI,gCACpB,KACA,KACA,cACA,UACA,IAAI,OAAO,cACX,UACA,UACA,IACD,EACY;AACX,YAAQ,IAAI;KACV;KACA;KACA,SAASJ,+BAAe,IAAI,QAAQ;KACpC,MAAM;KACN,UAAU;MAAE,QAAQ,IAAI,cAAc;MAAK,SAAS;MAAM;KAC3D,CAAC;AACF;;;EAIJ,MAAM,eAAe,SAAS,SAAS,MAAM;EAC7C,MAAM,gBAAgB,SAAS,SAC3B,oCACA;AACJ,UAAQ,IAAI;GACV;GACA;GACA,SAASA,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE,QAAQ;IAAc,SAAS;IAAM;GAClD,CAAC;AACF,wCACE,KACA,cACA,KAAK,UAAU,EACb,OAAO;GAAE,SAAS;GAAe,MAAM;GAAyB,MAAM;GAAoB,EAC3F,CAAC,CACH;AACD;;CAGF,MAAM,WAAW,QAAQ;AAEzB,KAAIK,gCAAgB,SAAS,EAAE;EAC7B,MAAM,SAAS,SAAS,UAAU;AAClC,UAAQ,IAAI;GACV;GACA;GACA,SAASL,+BAAe,IAAI,QAAQ;GACpC,MAAM;GACN,UAAU;IAAE;IAAQ;IAAS;GAC9B,CAAC;AACF,wCAAmB,KAAK,QAAQ,KAAK,UAAU,SAAS,CAAC;AACzD;;AAGF,KAAI,CAACM,gCAAgB,SAAS,EAAE;AAC9B,UAAQ,IAAI;GACV;GACA;GACA,SAASN,+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;CACvB,MAAM,aAAa,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;CAGhD,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM;AACpC,aAAY,IAAI,UAAU,MAAM;AAEhC,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,gBACA,aACM;AACN,gBAAe,IAAI;CACnB,MAAM,OAAO,IAAI,OAAO,cAAc;CACtC,MAAM,SAAS,IAAI,UAAU;CAG7B,MAAM,WAAW,GADFC,0BAAU,IAAI,CACF,GAAG;CAC9B,MAAM,QAAQ,YAAY,IAAI,SAAS;AAEvC,KAAI,CAAC,OAAO;AACV,UAAQ,IAAI;GACV;GACA;GACA,SAASD,+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;;AAGF,SAAQ,IAAI;EACV;EACA;EACA,SAASA,+BAAe,IAAI,QAAQ;EACpC,MAAM;EACN,UAAU;GAAE,QAAQ;GAAK,SAAS;GAAM;EACzC,CAAC;CAEF,MAAM,aAAa,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;CAChD,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"}
|
package/dist/video.d.cts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Journal } from "./journal.cjs";
|
|
2
|
+
import { Fixture, HandlerDefaults, VideoResponse } from "./types.cjs";
|
|
3
|
+
import * as http from "node:http";
|
|
4
|
+
|
|
5
|
+
//#region src/video.d.ts
|
|
6
|
+
/** Stored video state for GET status checks. Key: `${testId}:${videoId}` */
|
|
7
|
+
type VideoStateMap = Map<string, VideoResponse["video"]>;
|
|
8
|
+
declare function handleVideoCreate(req: http.IncomingMessage, res: http.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
|
|
9
|
+
declare function handleVideoStatus(req: http.IncomingMessage, res: http.ServerResponse, videoId: string, journal: Journal, setCorsHeaders: (res: http.ServerResponse) => void, videoStates: VideoStateMap): void;
|
|
10
|
+
//# sourceMappingURL=video.d.ts.map
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { VideoStateMap, handleVideoCreate, handleVideoStatus };
|
|
14
|
+
//# sourceMappingURL=video.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;KAgBY,aAAA,GAAgB,YAAY;AAA5B,iBAEU,iBAAA,CAFG,GAAA,EAGlB,IAAA,CAAK,eAHa,EAAA,GAAA,EAIlB,IAAA,CAAK,cAJa,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAMb,OANa,EAAA,EAAA,OAAA,EAOd,OAPc,EAAA,QAAA,EAQb,eARa,EAAA,cAAA,EAAA,CAAA,GAAA,EASD,IAAA,CAAK,cATJ,EAAA,GAAA,IAAA,EAAA,WAAA,EAUV,aAVU,CAAA,EAWtB,OAXsB,CAAA,IAAA,CAAA;AAAA,iBA2KT,iBAAA,CA3KS,GAAA,EA4KlB,IAAA,CAAK,eA5Ka,EAAA,GAAA,EA6KlB,IAAA,CAAK,cA7Ka,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EA+Kd,OA/Kc,EAAA,cAAA,EAAA,CAAA,GAAA,EAgLD,IAAA,CAAK,cAhLJ,EAAA,GAAA,IAAA,EAAA,WAAA,EAiLV,aAjLU,CAAA,EAAA,IAAA"}
|