@editframe/api 0.15.0-beta.17 → 0.15.0-beta.19

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  export { createCaptionFile, CreateCaptionFilePayload, type CreateCaptionFileResult, uploadCaptionFile, type LookupCaptionFileByMd5Result, lookupCaptionFileByMd5, } from './resources/caption-file.js';
2
- export { createImageFile, CreateImageFilePayload, type CreateImageFileResult, uploadImageFile, type LookupImageFileByMd5Result, lookupImageFileByMd5, } from './resources/image-file.js';
2
+ export { createImageFile, CreateImageFilePayload, type CreateImageFileResult, uploadImageFile, type LookupImageFileByMd5Result, lookupImageFileByMd5, type GetImageFileMetadataResult, getImageFileMetadata, } from './resources/image-file.js';
3
3
  export { createISOBMFFFile, CreateISOBMFFFilePayload, type CreateISOBMFFFileResult, uploadFragmentIndex, type LookupISOBMFFFileByMd5Result, lookupISOBMFFFileByMd5, type GetISOBMFFFileTranscriptionResult, getISOBMFFFileTranscription, type TranscribeISOBMFFFileResult, transcribeISOBMFFFile, TranscribeISOBMFFFilePayload, } from './resources/isobmff-file.js';
4
4
  export { createISOBMFFTrack, CreateISOBMFFTrackPayload, type CreateISOBMFFTrackResult, uploadISOBMFFTrack, AudioTrackPayload, type AudioStreamSchema, VideoTrackPayload, type VideoStreamSchema, } from './resources/isobmff-track.js';
5
5
  export { createRender, CreateRenderPayload, type CreateRenderResult, uploadRender, type LookupRenderByMd5Result, lookupRenderByMd5, getRenderProgress, getRenderInfo, downloadRender, } from './resources/renders.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
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, 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
5
  import { CreateRenderPayload, createRender, downloadRender, getRenderInfo, getRenderProgress, lookupRenderByMd5, uploadRender } from "./resources/renders.js";
@@ -30,6 +30,7 @@ export {
30
30
  createUnprocessedFile,
31
31
  downloadRender,
32
32
  getISOBMFFFileTranscription,
33
+ getImageFileMetadata,
33
34
  getIsobmffProcessInfo,
34
35
  getIsobmffProcessProgress,
35
36
  getRenderInfo,
package/dist/node.js CHANGED
@@ -3,7 +3,7 @@ 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 { 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";
@@ -76,6 +76,7 @@ export {
76
76
  createUnprocessedFileFromPath,
77
77
  downloadRender,
78
78
  getISOBMFFFileTranscription,
79
+ getImageFileMetadata,
79
80
  getIsobmffProcessInfo,
80
81
  getIsobmffProcessProgress,
81
82
  getRenderInfo,
@@ -1,22 +1,22 @@
1
1
  import { z } from 'zod';
2
2
  import { Client } from '../client.js';
3
- export declare const CreateImageFilePayload: z.ZodObject<{
3
+ export declare const CreateImageFilePayload: z.ZodEffects<z.ZodObject<{
4
4
  /**
5
5
  * The md5 hash of the image file.
6
6
  */
7
- md5: z.ZodNullable<z.ZodString>;
7
+ md5: z.ZodOptional<z.ZodString>;
8
8
  /**
9
9
  * The height of the image file in pixels.
10
10
  */
11
- height: z.ZodNullable<z.ZodNumber>;
11
+ height: z.ZodOptional<z.ZodNumber>;
12
12
  /**
13
13
  * The width of the image file in pixels.
14
14
  */
15
- width: z.ZodNullable<z.ZodNumber>;
15
+ width: z.ZodOptional<z.ZodNumber>;
16
16
  /**
17
- * The mime type of the image file.
17
+ * The mime type of the image file. Optional if the filename has a known file extension.
18
18
  */
19
- mime_type: z.ZodEnum<["image/jpeg", "image/png", "image/jpg", "image/webp"]>;
19
+ mime_type: z.ZodOptional<z.ZodEnum<["image/jpeg", "image/png", "image/jpg", "image/webp"]>>;
20
20
  /**
21
21
  * The filename of the image file.
22
22
  */
@@ -26,19 +26,33 @@ export declare const CreateImageFilePayload: z.ZodObject<{
26
26
  */
27
27
  byte_size: z.ZodNumber;
28
28
  }, "strip", z.ZodTypeAny, {
29
- width: number | null;
30
- height: number | null;
31
29
  filename: string;
32
- md5: string | null;
33
- mime_type: "image/jpeg" | "image/png" | "image/jpg" | "image/webp";
34
30
  byte_size: number;
31
+ width?: number | undefined;
32
+ height?: number | undefined;
33
+ md5?: string | undefined;
34
+ mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
35
35
  }, {
36
- width: number | null;
37
- height: number | null;
38
36
  filename: string;
39
- md5: string | null;
40
- mime_type: "image/jpeg" | "image/png" | "image/jpg" | "image/webp";
41
37
  byte_size: number;
38
+ width?: number | undefined;
39
+ height?: number | undefined;
40
+ md5?: string | undefined;
41
+ mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
42
+ }>, {
43
+ filename: string;
44
+ byte_size: number;
45
+ width?: number | undefined;
46
+ height?: number | undefined;
47
+ md5?: string | undefined;
48
+ mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
49
+ }, {
50
+ filename: string;
51
+ byte_size: number;
52
+ width?: number | undefined;
53
+ height?: number | undefined;
54
+ md5?: string | undefined;
55
+ mime_type?: "image/jpeg" | "image/png" | "image/jpg" | "image/webp" | undefined;
42
56
  }>;
43
57
  export type CreateImageFilePayload = z.infer<typeof CreateImageFilePayload>;
44
58
  export interface CreateImageFileResult {
@@ -60,14 +74,37 @@ export interface CreateImageFileResult {
60
74
  md5: string | null;
61
75
  }
62
76
  export interface LookupImageFileByMd5Result {
77
+ /**
78
+ * Whether the image file has been fully uploaded.
79
+ */
63
80
  complete: boolean | null;
81
+ /**
82
+ * The byte size of the image file.
83
+ */
64
84
  byte_size: number;
85
+ /**
86
+ * The id of the image file.
87
+ */
65
88
  id: string;
89
+ /**
90
+ * md5 hash of the image file.
91
+ */
66
92
  md5: string | null;
93
+ /**
94
+ * The height of the image file in pixels.
95
+ */
96
+ height: number | null;
97
+ /**
98
+ * The width of the image file in pixels.
99
+ */
100
+ width: number | null;
101
+ }
102
+ export interface GetImageFileMetadataResult extends LookupImageFileByMd5Result {
67
103
  }
68
104
  export declare const createImageFile: (client: Client, payload: CreateImageFilePayload) => Promise<CreateImageFileResult>;
69
105
  export declare const uploadImageFile: (client: Client, uploadDetails: {
70
106
  id: string;
71
107
  byte_size: number;
72
- }, fileStream: ReadableStream) => import('../uploadChunks.js').IteratorWithPromise<import('../uploadChunks.js').UploadChunkEvent>;
108
+ }, fileStream: ReadableStream, chunkSizeBytes?: number) => import('../uploadChunks.js').IteratorWithPromise<import('../uploadChunks.js').UploadChunkEvent>;
109
+ export declare const getImageFileMetadata: (client: Client, id: string) => Promise<GetImageFileMetadataResult | null>;
73
110
  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 acceptedTypes = 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().nullable(),
17
+ md5: z.string().optional(),
11
18
  /**
12
19
  * The height of the image file in pixels.
13
20
  */
14
- height: z.number().int().nullable(),
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().nullable(),
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: z.enum(["image/jpeg", "image/png", "image/jpg", "image/webp"]),
29
+ mime_type: acceptedTypes.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 = acceptedTypes.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}`,
@@ -74,6 +107,7 @@ const lookupImageFileByMd5 = async (client, md5) => {
74
107
  export {
75
108
  CreateImageFilePayload,
76
109
  createImageFile,
110
+ getImageFileMetadata,
77
111
  lookupImageFileByMd5,
78
112
  uploadImageFile
79
113
  };
@@ -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>;
@@ -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.17",
3
+ "version": "0.15.0-beta.19",
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.17",
48
+ "@editframe/assets": "0.15.0-beta.19",
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 CreateImageFilePayload = z.object({
12
- /**
13
- * The md5 hash of the image file.
14
- */
15
- md5: z.string().nullable(),
16
- /**
17
- * The height of the image file in pixels.
18
- */
19
- height: z.number().int().nullable(),
20
- /**
21
- * The width of the image file in pixels.
22
- */
23
- width: z.number().int().nullable(),
24
- /**
25
- * The mime type of the image file.
26
- */
27
- mime_type: z.enum(["image/jpeg", "image/png", "image/jpg", "image/webp"]),
28
- /**
29
- * The filename of the image file.
30
- */
31
- filename: z.string(),
32
- /**
33
- * The byte size of the image file.
34
- */
35
- byte_size: z.number().int().max(MAX_IMAGE_SIZE),
36
- });
12
+ const acceptedTypes = 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: acceptedTypes.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 = acceptedTypes.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,
@@ -52,6 +52,7 @@ export interface LookupRenderByMd5Result {
52
52
  id: string;
53
53
  md5: string | null;
54
54
  status: "complete" | "created" | "failed" | "pending" | "rendering" | string;
55
+ metadata: Record<string, string>;
55
56
  }
56
57
 
57
58
  export const createRender = async (