@editframe/api 0.37.3-beta → 0.38.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/dist/CHUNK_SIZE_BYTES.cjs +13 -0
- package/dist/CHUNK_SIZE_BYTES.cjs.map +1 -0
- package/dist/ProgressIterator.cjs +109 -0
- package/dist/ProgressIterator.cjs.map +1 -0
- package/dist/ProgressIterator.d.cts +30 -0
- package/dist/StreamEventSource.cjs +127 -0
- package/dist/StreamEventSource.cjs.map +1 -0
- package/dist/StreamEventSource.d.cts +65 -0
- package/dist/_virtual/rolldown_runtime.cjs +25 -0
- package/dist/client.cjs +54 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +14 -0
- package/dist/index.cjs +70 -0
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/node.cjs +175 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +27 -0
- package/dist/node.d.ts +8 -3
- package/dist/node.js +64 -5
- package/dist/node.js.map +1 -1
- package/dist/resources/caption-file.cjs +74 -0
- package/dist/resources/caption-file.cjs.map +1 -0
- package/dist/resources/caption-file.d.cts +83 -0
- package/dist/resources/caption-file.d.ts +5 -0
- package/dist/resources/caption-file.js +3 -0
- package/dist/resources/caption-file.js.map +1 -1
- package/dist/resources/file.cjs +145 -0
- package/dist/resources/file.cjs.map +1 -0
- package/dist/resources/file.d.cts +91 -0
- package/dist/resources/file.d.ts +91 -0
- package/dist/resources/file.js +129 -0
- package/dist/resources/file.js.map +1 -0
- package/dist/resources/image-file.cjs +87 -0
- package/dist/resources/image-file.cjs.map +1 -0
- package/dist/resources/image-file.d.cts +123 -0
- package/dist/resources/image-file.d.ts +7 -0
- package/dist/resources/image-file.js +4 -0
- package/dist/resources/image-file.js.map +1 -1
- package/dist/resources/isobmff-file.cjs +72 -0
- package/dist/resources/isobmff-file.cjs.map +1 -0
- package/dist/resources/isobmff-file.d.cts +81 -0
- package/dist/resources/isobmff-file.d.ts +8 -0
- package/dist/resources/isobmff-file.js +5 -0
- package/dist/resources/isobmff-file.js.map +1 -1
- package/dist/resources/isobmff-track.cjs +109 -0
- package/dist/resources/isobmff-track.cjs.map +1 -0
- package/dist/resources/isobmff-track.d.cts +769 -0
- package/dist/resources/isobmff-track.d.ts +2 -0
- package/dist/resources/isobmff-track.js +2 -0
- package/dist/resources/isobmff-track.js.map +1 -1
- package/dist/resources/process-isobmff.cjs +16 -0
- package/dist/resources/process-isobmff.cjs.map +1 -0
- package/dist/resources/process-isobmff.d.cts +17 -0
- package/dist/resources/renders.bundle.cjs +50 -0
- package/dist/resources/renders.bundle.cjs.map +1 -0
- package/dist/resources/renders.bundle.d.cts +9 -0
- package/dist/resources/renders.bundle.d.ts +1 -1
- package/dist/resources/renders.cjs +152 -0
- package/dist/resources/renders.cjs.map +1 -0
- package/dist/resources/renders.d.cts +284 -0
- package/dist/resources/renders.d.ts +19 -19
- package/dist/resources/renders.js +1 -1
- package/dist/resources/transcriptions.cjs +38 -0
- package/dist/resources/transcriptions.cjs.map +1 -0
- package/dist/resources/transcriptions.d.cts +30 -0
- package/dist/resources/unprocessed-file.cjs +61 -0
- package/dist/resources/unprocessed-file.cjs.map +1 -0
- package/dist/resources/unprocessed-file.d.cts +51 -0
- package/dist/resources/unprocessed-file.d.ts +9 -0
- package/dist/resources/unprocessed-file.js +4 -0
- package/dist/resources/unprocessed-file.js.map +1 -1
- package/dist/resources/url-token.cjs +19 -0
- package/dist/resources/url-token.cjs.map +1 -0
- package/dist/resources/url-token.d.cts +10 -0
- package/dist/streamChunker.cjs +29 -0
- package/dist/streamChunker.cjs.map +1 -0
- package/dist/uploadChunks.cjs +87 -0
- package/dist/uploadChunks.cjs.map +1 -0
- package/dist/uploadChunks.d.cts +14 -0
- package/dist/utils/assertTypesMatch.cjs +7 -0
- package/dist/utils/assertTypesMatch.cjs.map +1 -0
- package/dist/utils/createReadableStreamFromReadable.cjs +71 -0
- package/dist/utils/createReadableStreamFromReadable.cjs.map +1 -0
- package/dist/utils/createReadableStreamFromReadable.d.cts +9 -0
- package/dist/utils/createReadableStreamFromReadable.d.ts +1 -1
- package/package.json +37 -9
- package/tsdown.config.ts +1 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_ProgressIterator = require('../ProgressIterator.cjs');
|
|
3
|
+
const require_uploadChunks = require('../uploadChunks.cjs');
|
|
4
|
+
const require_isobmff_track = require('./isobmff-track.cjs');
|
|
5
|
+
let debug = require("debug");
|
|
6
|
+
debug = require_rolldown_runtime.__toESM(debug);
|
|
7
|
+
let zod = require("zod");
|
|
8
|
+
zod = require_rolldown_runtime.__toESM(zod);
|
|
9
|
+
|
|
10
|
+
//#region src/resources/file.ts
|
|
11
|
+
const log = (0, debug.default)("ef:api:file");
|
|
12
|
+
const MAX_VIDEO_SIZE = 1024 * 1024 * 1024;
|
|
13
|
+
const MAX_IMAGE_SIZE = 1024 * 1024 * 16;
|
|
14
|
+
const MAX_CAPTION_SIZE = 1024 * 1024 * 2;
|
|
15
|
+
const FileType = zod.z.enum([
|
|
16
|
+
"video",
|
|
17
|
+
"image",
|
|
18
|
+
"caption"
|
|
19
|
+
]);
|
|
20
|
+
const FileStatus = zod.z.enum([
|
|
21
|
+
"created",
|
|
22
|
+
"uploading",
|
|
23
|
+
"processing",
|
|
24
|
+
"ready",
|
|
25
|
+
"failed"
|
|
26
|
+
]);
|
|
27
|
+
const CreateFilePayload = zod.z.object({
|
|
28
|
+
filename: zod.z.string(),
|
|
29
|
+
type: FileType,
|
|
30
|
+
byte_size: zod.z.number().int().positive(),
|
|
31
|
+
md5: zod.z.string().optional(),
|
|
32
|
+
mime_type: zod.z.string().optional()
|
|
33
|
+
});
|
|
34
|
+
const MAX_SIZE_BY_TYPE = {
|
|
35
|
+
video: MAX_VIDEO_SIZE,
|
|
36
|
+
image: MAX_IMAGE_SIZE,
|
|
37
|
+
caption: MAX_CAPTION_SIZE
|
|
38
|
+
};
|
|
39
|
+
const createFile = async (client, payload) => {
|
|
40
|
+
log("Creating a file", payload);
|
|
41
|
+
CreateFilePayload.parse(payload);
|
|
42
|
+
const maxSize = MAX_SIZE_BY_TYPE[payload.type];
|
|
43
|
+
if (payload.byte_size > maxSize) throw new Error(`File size ${payload.byte_size} bytes exceeds limit ${maxSize} bytes for type ${payload.type}`);
|
|
44
|
+
const response = await client.authenticatedFetch("/api/v1/files", {
|
|
45
|
+
method: "POST",
|
|
46
|
+
body: JSON.stringify(payload)
|
|
47
|
+
});
|
|
48
|
+
log("File created", response.status, response.statusText);
|
|
49
|
+
if (response.ok) return await response.json();
|
|
50
|
+
throw new Error(`Failed to create file ${response.status} ${response.statusText}`);
|
|
51
|
+
};
|
|
52
|
+
const uploadFile = (client, uploadDetails, fileStream) => {
|
|
53
|
+
log("Uploading file", uploadDetails.id);
|
|
54
|
+
const maxSize = MAX_SIZE_BY_TYPE[uploadDetails.type];
|
|
55
|
+
return require_uploadChunks.uploadChunks(client, {
|
|
56
|
+
url: `/api/v1/files/${uploadDetails.id}/upload`,
|
|
57
|
+
fileSize: uploadDetails.byte_size,
|
|
58
|
+
fileStream,
|
|
59
|
+
maxSize
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const getFileDetail = async (client, id) => {
|
|
63
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}`, { method: "GET" });
|
|
64
|
+
if (response.ok) return await response.json();
|
|
65
|
+
if (response.status === 404) throw new Error(`File not found: ${id}`);
|
|
66
|
+
throw new Error(`Failed to get file detail ${response.status} ${response.statusText}`);
|
|
67
|
+
};
|
|
68
|
+
const lookupFileByMd5 = async (client, md5) => {
|
|
69
|
+
const response = await client.authenticatedFetch(`/api/v1/files/md5/${md5}`, { method: "GET" });
|
|
70
|
+
if (response.ok) return await response.json();
|
|
71
|
+
if (response.status === 404) return null;
|
|
72
|
+
throw new Error(`Failed to lookup file by md5 ${md5} ${response.status} ${response.statusText}`);
|
|
73
|
+
};
|
|
74
|
+
const deleteFile = async (client, id) => {
|
|
75
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}/delete`, { method: "POST" });
|
|
76
|
+
if (response.ok) return await response.json();
|
|
77
|
+
throw new Error(`Failed to delete file ${id} ${response.status} ${response.statusText}`);
|
|
78
|
+
};
|
|
79
|
+
const getFileProcessingProgress = async (client, id) => {
|
|
80
|
+
return new require_ProgressIterator.ProgressIterator(await client.authenticatedEventSource(`/api/v1/files/${id}/progress`));
|
|
81
|
+
};
|
|
82
|
+
const transcribeFile = async (client, id, options = {}) => {
|
|
83
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}/transcribe`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
body: JSON.stringify(options)
|
|
86
|
+
});
|
|
87
|
+
if (response.ok) return await response.json();
|
|
88
|
+
throw new Error(`Failed to transcribe file ${id} ${response.status} ${response.statusText}`);
|
|
89
|
+
};
|
|
90
|
+
const getFileTranscription = async (client, id) => {
|
|
91
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}/transcription`, { method: "GET" });
|
|
92
|
+
if (response.ok) return await response.json();
|
|
93
|
+
if (response.status === 404) return null;
|
|
94
|
+
throw new Error(`Failed to get file transcription ${id} ${response.status} ${response.statusText}`);
|
|
95
|
+
};
|
|
96
|
+
const createFileTrack = async (client, fileId, payload) => {
|
|
97
|
+
log("Creating file track", fileId, payload);
|
|
98
|
+
require_isobmff_track.CreateISOBMFFTrackPayload.parse(payload);
|
|
99
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${fileId}/tracks`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
body: JSON.stringify(payload)
|
|
102
|
+
});
|
|
103
|
+
log("File track created", response.status, response.statusText);
|
|
104
|
+
if (response.ok) return await response.json();
|
|
105
|
+
throw new Error(`Failed to create file track ${response.status} ${response.statusText}`);
|
|
106
|
+
};
|
|
107
|
+
const uploadFileTrack = (client, fileId, trackId, byteSize, fileStream) => {
|
|
108
|
+
log("Uploading file track", fileId, trackId);
|
|
109
|
+
return require_uploadChunks.uploadChunks(client, {
|
|
110
|
+
url: `/api/v1/files/${fileId}/tracks/${trackId}/upload`,
|
|
111
|
+
fileSize: byteSize,
|
|
112
|
+
fileStream,
|
|
113
|
+
maxSize: MAX_VIDEO_SIZE
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
const FRAGMENT_INDEX_SIZE_LIMIT = 1024 * 1024 * 50;
|
|
117
|
+
const uploadFileIndex = async (client, fileId, fileStream, fileSize) => {
|
|
118
|
+
log("Uploading file index", fileId);
|
|
119
|
+
if (fileSize > FRAGMENT_INDEX_SIZE_LIMIT) throw new Error(`Fragment index size ${fileSize} exceeds limit of ${FRAGMENT_INDEX_SIZE_LIMIT} bytes`);
|
|
120
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${fileId}/index/upload`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
body: fileStream,
|
|
123
|
+
duplex: "half"
|
|
124
|
+
});
|
|
125
|
+
log("File index uploaded", response.status, response.statusText);
|
|
126
|
+
if (response.ok) return response.json();
|
|
127
|
+
throw new Error(`Failed to upload file index ${response.status} ${response.statusText}`);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
//#endregion
|
|
131
|
+
exports.CreateFilePayload = CreateFilePayload;
|
|
132
|
+
exports.FileStatus = FileStatus;
|
|
133
|
+
exports.FileType = FileType;
|
|
134
|
+
exports.createFile = createFile;
|
|
135
|
+
exports.createFileTrack = createFileTrack;
|
|
136
|
+
exports.deleteFile = deleteFile;
|
|
137
|
+
exports.getFileDetail = getFileDetail;
|
|
138
|
+
exports.getFileProcessingProgress = getFileProcessingProgress;
|
|
139
|
+
exports.getFileTranscription = getFileTranscription;
|
|
140
|
+
exports.lookupFileByMd5 = lookupFileByMd5;
|
|
141
|
+
exports.transcribeFile = transcribeFile;
|
|
142
|
+
exports.uploadFile = uploadFile;
|
|
143
|
+
exports.uploadFileIndex = uploadFileIndex;
|
|
144
|
+
exports.uploadFileTrack = uploadFileTrack;
|
|
145
|
+
//# sourceMappingURL=file.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.cjs","names":["z","MAX_SIZE_BY_TYPE: Record<FileType, number>","uploadChunks","ProgressIterator"],"sources":["../../src/resources/file.ts"],"sourcesContent":["import debug from \"debug\";\nimport { z } from \"zod\";\n\nimport type { Client } from \"../client.js\";\nimport { ProgressIterator } from \"../ProgressIterator.js\";\nimport { uploadChunks } from \"../uploadChunks.js\";\nimport {\n CreateISOBMFFTrackPayload,\n type CreateISOBMFFTrackResult,\n} from \"./isobmff-track.js\";\n\nconst log = debug(\"ef:api:file\");\n\nconst MAX_VIDEO_SIZE = 1024 * 1024 * 1024; // 1GiB\nconst MAX_IMAGE_SIZE = 1024 * 1024 * 16; // 16MB\nconst MAX_CAPTION_SIZE = 1024 * 1024 * 2; // 2MB\n\nexport const FileType = z.enum([\"video\", \"image\", \"caption\"]);\nexport type FileType = z.infer<typeof FileType>;\n\nexport const FileStatus = z.enum([\n \"created\",\n \"uploading\",\n \"processing\",\n \"ready\",\n \"failed\",\n]);\nexport type FileStatus = z.infer<typeof FileStatus>;\n\nexport const CreateFilePayload = z.object({\n filename: z.string(),\n type: FileType,\n byte_size: z.number().int().positive(),\n md5: z.string().optional(),\n mime_type: z.string().optional(),\n});\n\nexport type CreateFilePayload = z.infer<typeof CreateFilePayload>;\n\nexport interface FileRecord {\n id: string;\n filename: string;\n type: FileType;\n status: FileStatus;\n byte_size: number | null;\n md5: string | null;\n next_byte: number;\n}\n\nexport interface CreateFileResult extends FileRecord {}\n\nexport interface FileDetail extends FileRecord {\n mime_type?: string | null;\n width?: number | null;\n height?: number | null;\n created_at?: string;\n completed_at?: string | null;\n expires_at?: string | null;\n tracks?: Array<{\n track_id: number;\n type: string;\n codec_name: string;\n duration_ms: number;\n byte_size: number;\n }>;\n}\n\nexport interface LookupFileByMd5Result extends FileRecord {}\n\nexport interface TranscribeFileResult {\n id: string;\n file_id: string;\n track_id: number;\n}\n\nexport interface FileTranscriptionResult {\n id: string;\n work_slice_ms: number;\n status: string;\n completed_at: string | null;\n failed_at: string | null;\n}\n\nconst MAX_SIZE_BY_TYPE: Record<FileType, number> = {\n video: MAX_VIDEO_SIZE,\n image: MAX_IMAGE_SIZE,\n caption: MAX_CAPTION_SIZE,\n};\n\nexport const createFile = async (\n client: Client,\n payload: CreateFilePayload,\n) => {\n log(\"Creating a file\", payload);\n CreateFilePayload.parse(payload);\n\n const maxSize = MAX_SIZE_BY_TYPE[payload.type];\n if (payload.byte_size > maxSize) {\n throw new Error(\n `File size ${payload.byte_size} bytes exceeds limit ${maxSize} bytes for type ${payload.type}`,\n );\n }\n\n const response = await client.authenticatedFetch(\"/api/v1/files\", {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n\n log(\"File created\", response.status, response.statusText);\n\n if (response.ok) {\n return (await response.json()) as CreateFileResult;\n }\n\n throw new Error(\n `Failed to create file ${response.status} ${response.statusText}`,\n );\n};\n\nexport const uploadFile = (\n client: Client,\n uploadDetails: { id: string; byte_size: number; type: FileType },\n fileStream: ReadableStream,\n) => {\n log(\"Uploading file\", uploadDetails.id);\n\n const maxSize = MAX_SIZE_BY_TYPE[uploadDetails.type];\n\n return uploadChunks(client, {\n url: `/api/v1/files/${uploadDetails.id}/upload`,\n fileSize: uploadDetails.byte_size,\n fileStream,\n maxSize,\n });\n};\n\nexport const getFileDetail = async (\n client: Client,\n id: string,\n): Promise<FileDetail> => {\n const response = await client.authenticatedFetch(`/api/v1/files/${id}`, {\n method: \"GET\",\n });\n\n if (response.ok) {\n return (await response.json()) as FileDetail;\n }\n\n if (response.status === 404) {\n throw new Error(`File not found: ${id}`);\n }\n\n throw new Error(\n `Failed to get file detail ${response.status} ${response.statusText}`,\n );\n};\n\nexport const lookupFileByMd5 = async (\n client: Client,\n md5: string,\n): Promise<LookupFileByMd5Result | null> => {\n const response = await client.authenticatedFetch(`/api/v1/files/md5/${md5}`, {\n method: \"GET\",\n });\n\n if (response.ok) {\n return (await response.json()) as LookupFileByMd5Result;\n }\n\n if (response.status === 404) {\n return null;\n }\n\n throw new Error(\n `Failed to lookup file by md5 ${md5} ${response.status} ${response.statusText}`,\n );\n};\n\nexport const deleteFile = async (client: Client, id: string) => {\n const response = await client.authenticatedFetch(\n `/api/v1/files/${id}/delete`,\n {\n method: \"POST\",\n },\n );\n\n if (response.ok) {\n return (await response.json()) as { success: boolean };\n }\n\n throw new Error(\n `Failed to delete file ${id} ${response.status} ${response.statusText}`,\n );\n};\n\nexport const getFileProcessingProgress = async (client: Client, id: string) => {\n const eventSource = await client.authenticatedEventSource(\n `/api/v1/files/${id}/progress`,\n );\n\n return new ProgressIterator(eventSource);\n};\n\nexport const transcribeFile = async (\n client: Client,\n id: string,\n options: { trackId?: number } = {},\n): Promise<TranscribeFileResult> => {\n const response = await client.authenticatedFetch(\n `/api/v1/files/${id}/transcribe`,\n {\n method: \"POST\",\n body: JSON.stringify(options),\n },\n );\n\n if (response.ok) {\n return (await response.json()) as TranscribeFileResult;\n }\n\n throw new Error(\n `Failed to transcribe file ${id} ${response.status} ${response.statusText}`,\n );\n};\n\nexport const getFileTranscription = async (\n client: Client,\n id: string,\n): Promise<FileTranscriptionResult | null> => {\n const response = await client.authenticatedFetch(\n `/api/v1/files/${id}/transcription`,\n {\n method: \"GET\",\n },\n );\n\n if (response.ok) {\n return (await response.json()) as FileTranscriptionResult;\n }\n\n if (response.status === 404) {\n return null;\n }\n\n throw new Error(\n `Failed to get file transcription ${id} ${response.status} ${response.statusText}`,\n );\n};\n\nexport type { CreateISOBMFFTrackPayload as CreateFileTrackPayload };\nexport type { CreateISOBMFFTrackResult as CreateFileTrackResult };\n\nexport const createFileTrack = async (\n client: Client,\n fileId: string,\n payload: CreateISOBMFFTrackPayload,\n): Promise<CreateISOBMFFTrackResult> => {\n log(\"Creating file track\", fileId, payload);\n CreateISOBMFFTrackPayload.parse(payload);\n\n const response = await client.authenticatedFetch(\n `/api/v1/files/${fileId}/tracks`,\n {\n method: \"POST\",\n body: JSON.stringify(payload),\n },\n );\n\n log(\"File track created\", response.status, response.statusText);\n\n if (response.ok) {\n return (await response.json()) as CreateISOBMFFTrackResult;\n }\n\n throw new Error(\n `Failed to create file track ${response.status} ${response.statusText}`,\n );\n};\n\nexport const uploadFileTrack = (\n client: Client,\n fileId: string,\n trackId: number,\n byteSize: number,\n fileStream: ReadableStream,\n) => {\n log(\"Uploading file track\", fileId, trackId);\n\n return uploadChunks(client, {\n url: `/api/v1/files/${fileId}/tracks/${trackId}/upload`,\n fileSize: byteSize,\n fileStream,\n maxSize: MAX_VIDEO_SIZE,\n });\n};\n\nconst FRAGMENT_INDEX_SIZE_LIMIT = 1024 * 1024 * 50; // 50MB\n\nexport const uploadFileIndex = async (\n client: Client,\n fileId: string,\n fileStream: ReadableStream,\n fileSize: number,\n) => {\n log(\"Uploading file index\", fileId);\n if (fileSize > FRAGMENT_INDEX_SIZE_LIMIT) {\n throw new Error(\n `Fragment index size ${fileSize} exceeds limit of ${FRAGMENT_INDEX_SIZE_LIMIT} bytes`,\n );\n }\n\n const response = await client.authenticatedFetch(\n `/api/v1/files/${fileId}/index/upload`,\n {\n method: \"POST\",\n body: fileStream,\n duplex: \"half\",\n },\n );\n\n log(\"File index uploaded\", response.status, response.statusText);\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(\n `Failed to upload file index ${response.status} ${response.statusText}`,\n );\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAM,yBAAY,cAAc;AAEhC,MAAM,iBAAiB,OAAO,OAAO;AACrC,MAAM,iBAAiB,OAAO,OAAO;AACrC,MAAM,mBAAmB,OAAO,OAAO;AAEvC,MAAa,WAAWA,MAAE,KAAK;CAAC;CAAS;CAAS;CAAU,CAAC;AAG7D,MAAa,aAAaA,MAAE,KAAK;CAC/B;CACA;CACA;CACA;CACA;CACD,CAAC;AAGF,MAAa,oBAAoBA,MAAE,OAAO;CACxC,UAAUA,MAAE,QAAQ;CACpB,MAAM;CACN,WAAWA,MAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;CACtC,KAAKA,MAAE,QAAQ,CAAC,UAAU;CAC1B,WAAWA,MAAE,QAAQ,CAAC,UAAU;CACjC,CAAC;AAgDF,MAAMC,mBAA6C;CACjD,OAAO;CACP,OAAO;CACP,SAAS;CACV;AAED,MAAa,aAAa,OACxB,QACA,YACG;AACH,KAAI,mBAAmB,QAAQ;AAC/B,mBAAkB,MAAM,QAAQ;CAEhC,MAAM,UAAU,iBAAiB,QAAQ;AACzC,KAAI,QAAQ,YAAY,QACtB,OAAM,IAAI,MACR,aAAa,QAAQ,UAAU,uBAAuB,QAAQ,kBAAkB,QAAQ,OACzF;CAGH,MAAM,WAAW,MAAM,OAAO,mBAAmB,iBAAiB;EAChE,QAAQ;EACR,MAAM,KAAK,UAAU,QAAQ;EAC9B,CAAC;AAEF,KAAI,gBAAgB,SAAS,QAAQ,SAAS,WAAW;AAEzD,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,OAAM,IAAI,MACR,yBAAyB,SAAS,OAAO,GAAG,SAAS,aACtD;;AAGH,MAAa,cACX,QACA,eACA,eACG;AACH,KAAI,kBAAkB,cAAc,GAAG;CAEvC,MAAM,UAAU,iBAAiB,cAAc;AAE/C,QAAOC,kCAAa,QAAQ;EAC1B,KAAK,iBAAiB,cAAc,GAAG;EACvC,UAAU,cAAc;EACxB;EACA;EACD,CAAC;;AAGJ,MAAa,gBAAgB,OAC3B,QACA,OACwB;CACxB,MAAM,WAAW,MAAM,OAAO,mBAAmB,iBAAiB,MAAM,EACtE,QAAQ,OACT,CAAC;AAEF,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,KAAI,SAAS,WAAW,IACtB,OAAM,IAAI,MAAM,mBAAmB,KAAK;AAG1C,OAAM,IAAI,MACR,6BAA6B,SAAS,OAAO,GAAG,SAAS,aAC1D;;AAGH,MAAa,kBAAkB,OAC7B,QACA,QAC0C;CAC1C,MAAM,WAAW,MAAM,OAAO,mBAAmB,qBAAqB,OAAO,EAC3E,QAAQ,OACT,CAAC;AAEF,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,KAAI,SAAS,WAAW,IACtB,QAAO;AAGT,OAAM,IAAI,MACR,gCAAgC,IAAI,GAAG,SAAS,OAAO,GAAG,SAAS,aACpE;;AAGH,MAAa,aAAa,OAAO,QAAgB,OAAe;CAC9D,MAAM,WAAW,MAAM,OAAO,mBAC5B,iBAAiB,GAAG,UACpB,EACE,QAAQ,QACT,CACF;AAED,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,OAAM,IAAI,MACR,yBAAyB,GAAG,GAAG,SAAS,OAAO,GAAG,SAAS,aAC5D;;AAGH,MAAa,4BAA4B,OAAO,QAAgB,OAAe;AAK7E,QAAO,IAAIC,0CAJS,MAAM,OAAO,yBAC/B,iBAAiB,GAAG,WACrB,CAEuC;;AAG1C,MAAa,iBAAiB,OAC5B,QACA,IACA,UAAgC,EAAE,KACA;CAClC,MAAM,WAAW,MAAM,OAAO,mBAC5B,iBAAiB,GAAG,cACpB;EACE,QAAQ;EACR,MAAM,KAAK,UAAU,QAAQ;EAC9B,CACF;AAED,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,OAAM,IAAI,MACR,6BAA6B,GAAG,GAAG,SAAS,OAAO,GAAG,SAAS,aAChE;;AAGH,MAAa,uBAAuB,OAClC,QACA,OAC4C;CAC5C,MAAM,WAAW,MAAM,OAAO,mBAC5B,iBAAiB,GAAG,iBACpB,EACE,QAAQ,OACT,CACF;AAED,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,KAAI,SAAS,WAAW,IACtB,QAAO;AAGT,OAAM,IAAI,MACR,oCAAoC,GAAG,GAAG,SAAS,OAAO,GAAG,SAAS,aACvE;;AAMH,MAAa,kBAAkB,OAC7B,QACA,QACA,YACsC;AACtC,KAAI,uBAAuB,QAAQ,QAAQ;AAC3C,iDAA0B,MAAM,QAAQ;CAExC,MAAM,WAAW,MAAM,OAAO,mBAC5B,iBAAiB,OAAO,UACxB;EACE,QAAQ;EACR,MAAM,KAAK,UAAU,QAAQ;EAC9B,CACF;AAED,KAAI,sBAAsB,SAAS,QAAQ,SAAS,WAAW;AAE/D,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,OAAM,IAAI,MACR,+BAA+B,SAAS,OAAO,GAAG,SAAS,aAC5D;;AAGH,MAAa,mBACX,QACA,QACA,SACA,UACA,eACG;AACH,KAAI,wBAAwB,QAAQ,QAAQ;AAE5C,QAAOD,kCAAa,QAAQ;EAC1B,KAAK,iBAAiB,OAAO,UAAU,QAAQ;EAC/C,UAAU;EACV;EACA,SAAS;EACV,CAAC;;AAGJ,MAAM,4BAA4B,OAAO,OAAO;AAEhD,MAAa,kBAAkB,OAC7B,QACA,QACA,YACA,aACG;AACH,KAAI,wBAAwB,OAAO;AACnC,KAAI,WAAW,0BACb,OAAM,IAAI,MACR,uBAAuB,SAAS,oBAAoB,0BAA0B,QAC/E;CAGH,MAAM,WAAW,MAAM,OAAO,mBAC5B,iBAAiB,OAAO,gBACxB;EACE,QAAQ;EACR,MAAM;EACN,QAAQ;EACT,CACF;AAED,KAAI,uBAAuB,SAAS,QAAQ,SAAS,WAAW;AAEhE,KAAI,SAAS,GACX,QAAO,SAAS,MAAM;AAGxB,OAAM,IAAI,MACR,+BAA+B,SAAS,OAAO,GAAG,SAAS,aAC5D"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Client } from "../client.cjs";
|
|
2
|
+
import { ProgressIterator } from "../ProgressIterator.cjs";
|
|
3
|
+
import { IteratorWithPromise, UploadChunkEvent } from "../uploadChunks.cjs";
|
|
4
|
+
import { CreateISOBMFFTrackPayload, CreateISOBMFFTrackResult } from "./isobmff-track.cjs";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/resources/file.d.ts
|
|
8
|
+
declare const FileType: z.ZodEnum<["video", "image", "caption"]>;
|
|
9
|
+
type FileType = z.infer<typeof FileType>;
|
|
10
|
+
declare const FileStatus: z.ZodEnum<["created", "uploading", "processing", "ready", "failed"]>;
|
|
11
|
+
type FileStatus = z.infer<typeof FileStatus>;
|
|
12
|
+
declare const CreateFilePayload: z.ZodObject<{
|
|
13
|
+
filename: z.ZodString;
|
|
14
|
+
type: z.ZodEnum<["video", "image", "caption"]>;
|
|
15
|
+
byte_size: z.ZodNumber;
|
|
16
|
+
md5: z.ZodOptional<z.ZodString>;
|
|
17
|
+
mime_type: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
filename: string;
|
|
20
|
+
byte_size: number;
|
|
21
|
+
type: "video" | "image" | "caption";
|
|
22
|
+
md5?: string | undefined;
|
|
23
|
+
mime_type?: string | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
filename: string;
|
|
26
|
+
byte_size: number;
|
|
27
|
+
type: "video" | "image" | "caption";
|
|
28
|
+
md5?: string | undefined;
|
|
29
|
+
mime_type?: string | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
type CreateFilePayload = z.infer<typeof CreateFilePayload>;
|
|
32
|
+
interface FileRecord {
|
|
33
|
+
id: string;
|
|
34
|
+
filename: string;
|
|
35
|
+
type: FileType;
|
|
36
|
+
status: FileStatus;
|
|
37
|
+
byte_size: number | null;
|
|
38
|
+
md5: string | null;
|
|
39
|
+
next_byte: number;
|
|
40
|
+
}
|
|
41
|
+
interface CreateFileResult extends FileRecord {}
|
|
42
|
+
interface FileDetail extends FileRecord {
|
|
43
|
+
mime_type?: string | null;
|
|
44
|
+
width?: number | null;
|
|
45
|
+
height?: number | null;
|
|
46
|
+
created_at?: string;
|
|
47
|
+
completed_at?: string | null;
|
|
48
|
+
expires_at?: string | null;
|
|
49
|
+
tracks?: Array<{
|
|
50
|
+
track_id: number;
|
|
51
|
+
type: string;
|
|
52
|
+
codec_name: string;
|
|
53
|
+
duration_ms: number;
|
|
54
|
+
byte_size: number;
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
interface LookupFileByMd5Result extends FileRecord {}
|
|
58
|
+
interface TranscribeFileResult {
|
|
59
|
+
id: string;
|
|
60
|
+
file_id: string;
|
|
61
|
+
track_id: number;
|
|
62
|
+
}
|
|
63
|
+
interface FileTranscriptionResult {
|
|
64
|
+
id: string;
|
|
65
|
+
work_slice_ms: number;
|
|
66
|
+
status: string;
|
|
67
|
+
completed_at: string | null;
|
|
68
|
+
failed_at: string | null;
|
|
69
|
+
}
|
|
70
|
+
declare const createFile: (client: Client, payload: CreateFilePayload) => Promise<CreateFileResult>;
|
|
71
|
+
declare const uploadFile: (client: Client, uploadDetails: {
|
|
72
|
+
id: string;
|
|
73
|
+
byte_size: number;
|
|
74
|
+
type: FileType;
|
|
75
|
+
}, fileStream: ReadableStream) => IteratorWithPromise<UploadChunkEvent>;
|
|
76
|
+
declare const getFileDetail: (client: Client, id: string) => Promise<FileDetail>;
|
|
77
|
+
declare const lookupFileByMd5: (client: Client, md5: string) => Promise<LookupFileByMd5Result | null>;
|
|
78
|
+
declare const deleteFile: (client: Client, id: string) => Promise<{
|
|
79
|
+
success: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
declare const getFileProcessingProgress: (client: Client, id: string) => Promise<ProgressIterator>;
|
|
82
|
+
declare const transcribeFile: (client: Client, id: string, options?: {
|
|
83
|
+
trackId?: number;
|
|
84
|
+
}) => Promise<TranscribeFileResult>;
|
|
85
|
+
declare const getFileTranscription: (client: Client, id: string) => Promise<FileTranscriptionResult | null>;
|
|
86
|
+
declare const createFileTrack: (client: Client, fileId: string, payload: CreateISOBMFFTrackPayload) => Promise<CreateISOBMFFTrackResult>;
|
|
87
|
+
declare const uploadFileTrack: (client: Client, fileId: string, trackId: number, byteSize: number, fileStream: ReadableStream) => IteratorWithPromise<UploadChunkEvent>;
|
|
88
|
+
declare const uploadFileIndex: (client: Client, fileId: string, fileStream: ReadableStream, fileSize: number) => Promise<any>;
|
|
89
|
+
//#endregion
|
|
90
|
+
export { CreateFilePayload, CreateFileResult, FileDetail, FileRecord, FileStatus, FileTranscriptionResult, FileType, LookupFileByMd5Result, TranscribeFileResult, createFile, createFileTrack, deleteFile, getFileDetail, getFileProcessingProgress, getFileTranscription, lookupFileByMd5, transcribeFile, uploadFile, uploadFileIndex, uploadFileTrack };
|
|
91
|
+
//# sourceMappingURL=file.d.cts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Client } from "../client.js";
|
|
2
|
+
import { ProgressIterator } from "../ProgressIterator.js";
|
|
3
|
+
import { IteratorWithPromise, UploadChunkEvent } from "../uploadChunks.js";
|
|
4
|
+
import { CreateISOBMFFTrackPayload, CreateISOBMFFTrackResult } from "./isobmff-track.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/resources/file.d.ts
|
|
8
|
+
declare const FileType: z.ZodEnum<["video", "image", "caption"]>;
|
|
9
|
+
type FileType = z.infer<typeof FileType>;
|
|
10
|
+
declare const FileStatus: z.ZodEnum<["created", "uploading", "processing", "ready", "failed"]>;
|
|
11
|
+
type FileStatus = z.infer<typeof FileStatus>;
|
|
12
|
+
declare const CreateFilePayload: z.ZodObject<{
|
|
13
|
+
filename: z.ZodString;
|
|
14
|
+
type: z.ZodEnum<["video", "image", "caption"]>;
|
|
15
|
+
byte_size: z.ZodNumber;
|
|
16
|
+
md5: z.ZodOptional<z.ZodString>;
|
|
17
|
+
mime_type: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
filename: string;
|
|
20
|
+
byte_size: number;
|
|
21
|
+
type: "video" | "image" | "caption";
|
|
22
|
+
md5?: string | undefined;
|
|
23
|
+
mime_type?: string | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
filename: string;
|
|
26
|
+
byte_size: number;
|
|
27
|
+
type: "video" | "image" | "caption";
|
|
28
|
+
md5?: string | undefined;
|
|
29
|
+
mime_type?: string | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
type CreateFilePayload = z.infer<typeof CreateFilePayload>;
|
|
32
|
+
interface FileRecord {
|
|
33
|
+
id: string;
|
|
34
|
+
filename: string;
|
|
35
|
+
type: FileType;
|
|
36
|
+
status: FileStatus;
|
|
37
|
+
byte_size: number | null;
|
|
38
|
+
md5: string | null;
|
|
39
|
+
next_byte: number;
|
|
40
|
+
}
|
|
41
|
+
interface CreateFileResult extends FileRecord {}
|
|
42
|
+
interface FileDetail extends FileRecord {
|
|
43
|
+
mime_type?: string | null;
|
|
44
|
+
width?: number | null;
|
|
45
|
+
height?: number | null;
|
|
46
|
+
created_at?: string;
|
|
47
|
+
completed_at?: string | null;
|
|
48
|
+
expires_at?: string | null;
|
|
49
|
+
tracks?: Array<{
|
|
50
|
+
track_id: number;
|
|
51
|
+
type: string;
|
|
52
|
+
codec_name: string;
|
|
53
|
+
duration_ms: number;
|
|
54
|
+
byte_size: number;
|
|
55
|
+
}>;
|
|
56
|
+
}
|
|
57
|
+
interface LookupFileByMd5Result extends FileRecord {}
|
|
58
|
+
interface TranscribeFileResult {
|
|
59
|
+
id: string;
|
|
60
|
+
file_id: string;
|
|
61
|
+
track_id: number;
|
|
62
|
+
}
|
|
63
|
+
interface FileTranscriptionResult {
|
|
64
|
+
id: string;
|
|
65
|
+
work_slice_ms: number;
|
|
66
|
+
status: string;
|
|
67
|
+
completed_at: string | null;
|
|
68
|
+
failed_at: string | null;
|
|
69
|
+
}
|
|
70
|
+
declare const createFile: (client: Client, payload: CreateFilePayload) => Promise<CreateFileResult>;
|
|
71
|
+
declare const uploadFile: (client: Client, uploadDetails: {
|
|
72
|
+
id: string;
|
|
73
|
+
byte_size: number;
|
|
74
|
+
type: FileType;
|
|
75
|
+
}, fileStream: ReadableStream) => IteratorWithPromise<UploadChunkEvent>;
|
|
76
|
+
declare const getFileDetail: (client: Client, id: string) => Promise<FileDetail>;
|
|
77
|
+
declare const lookupFileByMd5: (client: Client, md5: string) => Promise<LookupFileByMd5Result | null>;
|
|
78
|
+
declare const deleteFile: (client: Client, id: string) => Promise<{
|
|
79
|
+
success: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
declare const getFileProcessingProgress: (client: Client, id: string) => Promise<ProgressIterator>;
|
|
82
|
+
declare const transcribeFile: (client: Client, id: string, options?: {
|
|
83
|
+
trackId?: number;
|
|
84
|
+
}) => Promise<TranscribeFileResult>;
|
|
85
|
+
declare const getFileTranscription: (client: Client, id: string) => Promise<FileTranscriptionResult | null>;
|
|
86
|
+
declare const createFileTrack: (client: Client, fileId: string, payload: CreateISOBMFFTrackPayload) => Promise<CreateISOBMFFTrackResult>;
|
|
87
|
+
declare const uploadFileTrack: (client: Client, fileId: string, trackId: number, byteSize: number, fileStream: ReadableStream) => IteratorWithPromise<UploadChunkEvent>;
|
|
88
|
+
declare const uploadFileIndex: (client: Client, fileId: string, fileStream: ReadableStream, fileSize: number) => Promise<any>;
|
|
89
|
+
//#endregion
|
|
90
|
+
export { CreateFilePayload, CreateFileResult, FileDetail, FileRecord, FileStatus, FileTranscriptionResult, FileType, LookupFileByMd5Result, TranscribeFileResult, createFile, createFileTrack, deleteFile, getFileDetail, getFileProcessingProgress, getFileTranscription, lookupFileByMd5, transcribeFile, uploadFile, uploadFileIndex, uploadFileTrack };
|
|
91
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { ProgressIterator } from "../ProgressIterator.js";
|
|
2
|
+
import { uploadChunks } from "../uploadChunks.js";
|
|
3
|
+
import { CreateISOBMFFTrackPayload } from "./isobmff-track.js";
|
|
4
|
+
import debug from "debug";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/resources/file.ts
|
|
8
|
+
const log = debug("ef:api:file");
|
|
9
|
+
const MAX_VIDEO_SIZE = 1024 * 1024 * 1024;
|
|
10
|
+
const MAX_IMAGE_SIZE = 1024 * 1024 * 16;
|
|
11
|
+
const MAX_CAPTION_SIZE = 1024 * 1024 * 2;
|
|
12
|
+
const FileType = z.enum([
|
|
13
|
+
"video",
|
|
14
|
+
"image",
|
|
15
|
+
"caption"
|
|
16
|
+
]);
|
|
17
|
+
const FileStatus = z.enum([
|
|
18
|
+
"created",
|
|
19
|
+
"uploading",
|
|
20
|
+
"processing",
|
|
21
|
+
"ready",
|
|
22
|
+
"failed"
|
|
23
|
+
]);
|
|
24
|
+
const CreateFilePayload = z.object({
|
|
25
|
+
filename: z.string(),
|
|
26
|
+
type: FileType,
|
|
27
|
+
byte_size: z.number().int().positive(),
|
|
28
|
+
md5: z.string().optional(),
|
|
29
|
+
mime_type: z.string().optional()
|
|
30
|
+
});
|
|
31
|
+
const MAX_SIZE_BY_TYPE = {
|
|
32
|
+
video: MAX_VIDEO_SIZE,
|
|
33
|
+
image: MAX_IMAGE_SIZE,
|
|
34
|
+
caption: MAX_CAPTION_SIZE
|
|
35
|
+
};
|
|
36
|
+
const createFile = async (client, payload) => {
|
|
37
|
+
log("Creating a file", payload);
|
|
38
|
+
CreateFilePayload.parse(payload);
|
|
39
|
+
const maxSize = MAX_SIZE_BY_TYPE[payload.type];
|
|
40
|
+
if (payload.byte_size > maxSize) throw new Error(`File size ${payload.byte_size} bytes exceeds limit ${maxSize} bytes for type ${payload.type}`);
|
|
41
|
+
const response = await client.authenticatedFetch("/api/v1/files", {
|
|
42
|
+
method: "POST",
|
|
43
|
+
body: JSON.stringify(payload)
|
|
44
|
+
});
|
|
45
|
+
log("File created", response.status, response.statusText);
|
|
46
|
+
if (response.ok) return await response.json();
|
|
47
|
+
throw new Error(`Failed to create file ${response.status} ${response.statusText}`);
|
|
48
|
+
};
|
|
49
|
+
const uploadFile = (client, uploadDetails, fileStream) => {
|
|
50
|
+
log("Uploading file", uploadDetails.id);
|
|
51
|
+
const maxSize = MAX_SIZE_BY_TYPE[uploadDetails.type];
|
|
52
|
+
return uploadChunks(client, {
|
|
53
|
+
url: `/api/v1/files/${uploadDetails.id}/upload`,
|
|
54
|
+
fileSize: uploadDetails.byte_size,
|
|
55
|
+
fileStream,
|
|
56
|
+
maxSize
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const getFileDetail = async (client, id) => {
|
|
60
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}`, { method: "GET" });
|
|
61
|
+
if (response.ok) return await response.json();
|
|
62
|
+
if (response.status === 404) throw new Error(`File not found: ${id}`);
|
|
63
|
+
throw new Error(`Failed to get file detail ${response.status} ${response.statusText}`);
|
|
64
|
+
};
|
|
65
|
+
const lookupFileByMd5 = async (client, md5) => {
|
|
66
|
+
const response = await client.authenticatedFetch(`/api/v1/files/md5/${md5}`, { method: "GET" });
|
|
67
|
+
if (response.ok) return await response.json();
|
|
68
|
+
if (response.status === 404) return null;
|
|
69
|
+
throw new Error(`Failed to lookup file by md5 ${md5} ${response.status} ${response.statusText}`);
|
|
70
|
+
};
|
|
71
|
+
const deleteFile = async (client, id) => {
|
|
72
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}/delete`, { method: "POST" });
|
|
73
|
+
if (response.ok) return await response.json();
|
|
74
|
+
throw new Error(`Failed to delete file ${id} ${response.status} ${response.statusText}`);
|
|
75
|
+
};
|
|
76
|
+
const getFileProcessingProgress = async (client, id) => {
|
|
77
|
+
return new ProgressIterator(await client.authenticatedEventSource(`/api/v1/files/${id}/progress`));
|
|
78
|
+
};
|
|
79
|
+
const transcribeFile = async (client, id, options = {}) => {
|
|
80
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}/transcribe`, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
body: JSON.stringify(options)
|
|
83
|
+
});
|
|
84
|
+
if (response.ok) return await response.json();
|
|
85
|
+
throw new Error(`Failed to transcribe file ${id} ${response.status} ${response.statusText}`);
|
|
86
|
+
};
|
|
87
|
+
const getFileTranscription = async (client, id) => {
|
|
88
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${id}/transcription`, { method: "GET" });
|
|
89
|
+
if (response.ok) return await response.json();
|
|
90
|
+
if (response.status === 404) return null;
|
|
91
|
+
throw new Error(`Failed to get file transcription ${id} ${response.status} ${response.statusText}`);
|
|
92
|
+
};
|
|
93
|
+
const createFileTrack = async (client, fileId, payload) => {
|
|
94
|
+
log("Creating file track", fileId, payload);
|
|
95
|
+
CreateISOBMFFTrackPayload.parse(payload);
|
|
96
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${fileId}/tracks`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
body: JSON.stringify(payload)
|
|
99
|
+
});
|
|
100
|
+
log("File track created", response.status, response.statusText);
|
|
101
|
+
if (response.ok) return await response.json();
|
|
102
|
+
throw new Error(`Failed to create file track ${response.status} ${response.statusText}`);
|
|
103
|
+
};
|
|
104
|
+
const uploadFileTrack = (client, fileId, trackId, byteSize, fileStream) => {
|
|
105
|
+
log("Uploading file track", fileId, trackId);
|
|
106
|
+
return uploadChunks(client, {
|
|
107
|
+
url: `/api/v1/files/${fileId}/tracks/${trackId}/upload`,
|
|
108
|
+
fileSize: byteSize,
|
|
109
|
+
fileStream,
|
|
110
|
+
maxSize: MAX_VIDEO_SIZE
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const FRAGMENT_INDEX_SIZE_LIMIT = 1024 * 1024 * 50;
|
|
114
|
+
const uploadFileIndex = async (client, fileId, fileStream, fileSize) => {
|
|
115
|
+
log("Uploading file index", fileId);
|
|
116
|
+
if (fileSize > FRAGMENT_INDEX_SIZE_LIMIT) throw new Error(`Fragment index size ${fileSize} exceeds limit of ${FRAGMENT_INDEX_SIZE_LIMIT} bytes`);
|
|
117
|
+
const response = await client.authenticatedFetch(`/api/v1/files/${fileId}/index/upload`, {
|
|
118
|
+
method: "POST",
|
|
119
|
+
body: fileStream,
|
|
120
|
+
duplex: "half"
|
|
121
|
+
});
|
|
122
|
+
log("File index uploaded", response.status, response.statusText);
|
|
123
|
+
if (response.ok) return response.json();
|
|
124
|
+
throw new Error(`Failed to upload file index ${response.status} ${response.statusText}`);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
//#endregion
|
|
128
|
+
export { CreateFilePayload, FileStatus, FileType, createFile, createFileTrack, deleteFile, getFileDetail, getFileProcessingProgress, getFileTranscription, lookupFileByMd5, transcribeFile, uploadFile, uploadFileIndex, uploadFileTrack };
|
|
129
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","names":["MAX_SIZE_BY_TYPE: Record<FileType, number>"],"sources":["../../src/resources/file.ts"],"sourcesContent":["import debug from \"debug\";\nimport { z } from \"zod\";\n\nimport type { Client } from \"../client.js\";\nimport { ProgressIterator } from \"../ProgressIterator.js\";\nimport { uploadChunks } from \"../uploadChunks.js\";\nimport {\n CreateISOBMFFTrackPayload,\n type CreateISOBMFFTrackResult,\n} from \"./isobmff-track.js\";\n\nconst log = debug(\"ef:api:file\");\n\nconst MAX_VIDEO_SIZE = 1024 * 1024 * 1024; // 1GiB\nconst MAX_IMAGE_SIZE = 1024 * 1024 * 16; // 16MB\nconst MAX_CAPTION_SIZE = 1024 * 1024 * 2; // 2MB\n\nexport const FileType = z.enum([\"video\", \"image\", \"caption\"]);\nexport type FileType = z.infer<typeof FileType>;\n\nexport const FileStatus = z.enum([\n \"created\",\n \"uploading\",\n \"processing\",\n \"ready\",\n \"failed\",\n]);\nexport type FileStatus = z.infer<typeof FileStatus>;\n\nexport const CreateFilePayload = z.object({\n filename: z.string(),\n type: FileType,\n byte_size: z.number().int().positive(),\n md5: z.string().optional(),\n mime_type: z.string().optional(),\n});\n\nexport type CreateFilePayload = z.infer<typeof CreateFilePayload>;\n\nexport interface FileRecord {\n id: string;\n filename: string;\n type: FileType;\n status: FileStatus;\n byte_size: number | null;\n md5: string | null;\n next_byte: number;\n}\n\nexport interface CreateFileResult extends FileRecord {}\n\nexport interface FileDetail extends FileRecord {\n mime_type?: string | null;\n width?: number | null;\n height?: number | null;\n created_at?: string;\n completed_at?: string | null;\n expires_at?: string | null;\n tracks?: Array<{\n track_id: number;\n type: string;\n codec_name: string;\n duration_ms: number;\n byte_size: number;\n }>;\n}\n\nexport interface LookupFileByMd5Result extends FileRecord {}\n\nexport interface TranscribeFileResult {\n id: string;\n file_id: string;\n track_id: number;\n}\n\nexport interface FileTranscriptionResult {\n id: string;\n work_slice_ms: number;\n status: string;\n completed_at: string | null;\n failed_at: string | null;\n}\n\nconst MAX_SIZE_BY_TYPE: Record<FileType, number> = {\n video: MAX_VIDEO_SIZE,\n image: MAX_IMAGE_SIZE,\n caption: MAX_CAPTION_SIZE,\n};\n\nexport const createFile = async (\n client: Client,\n payload: CreateFilePayload,\n) => {\n log(\"Creating a file\", payload);\n CreateFilePayload.parse(payload);\n\n const maxSize = MAX_SIZE_BY_TYPE[payload.type];\n if (payload.byte_size > maxSize) {\n throw new Error(\n `File size ${payload.byte_size} bytes exceeds limit ${maxSize} bytes for type ${payload.type}`,\n );\n }\n\n const response = await client.authenticatedFetch(\"/api/v1/files\", {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n\n log(\"File created\", response.status, response.statusText);\n\n if (response.ok) {\n return (await response.json()) as CreateFileResult;\n }\n\n throw new Error(\n `Failed to create file ${response.status} ${response.statusText}`,\n );\n};\n\nexport const uploadFile = (\n client: Client,\n uploadDetails: { id: string; byte_size: number; type: FileType },\n fileStream: ReadableStream,\n) => {\n log(\"Uploading file\", uploadDetails.id);\n\n const maxSize = MAX_SIZE_BY_TYPE[uploadDetails.type];\n\n return uploadChunks(client, {\n url: `/api/v1/files/${uploadDetails.id}/upload`,\n fileSize: uploadDetails.byte_size,\n fileStream,\n maxSize,\n });\n};\n\nexport const getFileDetail = async (\n client: Client,\n id: string,\n): Promise<FileDetail> => {\n const response = await client.authenticatedFetch(`/api/v1/files/${id}`, {\n method: \"GET\",\n });\n\n if (response.ok) {\n return (await response.json()) as FileDetail;\n }\n\n if (response.status === 404) {\n throw new Error(`File not found: ${id}`);\n }\n\n throw new Error(\n `Failed to get file detail ${response.status} ${response.statusText}`,\n );\n};\n\nexport const lookupFileByMd5 = async (\n client: Client,\n md5: string,\n): Promise<LookupFileByMd5Result | null> => {\n const response = await client.authenticatedFetch(`/api/v1/files/md5/${md5}`, {\n method: \"GET\",\n });\n\n if (response.ok) {\n return (await response.json()) as LookupFileByMd5Result;\n }\n\n if (response.status === 404) {\n return null;\n }\n\n throw new Error(\n `Failed to lookup file by md5 ${md5} ${response.status} ${response.statusText}`,\n );\n};\n\nexport const deleteFile = async (client: Client, id: string) => {\n const response = await client.authenticatedFetch(\n `/api/v1/files/${id}/delete`,\n {\n method: \"POST\",\n },\n );\n\n if (response.ok) {\n return (await response.json()) as { success: boolean };\n }\n\n throw new Error(\n `Failed to delete file ${id} ${response.status} ${response.statusText}`,\n );\n};\n\nexport const getFileProcessingProgress = async (client: Client, id: string) => {\n const eventSource = await client.authenticatedEventSource(\n `/api/v1/files/${id}/progress`,\n );\n\n return new ProgressIterator(eventSource);\n};\n\nexport const transcribeFile = async (\n client: Client,\n id: string,\n options: { trackId?: number } = {},\n): Promise<TranscribeFileResult> => {\n const response = await client.authenticatedFetch(\n `/api/v1/files/${id}/transcribe`,\n {\n method: \"POST\",\n body: JSON.stringify(options),\n },\n );\n\n if (response.ok) {\n return (await response.json()) as TranscribeFileResult;\n }\n\n throw new Error(\n `Failed to transcribe file ${id} ${response.status} ${response.statusText}`,\n );\n};\n\nexport const getFileTranscription = async (\n client: Client,\n id: string,\n): Promise<FileTranscriptionResult | null> => {\n const response = await client.authenticatedFetch(\n `/api/v1/files/${id}/transcription`,\n {\n method: \"GET\",\n },\n );\n\n if (response.ok) {\n return (await response.json()) as FileTranscriptionResult;\n }\n\n if (response.status === 404) {\n return null;\n }\n\n throw new Error(\n `Failed to get file transcription ${id} ${response.status} ${response.statusText}`,\n );\n};\n\nexport type { CreateISOBMFFTrackPayload as CreateFileTrackPayload };\nexport type { CreateISOBMFFTrackResult as CreateFileTrackResult };\n\nexport const createFileTrack = async (\n client: Client,\n fileId: string,\n payload: CreateISOBMFFTrackPayload,\n): Promise<CreateISOBMFFTrackResult> => {\n log(\"Creating file track\", fileId, payload);\n CreateISOBMFFTrackPayload.parse(payload);\n\n const response = await client.authenticatedFetch(\n `/api/v1/files/${fileId}/tracks`,\n {\n method: \"POST\",\n body: JSON.stringify(payload),\n },\n );\n\n log(\"File track created\", response.status, response.statusText);\n\n if (response.ok) {\n return (await response.json()) as CreateISOBMFFTrackResult;\n }\n\n throw new Error(\n `Failed to create file track ${response.status} ${response.statusText}`,\n );\n};\n\nexport const uploadFileTrack = (\n client: Client,\n fileId: string,\n trackId: number,\n byteSize: number,\n fileStream: ReadableStream,\n) => {\n log(\"Uploading file track\", fileId, trackId);\n\n return uploadChunks(client, {\n url: `/api/v1/files/${fileId}/tracks/${trackId}/upload`,\n fileSize: byteSize,\n fileStream,\n maxSize: MAX_VIDEO_SIZE,\n });\n};\n\nconst FRAGMENT_INDEX_SIZE_LIMIT = 1024 * 1024 * 50; // 50MB\n\nexport const uploadFileIndex = async (\n client: Client,\n fileId: string,\n fileStream: ReadableStream,\n fileSize: number,\n) => {\n log(\"Uploading file index\", fileId);\n if (fileSize > FRAGMENT_INDEX_SIZE_LIMIT) {\n throw new Error(\n `Fragment index size ${fileSize} exceeds limit of ${FRAGMENT_INDEX_SIZE_LIMIT} bytes`,\n );\n }\n\n const response = await client.authenticatedFetch(\n `/api/v1/files/${fileId}/index/upload`,\n {\n method: \"POST\",\n body: fileStream,\n duplex: \"half\",\n },\n );\n\n log(\"File index uploaded\", response.status, response.statusText);\n\n if (response.ok) {\n return response.json();\n }\n\n throw new Error(\n `Failed to upload file index ${response.status} ${response.statusText}`,\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_uploadChunks = require('../uploadChunks.cjs');
|
|
3
|
+
let debug = require("debug");
|
|
4
|
+
debug = require_rolldown_runtime.__toESM(debug);
|
|
5
|
+
let zod = require("zod");
|
|
6
|
+
zod = require_rolldown_runtime.__toESM(zod);
|
|
7
|
+
let mime_types = require("mime-types");
|
|
8
|
+
mime_types = require_rolldown_runtime.__toESM(mime_types);
|
|
9
|
+
|
|
10
|
+
//#region src/resources/image-file.ts
|
|
11
|
+
const log = (0, debug.default)("ef:api:image-file");
|
|
12
|
+
const MAX_IMAGE_SIZE = 1024 * 1024 * 16;
|
|
13
|
+
const ImageFileMimeTypes = zod.z.enum([
|
|
14
|
+
"image/jpeg",
|
|
15
|
+
"image/png",
|
|
16
|
+
"image/jpg",
|
|
17
|
+
"image/webp",
|
|
18
|
+
"image/svg+xml"
|
|
19
|
+
]);
|
|
20
|
+
function getFileExtension(path) {
|
|
21
|
+
const match = path.match(/\.([^.]+)$/);
|
|
22
|
+
return match ? match[1] : null;
|
|
23
|
+
}
|
|
24
|
+
const CreateImageFilePayload = zod.z.object({
|
|
25
|
+
md5: zod.z.string().optional(),
|
|
26
|
+
height: zod.z.number().int().optional(),
|
|
27
|
+
width: zod.z.number().int().optional(),
|
|
28
|
+
mime_type: ImageFileMimeTypes.optional(),
|
|
29
|
+
filename: zod.z.string(),
|
|
30
|
+
byte_size: zod.z.number().int().max(MAX_IMAGE_SIZE)
|
|
31
|
+
}).superRefine((data, ctx) => {
|
|
32
|
+
const extension = getFileExtension(data.filename);
|
|
33
|
+
const mimeType = extension ? mime_types.types[extension] : null;
|
|
34
|
+
const parsedMimeType = ImageFileMimeTypes.safeParse(mimeType).data;
|
|
35
|
+
if (parsedMimeType) data.mime_type = parsedMimeType;
|
|
36
|
+
if (!parsedMimeType && !data.mime_type) ctx.addIssue({
|
|
37
|
+
code: zod.z.ZodIssueCode.custom,
|
|
38
|
+
message: "mime_type is required when filename extension doesn't match a known image type",
|
|
39
|
+
path: ["mime_type"]
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
/** @deprecated Use the unified file API from ./file.js instead */
|
|
43
|
+
const createImageFile = async (client, payload) => {
|
|
44
|
+
log("Creating image file", payload);
|
|
45
|
+
CreateImageFilePayload.parse(payload);
|
|
46
|
+
const response = await client.authenticatedFetch("/api/v1/image_files", {
|
|
47
|
+
method: "POST",
|
|
48
|
+
body: JSON.stringify(payload)
|
|
49
|
+
});
|
|
50
|
+
log("Image file created", response);
|
|
51
|
+
if (response.ok) return await response.json();
|
|
52
|
+
throw new Error(`Failed to create file ${response.status} ${response.statusText}`);
|
|
53
|
+
};
|
|
54
|
+
/** @deprecated Use the unified file API from ./file.js instead */
|
|
55
|
+
const uploadImageFile = (client, uploadDetails, fileStream, chunkSizeBytes) => {
|
|
56
|
+
log("Uploading image file", uploadDetails.id);
|
|
57
|
+
return require_uploadChunks.uploadChunks(client, {
|
|
58
|
+
url: `/api/v1/image_files/${uploadDetails.id}/upload`,
|
|
59
|
+
fileSize: uploadDetails.byte_size,
|
|
60
|
+
fileStream,
|
|
61
|
+
maxSize: MAX_IMAGE_SIZE,
|
|
62
|
+
chunkSizeBytes
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
/** @deprecated Use the unified file API from ./file.js instead */
|
|
66
|
+
const getImageFileMetadata = async (client, id) => {
|
|
67
|
+
const response = await client.authenticatedFetch(`/api/v1/image_files/${id}.json`, { method: "GET" });
|
|
68
|
+
if (response.ok) return await response.json();
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
/** @deprecated Use the unified file API from ./file.js instead */
|
|
72
|
+
const lookupImageFileByMd5 = async (client, md5) => {
|
|
73
|
+
const response = await client.authenticatedFetch(`/api/v1/image_files/md5/${md5}`, { method: "GET" });
|
|
74
|
+
log("Image file lookup", response);
|
|
75
|
+
if (response.ok) return await response.json();
|
|
76
|
+
if (response.status === 404) return null;
|
|
77
|
+
throw new Error(`Failed to lookup image by md5 ${md5} ${response.status} ${response.statusText}`);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
exports.CreateImageFilePayload = CreateImageFilePayload;
|
|
82
|
+
exports.ImageFileMimeTypes = ImageFileMimeTypes;
|
|
83
|
+
exports.createImageFile = createImageFile;
|
|
84
|
+
exports.getImageFileMetadata = getImageFileMetadata;
|
|
85
|
+
exports.lookupImageFileByMd5 = lookupImageFileByMd5;
|
|
86
|
+
exports.uploadImageFile = uploadImageFile;
|
|
87
|
+
//# sourceMappingURL=image-file.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-file.cjs","names":["z","types","uploadChunks"],"sources":["../../src/resources/image-file.ts"],"sourcesContent":["import debug from \"debug\";\nimport { types } from \"mime-types\";\nimport { z } from \"zod\";\n\nimport type { Client } from \"../client.js\";\nimport { uploadChunks } from \"../uploadChunks.js\";\n\nconst log = debug(\"ef:api:image-file\");\n\nconst MAX_IMAGE_SIZE = 1024 * 1024 * 16; // 16MB\n\nexport const ImageFileMimeTypes = z.enum([\n \"image/jpeg\",\n \"image/png\",\n \"image/jpg\",\n \"image/webp\",\n \"image/svg+xml\",\n]);\n\nfunction getFileExtension(path: string) {\n const match = path.match(/\\.([^.]+)$/);\n return match ? match[1] : null;\n}\n\nexport const CreateImageFilePayload = z\n .object({\n /**\n * The md5 hash of the image file.\n */\n md5: z.string().optional(),\n /**\n * The height of the image file in pixels.\n */\n height: z.number().int().optional(),\n /**\n * The width of the image file in pixels.\n */\n width: z.number().int().optional(),\n /**\n * The mime type of the image file. Optional if the filename has a known file extension.\n */\n mime_type: ImageFileMimeTypes.optional(),\n /**\n * The filename of the image file.\n */\n filename: z.string(),\n /**\n * The byte size of the image file.\n */\n byte_size: z.number().int().max(MAX_IMAGE_SIZE),\n })\n .superRefine((data, ctx) => {\n const extension = getFileExtension(data.filename);\n const mimeType = extension ? types[extension] : null;\n const parsedMimeType = ImageFileMimeTypes.safeParse(mimeType).data;\n\n if (parsedMimeType) {\n data.mime_type = parsedMimeType;\n }\n\n if (!parsedMimeType && !data.mime_type) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message:\n \"mime_type is required when filename extension doesn't match a known image type\",\n path: [\"mime_type\"],\n });\n }\n });\n\nexport type CreateImageFilePayload = z.infer<typeof CreateImageFilePayload>;\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport interface CreateImageFileResult {\n /**\n * Whether the image file has been fully uploaded.\n */\n complete: boolean | null;\n /**\n * The byte size of the image file.\n */\n byte_size: number;\n /**\n * The id of the image file.\n */\n id: string;\n /**\n * The md5 hash of the image file.\n */\n md5: string | null;\n}\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport interface LookupImageFileByMd5Result {\n /**\n * Whether the image file has been fully uploaded.\n */\n complete: boolean | null;\n /**\n * The byte size of the image file.\n */\n byte_size: number;\n /**\n * The id of the image file.\n */\n id: string;\n /**\n * md5 hash of the image file.\n */\n md5: string | null;\n /**\n * The height of the image file in pixels.\n */\n height: number | null;\n /**\n * The width of the image file in pixels.\n */\n width: number | null;\n}\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport interface GetImageFileMetadataResult extends LookupImageFileByMd5Result {}\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport const createImageFile = async (\n client: Client,\n payload: CreateImageFilePayload,\n) => {\n log(\"Creating image file\", payload);\n CreateImageFilePayload.parse(payload);\n const response = await client.authenticatedFetch(\"/api/v1/image_files\", {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n\n log(\"Image file created\", response);\n\n if (response.ok) {\n return (await response.json()) as CreateImageFileResult;\n }\n\n throw new Error(\n `Failed to create file ${response.status} ${response.statusText}`,\n );\n};\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport const uploadImageFile = (\n client: Client,\n uploadDetails: {\n id: string;\n byte_size: number;\n },\n fileStream: ReadableStream,\n chunkSizeBytes?: number,\n) => {\n log(\"Uploading image file\", uploadDetails.id);\n\n return uploadChunks(client, {\n url: `/api/v1/image_files/${uploadDetails.id}/upload`,\n fileSize: uploadDetails.byte_size,\n fileStream,\n maxSize: MAX_IMAGE_SIZE,\n chunkSizeBytes,\n });\n};\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport const getImageFileMetadata = async (\n client: Client,\n id: string,\n): Promise<GetImageFileMetadataResult | null> => {\n const response = await client.authenticatedFetch(\n `/api/v1/image_files/${id}.json`,\n {\n method: \"GET\",\n },\n );\n\n if (response.ok) {\n return (await response.json()) as LookupImageFileByMd5Result;\n }\n\n return null;\n};\n\n/** @deprecated Use the unified file API from ./file.js instead */\nexport const lookupImageFileByMd5 = async (\n client: Client,\n md5: string,\n): Promise<LookupImageFileByMd5Result | null> => {\n const response = await client.authenticatedFetch(\n `/api/v1/image_files/md5/${md5}`,\n {\n method: \"GET\",\n },\n );\n log(\"Image file lookup\", response);\n\n if (response.ok) {\n return (await response.json()) as LookupImageFileByMd5Result;\n }\n\n if (response.status === 404) {\n return null;\n }\n\n throw new Error(\n `Failed to lookup image by md5 ${md5} ${response.status} ${response.statusText}`,\n );\n};\n"],"mappings":";;;;;;;;;;AAOA,MAAM,yBAAY,oBAAoB;AAEtC,MAAM,iBAAiB,OAAO,OAAO;AAErC,MAAa,qBAAqBA,MAAE,KAAK;CACvC;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,iBAAiB,MAAc;CACtC,MAAM,QAAQ,KAAK,MAAM,aAAa;AACtC,QAAO,QAAQ,MAAM,KAAK;;AAG5B,MAAa,yBAAyBA,MACnC,OAAO;CAIN,KAAKA,MAAE,QAAQ,CAAC,UAAU;CAI1B,QAAQA,MAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;CAInC,OAAOA,MAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;CAIlC,WAAW,mBAAmB,UAAU;CAIxC,UAAUA,MAAE,QAAQ;CAIpB,WAAWA,MAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,eAAe;CAChD,CAAC,CACD,aAAa,MAAM,QAAQ;CAC1B,MAAM,YAAY,iBAAiB,KAAK,SAAS;CACjD,MAAM,WAAW,YAAYC,iBAAM,aAAa;CAChD,MAAM,iBAAiB,mBAAmB,UAAU,SAAS,CAAC;AAE9D,KAAI,eACF,MAAK,YAAY;AAGnB,KAAI,CAAC,kBAAkB,CAAC,KAAK,UAC3B,KAAI,SAAS;EACX,MAAMD,MAAE,aAAa;EACrB,SACE;EACF,MAAM,CAAC,YAAY;EACpB,CAAC;EAEJ;;AAwDJ,MAAa,kBAAkB,OAC7B,QACA,YACG;AACH,KAAI,uBAAuB,QAAQ;AACnC,wBAAuB,MAAM,QAAQ;CACrC,MAAM,WAAW,MAAM,OAAO,mBAAmB,uBAAuB;EACtE,QAAQ;EACR,MAAM,KAAK,UAAU,QAAQ;EAC9B,CAAC;AAEF,KAAI,sBAAsB,SAAS;AAEnC,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,OAAM,IAAI,MACR,yBAAyB,SAAS,OAAO,GAAG,SAAS,aACtD;;;AAIH,MAAa,mBACX,QACA,eAIA,YACA,mBACG;AACH,KAAI,wBAAwB,cAAc,GAAG;AAE7C,QAAOE,kCAAa,QAAQ;EAC1B,KAAK,uBAAuB,cAAc,GAAG;EAC7C,UAAU,cAAc;EACxB;EACA,SAAS;EACT;EACD,CAAC;;;AAIJ,MAAa,uBAAuB,OAClC,QACA,OAC+C;CAC/C,MAAM,WAAW,MAAM,OAAO,mBAC5B,uBAAuB,GAAG,QAC1B,EACE,QAAQ,OACT,CACF;AAED,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,QAAO;;;AAIT,MAAa,uBAAuB,OAClC,QACA,QAC+C;CAC/C,MAAM,WAAW,MAAM,OAAO,mBAC5B,2BAA2B,OAC3B,EACE,QAAQ,OACT,CACF;AACD,KAAI,qBAAqB,SAAS;AAElC,KAAI,SAAS,GACX,QAAQ,MAAM,SAAS,MAAM;AAG/B,KAAI,SAAS,WAAW,IACtB,QAAO;AAGT,OAAM,IAAI,MACR,iCAAiC,IAAI,GAAG,SAAS,OAAO,GAAG,SAAS,aACrE"}
|