@editframe/api 0.15.0-beta.18 → 0.15.0-beta.20
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/index.d.ts +10 -10
- package/dist/index.js +5 -3
- package/dist/node.js +4 -2
- package/dist/resources/image-file.d.ts +53 -15
- package/dist/resources/image-file.js +42 -7
- package/dist/resources/renders.d.ts +1 -0
- package/dist/uploadChunks.js +1 -0
- package/package.json +6 -4
- package/src/resources/image-file.test.ts +23 -0
- package/src/resources/image-file.ts +95 -26
- package/src/resources/renders.ts +1 -0
- package/types.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { createCaptionFile, CreateCaptionFilePayload,
|
|
2
|
-
export { createImageFile, CreateImageFilePayload, type CreateImageFileResult,
|
|
3
|
-
export { createISOBMFFFile, CreateISOBMFFFilePayload,
|
|
4
|
-
export { createISOBMFFTrack, CreateISOBMFFTrackPayload,
|
|
5
|
-
export { createRender, CreateRenderPayload, type CreateRenderResult, uploadRender, type LookupRenderByMd5Result, lookupRenderByMd5, getRenderProgress, getRenderInfo, downloadRender, } from './resources/renders.js';
|
|
6
|
-
export { createTranscription, CreateTranscriptionPayload, type CreateTranscriptionResult, getTranscriptionInfo, getTranscriptionProgress, type TranscriptionInfoResult, } from './resources/transcriptions.js';
|
|
7
|
-
export { createURLToken, type URLTokenResult, } from './resources/url-token.js';
|
|
8
|
-
export { createUnprocessedFile, CreateUnprocessedFilePayload, type CreateUnprocessedFileResult, uploadUnprocessedReadableStream, type LookupUnprocessedFileByMd5Result, lookupUnprocessedFileByMd5, processIsobmffFile, type ProcessIsobmffFileResult, type UnprocessedFileUploadDetails, type UnprocessedFile, } from './resources/unprocessed-file.js';
|
|
1
|
+
export { createCaptionFile, CreateCaptionFilePayload, lookupCaptionFileByMd5, uploadCaptionFile, type CreateCaptionFileResult, type LookupCaptionFileByMd5Result, } from './resources/caption-file.js';
|
|
2
|
+
export { createImageFile, CreateImageFilePayload, getImageFileMetadata, ImageFileMimeTypes, lookupImageFileByMd5, uploadImageFile, type CreateImageFileResult, type GetImageFileMetadataResult, type LookupImageFileByMd5Result, } from './resources/image-file.js';
|
|
3
|
+
export { createISOBMFFFile, CreateISOBMFFFilePayload, getISOBMFFFileTranscription, lookupISOBMFFFileByMd5, transcribeISOBMFFFile, TranscribeISOBMFFFilePayload, uploadFragmentIndex, type CreateISOBMFFFileResult, type GetISOBMFFFileTranscriptionResult, type LookupISOBMFFFileByMd5Result, type TranscribeISOBMFFFileResult, } from './resources/isobmff-file.js';
|
|
4
|
+
export { AudioTrackPayload, createISOBMFFTrack, CreateISOBMFFTrackPayload, uploadISOBMFFTrack, VideoTrackPayload, type AudioStreamSchema, type CreateISOBMFFTrackResult, type VideoStreamSchema, } from './resources/isobmff-track.js';
|
|
9
5
|
export { getIsobmffProcessInfo, getIsobmffProcessProgress, type IsobmffProcessInfoResult, } from './resources/process-isobmff.js';
|
|
6
|
+
export { createRender, CreateRenderPayload, downloadRender, getRenderInfo, getRenderProgress, lookupRenderByMd5, uploadRender, type CreateRenderResult, type LookupRenderByMd5Result, } from './resources/renders.js';
|
|
7
|
+
export { createTranscription, CreateTranscriptionPayload, getTranscriptionInfo, getTranscriptionProgress, type CreateTranscriptionResult, type TranscriptionInfoResult, } from './resources/transcriptions.js';
|
|
8
|
+
export { createUnprocessedFile, CreateUnprocessedFilePayload, lookupUnprocessedFileByMd5, processIsobmffFile, uploadUnprocessedReadableStream, type CreateUnprocessedFileResult, type LookupUnprocessedFileByMd5Result, type ProcessIsobmffFileResult, type UnprocessedFile, type UnprocessedFileUploadDetails, } from './resources/unprocessed-file.js';
|
|
9
|
+
export { createURLToken, type URLTokenResult, } from './resources/url-token.js';
|
|
10
10
|
export { Client } from './client.js';
|
|
11
|
+
export type { CompletionIterator, ProgressIterator, } from './ProgressIterator.js';
|
|
11
12
|
export type { IteratorWithPromise, UploadChunkEvent } from './uploadChunks.js';
|
|
12
|
-
export type {
|
|
13
|
-
export type { StreamEventSource, ProgressEvent, CompletionEvent, StreamEventSourceEventMap, EventCallback, } from './StreamEventSource.js';
|
|
13
|
+
export type { CompletionEvent, EventCallback, ProgressEvent, StreamEventSource, StreamEventSourceEventMap, } from './StreamEventSource.js';
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CreateCaptionFilePayload, createCaptionFile, lookupCaptionFileByMd5, uploadCaptionFile } from "./resources/caption-file.js";
|
|
2
|
-
import { CreateImageFilePayload, createImageFile, lookupImageFileByMd5, uploadImageFile } from "./resources/image-file.js";
|
|
2
|
+
import { CreateImageFilePayload, ImageFileMimeTypes, createImageFile, getImageFileMetadata, lookupImageFileByMd5, uploadImageFile } from "./resources/image-file.js";
|
|
3
3
|
import { CreateISOBMFFFilePayload, TranscribeISOBMFFFilePayload, createISOBMFFFile, getISOBMFFFileTranscription, lookupISOBMFFFileByMd5, transcribeISOBMFFFile, uploadFragmentIndex } from "./resources/isobmff-file.js";
|
|
4
4
|
import { AudioTrackPayload, CreateISOBMFFTrackPayload, VideoTrackPayload, createISOBMFFTrack, uploadISOBMFFTrack } from "./resources/isobmff-track.js";
|
|
5
|
+
import { getIsobmffProcessInfo, getIsobmffProcessProgress } from "./resources/process-isobmff.js";
|
|
5
6
|
import { CreateRenderPayload, createRender, downloadRender, getRenderInfo, getRenderProgress, lookupRenderByMd5, uploadRender } from "./resources/renders.js";
|
|
6
7
|
import { CreateTranscriptionPayload, createTranscription, getTranscriptionInfo, getTranscriptionProgress } from "./resources/transcriptions.js";
|
|
7
|
-
import { createURLToken } from "./resources/url-token.js";
|
|
8
8
|
import { CreateUnprocessedFilePayload, createUnprocessedFile, lookupUnprocessedFileByMd5, processIsobmffFile, uploadUnprocessedReadableStream } from "./resources/unprocessed-file.js";
|
|
9
|
-
import {
|
|
9
|
+
import { createURLToken } from "./resources/url-token.js";
|
|
10
10
|
import { Client } from "./client.js";
|
|
11
11
|
export {
|
|
12
12
|
AudioTrackPayload,
|
|
@@ -18,6 +18,7 @@ export {
|
|
|
18
18
|
CreateRenderPayload,
|
|
19
19
|
CreateTranscriptionPayload,
|
|
20
20
|
CreateUnprocessedFilePayload,
|
|
21
|
+
ImageFileMimeTypes,
|
|
21
22
|
TranscribeISOBMFFFilePayload,
|
|
22
23
|
VideoTrackPayload,
|
|
23
24
|
createCaptionFile,
|
|
@@ -30,6 +31,7 @@ export {
|
|
|
30
31
|
createUnprocessedFile,
|
|
31
32
|
downloadRender,
|
|
32
33
|
getISOBMFFFileTranscription,
|
|
34
|
+
getImageFileMetadata,
|
|
33
35
|
getIsobmffProcessInfo,
|
|
34
36
|
getIsobmffProcessProgress,
|
|
35
37
|
getRenderInfo,
|
package/dist/node.js
CHANGED
|
@@ -3,17 +3,17 @@ import { basename } from "node:path";
|
|
|
3
3
|
import mime from "mime";
|
|
4
4
|
import { md5FilePath } from "@editframe/assets";
|
|
5
5
|
import { createImageFile, CreateImageFilePayload } from "./resources/image-file.js";
|
|
6
|
-
import { lookupImageFileByMd5, uploadImageFile } from "./resources/image-file.js";
|
|
6
|
+
import { ImageFileMimeTypes, getImageFileMetadata, lookupImageFileByMd5, uploadImageFile } from "./resources/image-file.js";
|
|
7
7
|
import { createUnprocessedFile, uploadUnprocessedReadableStream } from "./resources/unprocessed-file.js";
|
|
8
8
|
import { CreateUnprocessedFilePayload, lookupUnprocessedFileByMd5, processIsobmffFile } from "./resources/unprocessed-file.js";
|
|
9
9
|
import { createReadableStreamFromReadable } from "./utils/createReadableStreamFromReadable.js";
|
|
10
10
|
import { CreateCaptionFilePayload, createCaptionFile, lookupCaptionFileByMd5, uploadCaptionFile } from "./resources/caption-file.js";
|
|
11
11
|
import { CreateISOBMFFFilePayload, TranscribeISOBMFFFilePayload, createISOBMFFFile, getISOBMFFFileTranscription, lookupISOBMFFFileByMd5, transcribeISOBMFFFile, uploadFragmentIndex } from "./resources/isobmff-file.js";
|
|
12
12
|
import { AudioTrackPayload, CreateISOBMFFTrackPayload, VideoTrackPayload, createISOBMFFTrack, uploadISOBMFFTrack } from "./resources/isobmff-track.js";
|
|
13
|
+
import { getIsobmffProcessInfo, getIsobmffProcessProgress } from "./resources/process-isobmff.js";
|
|
13
14
|
import { CreateRenderPayload, createRender, downloadRender, getRenderInfo, getRenderProgress, lookupRenderByMd5, uploadRender } from "./resources/renders.js";
|
|
14
15
|
import { CreateTranscriptionPayload, createTranscription, getTranscriptionInfo, getTranscriptionProgress } from "./resources/transcriptions.js";
|
|
15
16
|
import { createURLToken } from "./resources/url-token.js";
|
|
16
|
-
import { getIsobmffProcessInfo, getIsobmffProcessProgress } from "./resources/process-isobmff.js";
|
|
17
17
|
import { Client } from "./client.js";
|
|
18
18
|
const createImageFileFromPath = async (client, path) => {
|
|
19
19
|
const fileInfo = await stat(path);
|
|
@@ -61,6 +61,7 @@ export {
|
|
|
61
61
|
CreateRenderPayload,
|
|
62
62
|
CreateTranscriptionPayload,
|
|
63
63
|
CreateUnprocessedFilePayload,
|
|
64
|
+
ImageFileMimeTypes,
|
|
64
65
|
TranscribeISOBMFFFilePayload,
|
|
65
66
|
VideoTrackPayload,
|
|
66
67
|
createCaptionFile,
|
|
@@ -76,6 +77,7 @@ export {
|
|
|
76
77
|
createUnprocessedFileFromPath,
|
|
77
78
|
downloadRender,
|
|
78
79
|
getISOBMFFFileTranscription,
|
|
80
|
+
getImageFileMetadata,
|
|
79
81
|
getIsobmffProcessInfo,
|
|
80
82
|
getIsobmffProcessProgress,
|
|
81
83
|
getRenderInfo,
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Client } from '../client.js';
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const ImageFileMimeTypes: z.ZodEnum<["image/jpeg", "image/png", "image/jpg", "image/webp"]>;
|
|
4
|
+
export declare const CreateImageFilePayload: z.ZodEffects<z.ZodObject<{
|
|
4
5
|
/**
|
|
5
6
|
* The md5 hash of the image file.
|
|
6
7
|
*/
|
|
7
|
-
md5: z.
|
|
8
|
+
md5: z.ZodOptional<z.ZodString>;
|
|
8
9
|
/**
|
|
9
10
|
* The height of the image file in pixels.
|
|
10
11
|
*/
|
|
11
|
-
height: z.
|
|
12
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
12
13
|
/**
|
|
13
14
|
* The width of the image file in pixels.
|
|
14
15
|
*/
|
|
15
|
-
width: z.
|
|
16
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
16
17
|
/**
|
|
17
|
-
* The mime type of the image file.
|
|
18
|
+
* The mime type of the image file. Optional if the filename has a known file extension.
|
|
18
19
|
*/
|
|
19
|
-
mime_type: z.ZodEnum<["image/jpeg", "image/png", "image/jpg", "image/webp"]
|
|
20
|
+
mime_type: z.ZodOptional<z.ZodEnum<["image/jpeg", "image/png", "image/jpg", "image/webp"]>>;
|
|
20
21
|
/**
|
|
21
22
|
* The filename of the image file.
|
|
22
23
|
*/
|
|
@@ -26,19 +27,33 @@ export declare const CreateImageFilePayload: z.ZodObject<{
|
|
|
26
27
|
*/
|
|
27
28
|
byte_size: z.ZodNumber;
|
|
28
29
|
}, "strip", z.ZodTypeAny, {
|
|
29
|
-
width: number | null;
|
|
30
|
-
height: number | null;
|
|
31
30
|
filename: string;
|
|
32
|
-
md5: string | null;
|
|
33
|
-
mime_type: "image/jpeg" | "image/png" | "image/jpg" | "image/webp";
|
|
34
31
|
byte_size: number;
|
|
32
|
+
width?: number | undefined;
|
|
33
|
+
height?: number | undefined;
|
|
34
|
+
md5?: string | undefined;
|
|
35
|
+
mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
|
|
35
36
|
}, {
|
|
36
|
-
width: number | null;
|
|
37
|
-
height: number | null;
|
|
38
37
|
filename: string;
|
|
39
|
-
md5: string | null;
|
|
40
|
-
mime_type: "image/jpeg" | "image/png" | "image/jpg" | "image/webp";
|
|
41
38
|
byte_size: number;
|
|
39
|
+
width?: number | undefined;
|
|
40
|
+
height?: number | undefined;
|
|
41
|
+
md5?: string | undefined;
|
|
42
|
+
mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
|
|
43
|
+
}>, {
|
|
44
|
+
filename: string;
|
|
45
|
+
byte_size: number;
|
|
46
|
+
width?: number | undefined;
|
|
47
|
+
height?: number | undefined;
|
|
48
|
+
md5?: string | undefined;
|
|
49
|
+
mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
filename: string;
|
|
52
|
+
byte_size: number;
|
|
53
|
+
width?: number | undefined;
|
|
54
|
+
height?: number | undefined;
|
|
55
|
+
md5?: string | undefined;
|
|
56
|
+
mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
|
|
42
57
|
}>;
|
|
43
58
|
export type CreateImageFilePayload = z.infer<typeof CreateImageFilePayload>;
|
|
44
59
|
export interface CreateImageFileResult {
|
|
@@ -60,14 +75,37 @@ export interface CreateImageFileResult {
|
|
|
60
75
|
md5: string | null;
|
|
61
76
|
}
|
|
62
77
|
export interface LookupImageFileByMd5Result {
|
|
78
|
+
/**
|
|
79
|
+
* Whether the image file has been fully uploaded.
|
|
80
|
+
*/
|
|
63
81
|
complete: boolean | null;
|
|
82
|
+
/**
|
|
83
|
+
* The byte size of the image file.
|
|
84
|
+
*/
|
|
64
85
|
byte_size: number;
|
|
86
|
+
/**
|
|
87
|
+
* The id of the image file.
|
|
88
|
+
*/
|
|
65
89
|
id: string;
|
|
90
|
+
/**
|
|
91
|
+
* md5 hash of the image file.
|
|
92
|
+
*/
|
|
66
93
|
md5: string | null;
|
|
94
|
+
/**
|
|
95
|
+
* The height of the image file in pixels.
|
|
96
|
+
*/
|
|
97
|
+
height: number | null;
|
|
98
|
+
/**
|
|
99
|
+
* The width of the image file in pixels.
|
|
100
|
+
*/
|
|
101
|
+
width: number | null;
|
|
102
|
+
}
|
|
103
|
+
export interface GetImageFileMetadataResult extends LookupImageFileByMd5Result {
|
|
67
104
|
}
|
|
68
105
|
export declare const createImageFile: (client: Client, payload: CreateImageFilePayload) => Promise<CreateImageFileResult>;
|
|
69
106
|
export declare const uploadImageFile: (client: Client, uploadDetails: {
|
|
70
107
|
id: string;
|
|
71
108
|
byte_size: number;
|
|
72
|
-
}, fileStream: ReadableStream) => import('../uploadChunks.js').IteratorWithPromise<import('../uploadChunks.js').UploadChunkEvent>;
|
|
109
|
+
}, fileStream: ReadableStream, chunkSizeBytes?: number) => import('../uploadChunks.js').IteratorWithPromise<import('../uploadChunks.js').UploadChunkEvent>;
|
|
110
|
+
export declare const getImageFileMetadata: (client: Client, id: string) => Promise<GetImageFileMetadataResult | null>;
|
|
73
111
|
export declare const lookupImageFileByMd5: (client: Client, md5: string) => Promise<LookupImageFileByMd5Result | null>;
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
|
+
import mime from "mime-types";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { uploadChunks } from "../uploadChunks.js";
|
|
4
5
|
const log = debug("ef:api:image-file");
|
|
5
6
|
const MAX_IMAGE_SIZE = 1024 * 1024 * 16;
|
|
7
|
+
const ImageFileMimeTypes = z.enum([
|
|
8
|
+
"image/jpeg",
|
|
9
|
+
"image/png",
|
|
10
|
+
"image/jpg",
|
|
11
|
+
"image/webp"
|
|
12
|
+
]);
|
|
6
13
|
const CreateImageFilePayload = z.object({
|
|
7
14
|
/**
|
|
8
15
|
* The md5 hash of the image file.
|
|
9
16
|
*/
|
|
10
|
-
md5: z.string().
|
|
17
|
+
md5: z.string().optional(),
|
|
11
18
|
/**
|
|
12
19
|
* The height of the image file in pixels.
|
|
13
20
|
*/
|
|
14
|
-
height: z.number().int().
|
|
21
|
+
height: z.number().int().optional(),
|
|
15
22
|
/**
|
|
16
23
|
* The width of the image file in pixels.
|
|
17
24
|
*/
|
|
18
|
-
width: z.number().int().
|
|
25
|
+
width: z.number().int().optional(),
|
|
19
26
|
/**
|
|
20
|
-
* The mime type of the image file.
|
|
27
|
+
* The mime type of the image file. Optional if the filename has a known file extension.
|
|
21
28
|
*/
|
|
22
|
-
mime_type:
|
|
29
|
+
mime_type: ImageFileMimeTypes.optional(),
|
|
23
30
|
/**
|
|
24
31
|
* The filename of the image file.
|
|
25
32
|
*/
|
|
@@ -28,6 +35,19 @@ const CreateImageFilePayload = z.object({
|
|
|
28
35
|
* The byte size of the image file.
|
|
29
36
|
*/
|
|
30
37
|
byte_size: z.number().int().max(MAX_IMAGE_SIZE)
|
|
38
|
+
}).superRefine((data, ctx) => {
|
|
39
|
+
const mimeType = mime.lookup(data.filename);
|
|
40
|
+
const parsedMimeType = ImageFileMimeTypes.safeParse(mimeType).data;
|
|
41
|
+
if (parsedMimeType) {
|
|
42
|
+
data.mime_type = parsedMimeType;
|
|
43
|
+
}
|
|
44
|
+
if (!parsedMimeType && !data.mime_type) {
|
|
45
|
+
ctx.addIssue({
|
|
46
|
+
code: z.ZodIssueCode.custom,
|
|
47
|
+
message: "mime_type is required when filename extension doesn't match a known image type",
|
|
48
|
+
path: ["mime_type"]
|
|
49
|
+
});
|
|
50
|
+
}
|
|
31
51
|
});
|
|
32
52
|
const createImageFile = async (client, payload) => {
|
|
33
53
|
log("Creating image file", payload);
|
|
@@ -44,15 +64,28 @@ const createImageFile = async (client, payload) => {
|
|
|
44
64
|
`Failed to create file ${response.status} ${response.statusText}`
|
|
45
65
|
);
|
|
46
66
|
};
|
|
47
|
-
const uploadImageFile = (client, uploadDetails, fileStream) => {
|
|
67
|
+
const uploadImageFile = (client, uploadDetails, fileStream, chunkSizeBytes) => {
|
|
48
68
|
log("Uploading image file", uploadDetails.id);
|
|
49
69
|
return uploadChunks(client, {
|
|
50
70
|
url: `/api/v1/image_files/${uploadDetails.id}/upload`,
|
|
51
71
|
fileSize: uploadDetails.byte_size,
|
|
52
72
|
fileStream,
|
|
53
|
-
maxSize: MAX_IMAGE_SIZE
|
|
73
|
+
maxSize: MAX_IMAGE_SIZE,
|
|
74
|
+
chunkSizeBytes
|
|
54
75
|
});
|
|
55
76
|
};
|
|
77
|
+
const getImageFileMetadata = async (client, id) => {
|
|
78
|
+
const response = await client.authenticatedFetch(
|
|
79
|
+
`/api/v1/image_files/${id}.json`,
|
|
80
|
+
{
|
|
81
|
+
method: "GET"
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
if (response.ok) {
|
|
85
|
+
return await response.json();
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
};
|
|
56
89
|
const lookupImageFileByMd5 = async (client, md5) => {
|
|
57
90
|
const response = await client.authenticatedFetch(
|
|
58
91
|
`/api/v1/image_files/md5/${md5}`,
|
|
@@ -73,7 +106,9 @@ const lookupImageFileByMd5 = async (client, md5) => {
|
|
|
73
106
|
};
|
|
74
107
|
export {
|
|
75
108
|
CreateImageFilePayload,
|
|
109
|
+
ImageFileMimeTypes,
|
|
76
110
|
createImageFile,
|
|
111
|
+
getImageFileMetadata,
|
|
77
112
|
lookupImageFileByMd5,
|
|
78
113
|
uploadImageFile
|
|
79
114
|
};
|
|
@@ -53,6 +53,7 @@ export interface LookupRenderByMd5Result {
|
|
|
53
53
|
id: string;
|
|
54
54
|
md5: string | null;
|
|
55
55
|
status: "complete" | "created" | "failed" | "pending" | "rendering" | string;
|
|
56
|
+
metadata: Record<string, string>;
|
|
56
57
|
}
|
|
57
58
|
export declare const createRender: (client: Client, payload: CreateRenderPayload) => Promise<CreateRenderResult>;
|
|
58
59
|
export declare const uploadRender: (client: Client, renderId: string, fileStream: ReadableStream) => Promise<any>;
|
package/dist/uploadChunks.js
CHANGED
|
@@ -49,6 +49,7 @@ function uploadChunks(client, {
|
|
|
49
49
|
}
|
|
50
50
|
log("Checking upload status", url);
|
|
51
51
|
const uploadStatus = await client.authenticatedFetch(url);
|
|
52
|
+
console.log("UPLOAD STATUS", url, uploadStatus);
|
|
52
53
|
yield { type: "progress", progress: 0 };
|
|
53
54
|
if (uploadStatus.status === 200) {
|
|
54
55
|
log("Chunk already uploaded");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/api",
|
|
3
|
-
"version": "0.15.0-beta.
|
|
3
|
+
"version": "0.15.0-beta.20",
|
|
4
4
|
"description": "API functions for EditFrame",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -38,23 +38,25 @@
|
|
|
38
38
|
"license": "UNLICENSED",
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/jsonwebtoken": "^9.0.6",
|
|
41
|
+
"@types/mime-types": "^2.1.4",
|
|
41
42
|
"@types/node": "^20.14.13",
|
|
42
43
|
"typedoc": "^0.26.5",
|
|
43
44
|
"typescript": "^5.5.4",
|
|
44
45
|
"vite-plugin-dts": "^4.0.3"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@editframe/assets": "0.15.0-beta.
|
|
48
|
+
"@editframe/assets": "0.15.0-beta.20",
|
|
48
49
|
"@vitejs/plugin-react": "^4.3.4",
|
|
49
|
-
"vite-tsconfig-paths": "^4.3.2",
|
|
50
|
-
"vite": "^5.4.11",
|
|
51
50
|
"debug": "^4.3.5",
|
|
52
51
|
"eventsource-parser": "^3.0.0",
|
|
53
52
|
"jsonwebtoken": "^9.0.2",
|
|
54
53
|
"mime": "^4.0.4",
|
|
54
|
+
"mime-types": "^2.1.35",
|
|
55
55
|
"node-fetch": "^3.3.2",
|
|
56
56
|
"tar": "^7.4.3",
|
|
57
|
+
"vite": "^5.4.11",
|
|
57
58
|
"vite-plugin-singlefile": "^2.1.0",
|
|
59
|
+
"vite-tsconfig-paths": "^4.3.2",
|
|
58
60
|
"zod": "^3.23.8"
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -6,6 +6,7 @@ import { ZodError } from "zod";
|
|
|
6
6
|
import { Client } from "../client.js";
|
|
7
7
|
import { webReadableFromBuffers } from "../readableFromBuffers.js";
|
|
8
8
|
import {
|
|
9
|
+
CreateImageFilePayload,
|
|
9
10
|
createImageFile,
|
|
10
11
|
lookupImageFileByMd5,
|
|
11
12
|
uploadImageFile,
|
|
@@ -19,6 +20,28 @@ const UploadMustContinue = (id = "test-file") =>
|
|
|
19
20
|
HttpResponse.json({}, { status: 202 }),
|
|
20
21
|
);
|
|
21
22
|
|
|
23
|
+
describe("CreateImageFilePayload", () => {
|
|
24
|
+
test("parses mime type from filename", () => {
|
|
25
|
+
const payload = CreateImageFilePayload.parse({
|
|
26
|
+
byte_size: 100,
|
|
27
|
+
filename: "test.jpg",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(payload.mime_type).toBe("image/jpeg");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("rejects unsupported mime types", () => {
|
|
34
|
+
const payload = CreateImageFilePayload.safeParse({
|
|
35
|
+
byte_size: 100,
|
|
36
|
+
filename: "test.txt",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(
|
|
40
|
+
payload.error?.issues.some((issue) => issue.path.includes("mime_type")),
|
|
41
|
+
).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
22
45
|
describe("ImageFile", () => {
|
|
23
46
|
beforeAll(() => server.listen());
|
|
24
47
|
afterEach(() => server.resetHandlers());
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
|
+
import mime from "mime-types";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
|
|
4
5
|
import type { Client } from "../client.js";
|
|
@@ -8,32 +9,57 @@ const log = debug("ef:api:image-file");
|
|
|
8
9
|
|
|
9
10
|
const MAX_IMAGE_SIZE = 1024 * 1024 * 16; // 16MB
|
|
10
11
|
|
|
11
|
-
export const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
12
|
+
export const ImageFileMimeTypes = z.enum([
|
|
13
|
+
"image/jpeg",
|
|
14
|
+
"image/png",
|
|
15
|
+
"image/jpg",
|
|
16
|
+
"image/webp",
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
export const CreateImageFilePayload = z
|
|
20
|
+
.object({
|
|
21
|
+
/**
|
|
22
|
+
* The md5 hash of the image file.
|
|
23
|
+
*/
|
|
24
|
+
md5: z.string().optional(),
|
|
25
|
+
/**
|
|
26
|
+
* The height of the image file in pixels.
|
|
27
|
+
*/
|
|
28
|
+
height: z.number().int().optional(),
|
|
29
|
+
/**
|
|
30
|
+
* The width of the image file in pixels.
|
|
31
|
+
*/
|
|
32
|
+
width: z.number().int().optional(),
|
|
33
|
+
/**
|
|
34
|
+
* The mime type of the image file. Optional if the filename has a known file extension.
|
|
35
|
+
*/
|
|
36
|
+
mime_type: ImageFileMimeTypes.optional(),
|
|
37
|
+
/**
|
|
38
|
+
* The filename of the image file.
|
|
39
|
+
*/
|
|
40
|
+
filename: z.string(),
|
|
41
|
+
/**
|
|
42
|
+
* The byte size of the image file.
|
|
43
|
+
*/
|
|
44
|
+
byte_size: z.number().int().max(MAX_IMAGE_SIZE),
|
|
45
|
+
})
|
|
46
|
+
.superRefine((data, ctx) => {
|
|
47
|
+
const mimeType = mime.lookup(data.filename);
|
|
48
|
+
const parsedMimeType = ImageFileMimeTypes.safeParse(mimeType).data;
|
|
49
|
+
|
|
50
|
+
if (parsedMimeType) {
|
|
51
|
+
data.mime_type = parsedMimeType;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!parsedMimeType && !data.mime_type) {
|
|
55
|
+
ctx.addIssue({
|
|
56
|
+
code: z.ZodIssueCode.custom,
|
|
57
|
+
message:
|
|
58
|
+
"mime_type is required when filename extension doesn't match a known image type",
|
|
59
|
+
path: ["mime_type"],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
37
63
|
|
|
38
64
|
export type CreateImageFilePayload = z.infer<typeof CreateImageFilePayload>;
|
|
39
65
|
|
|
@@ -57,12 +83,35 @@ export interface CreateImageFileResult {
|
|
|
57
83
|
}
|
|
58
84
|
|
|
59
85
|
export interface LookupImageFileByMd5Result {
|
|
86
|
+
/**
|
|
87
|
+
* Whether the image file has been fully uploaded.
|
|
88
|
+
*/
|
|
60
89
|
complete: boolean | null;
|
|
90
|
+
/**
|
|
91
|
+
* The byte size of the image file.
|
|
92
|
+
*/
|
|
61
93
|
byte_size: number;
|
|
94
|
+
/**
|
|
95
|
+
* The id of the image file.
|
|
96
|
+
*/
|
|
62
97
|
id: string;
|
|
98
|
+
/**
|
|
99
|
+
* md5 hash of the image file.
|
|
100
|
+
*/
|
|
63
101
|
md5: string | null;
|
|
102
|
+
/**
|
|
103
|
+
* The height of the image file in pixels.
|
|
104
|
+
*/
|
|
105
|
+
height: number | null;
|
|
106
|
+
/**
|
|
107
|
+
* The width of the image file in pixels.
|
|
108
|
+
*/
|
|
109
|
+
width: number | null;
|
|
64
110
|
}
|
|
65
111
|
|
|
112
|
+
export interface GetImageFileMetadataResult
|
|
113
|
+
extends LookupImageFileByMd5Result {}
|
|
114
|
+
|
|
66
115
|
export const createImageFile = async (
|
|
67
116
|
client: Client,
|
|
68
117
|
payload: CreateImageFilePayload,
|
|
@@ -92,6 +141,7 @@ export const uploadImageFile = (
|
|
|
92
141
|
byte_size: number;
|
|
93
142
|
},
|
|
94
143
|
fileStream: ReadableStream,
|
|
144
|
+
chunkSizeBytes?: number,
|
|
95
145
|
) => {
|
|
96
146
|
log("Uploading image file", uploadDetails.id);
|
|
97
147
|
|
|
@@ -100,9 +150,28 @@ export const uploadImageFile = (
|
|
|
100
150
|
fileSize: uploadDetails.byte_size,
|
|
101
151
|
fileStream,
|
|
102
152
|
maxSize: MAX_IMAGE_SIZE,
|
|
153
|
+
chunkSizeBytes,
|
|
103
154
|
});
|
|
104
155
|
};
|
|
105
156
|
|
|
157
|
+
export const getImageFileMetadata = async (
|
|
158
|
+
client: Client,
|
|
159
|
+
id: string,
|
|
160
|
+
): Promise<GetImageFileMetadataResult | null> => {
|
|
161
|
+
const response = await client.authenticatedFetch(
|
|
162
|
+
`/api/v1/image_files/${id}.json`,
|
|
163
|
+
{
|
|
164
|
+
method: "GET",
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
if (response.ok) {
|
|
169
|
+
return (await response.json()) as LookupImageFileByMd5Result;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return null;
|
|
173
|
+
};
|
|
174
|
+
|
|
106
175
|
export const lookupImageFileByMd5 = async (
|
|
107
176
|
client: Client,
|
|
108
177
|
md5: string,
|
package/src/resources/renders.ts
CHANGED