@editframe/api 0.11.0-beta.9 → 0.12.0-beta.2

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.
Files changed (51) hide show
  1. package/dist/CHUNK_SIZE_BYTES.js +1 -1
  2. package/dist/ProgressIterator.d.ts +25 -0
  3. package/dist/ProgressIterator.js +99 -0
  4. package/dist/ProgressIterator.test.d.ts +1 -0
  5. package/dist/StreamEventSource.d.ts +50 -0
  6. package/dist/StreamEventSource.js +130 -0
  7. package/dist/StreamEventSource.test.d.ts +1 -0
  8. package/dist/client.d.ts +6 -3
  9. package/dist/client.js +20 -6
  10. package/dist/index.d.ts +7 -5
  11. package/dist/index.js +20 -11
  12. package/dist/readableFromBuffers.d.ts +1 -2
  13. package/dist/resources/caption-file.d.ts +7 -3
  14. package/dist/resources/caption-file.js +22 -2
  15. package/dist/resources/image-file.d.ts +7 -3
  16. package/dist/resources/image-file.js +19 -0
  17. package/dist/resources/isobmff-file.d.ts +16 -3
  18. package/dist/resources/isobmff-file.js +37 -2
  19. package/dist/resources/isobmff-track.d.ts +5 -7
  20. package/dist/resources/isobmff-track.js +44 -1
  21. package/dist/resources/process-isobmff.d.ts +12 -0
  22. package/dist/resources/process-isobmff.js +22 -0
  23. package/dist/resources/process-isobmff.test.d.ts +1 -0
  24. package/dist/resources/renders.d.ts +10 -5
  25. package/dist/resources/renders.js +21 -2
  26. package/dist/resources/transcriptions.d.ts +24 -0
  27. package/dist/resources/transcriptions.js +45 -0
  28. package/dist/resources/transcriptions.test.d.ts +1 -0
  29. package/dist/resources/unprocessed-file.d.ts +12 -53
  30. package/dist/resources/unprocessed-file.js +31 -130
  31. package/dist/streamChunker.d.ts +1 -2
  32. package/dist/streamChunker.js +20 -9
  33. package/dist/uploadChunks.d.ts +1 -2
  34. package/dist/uploadChunks.js +1 -4
  35. package/package.json +3 -2
  36. package/src/resources/caption-file.test.ts +57 -6
  37. package/src/resources/caption-file.ts +34 -5
  38. package/src/resources/image-file.test.ts +56 -5
  39. package/src/resources/image-file.ts +32 -4
  40. package/src/resources/isobmff-file.test.ts +57 -6
  41. package/src/resources/isobmff-file.ts +64 -5
  42. package/src/resources/isobmff-track.test.ts +3 -3
  43. package/src/resources/isobmff-track.ts +50 -5
  44. package/src/resources/process-isobmff.test.ts +62 -0
  45. package/src/resources/process-isobmff.ts +33 -0
  46. package/src/resources/renders.test.ts +51 -6
  47. package/src/resources/renders.ts +34 -5
  48. package/src/resources/transcriptions.test.ts +49 -0
  49. package/src/resources/transcriptions.ts +64 -0
  50. package/src/resources/unprocessed-file.test.ts +19 -430
  51. package/src/resources/unprocessed-file.ts +45 -161
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/api",
3
- "version": "0.11.0-beta.9",
3
+ "version": "0.12.0-beta.2",
4
4
  "description": "API functions for EditFrame",
5
5
  "exports": {
6
6
  ".": {
@@ -21,6 +21,7 @@
21
21
  "devDependencies": {
22
22
  "@types/jsonwebtoken": "^9.0.6",
23
23
  "@types/node": "^20.14.13",
24
+ "eventsource-parser": "^3.0.0",
24
25
  "typedoc": "^0.26.5",
25
26
  "typescript": "^5.5.4",
26
27
  "vite": "^5.2.11",
@@ -28,7 +29,7 @@
28
29
  "vite-tsconfig-paths": "^4.3.2"
29
30
  },
30
31
  "dependencies": {
31
- "@editframe/assets": "0.11.0-beta.9",
32
+ "@editframe/assets": "0.12.0-beta.2",
32
33
  "debug": "^4.3.5",
33
34
  "jsonwebtoken": "^9.0.2",
34
35
  "node-fetch": "^3.3.2",
@@ -1,10 +1,14 @@
1
- import { test, expect, beforeAll, afterEach, afterAll, describe } from "vitest";
2
1
  import { http, HttpResponse } from "msw";
3
2
  import { setupServer } from "msw/node";
3
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
4
4
 
5
5
  import { Client } from "../client.ts";
6
- import { createCaptionFile, uploadCaptionFile } from "./caption-file.ts";
7
- import { readableFromBuffers } from "../readableFromBuffers.ts";
6
+ import { webReadableFromBuffers } from "../readableFromBuffers.ts";
7
+ import {
8
+ createCaptionFile,
9
+ lookupCaptionFileByMd5,
10
+ uploadCaptionFile,
11
+ } from "./caption-file.ts";
8
12
 
9
13
  const server = setupServer();
10
14
  const client = new Client("ef_TEST_TOKEN", "http://localhost");
@@ -71,7 +75,7 @@ describe("CaptionFile", () => {
71
75
  uploadCaptionFile(
72
76
  client,
73
77
  "test-id",
74
- readableFromBuffers(Buffer.from("test")),
78
+ webReadableFromBuffers(Buffer.from("test")),
75
79
  1024 * 1024 * 3,
76
80
  ),
77
81
  ).rejects.toThrowError(
@@ -90,7 +94,7 @@ describe("CaptionFile", () => {
90
94
  uploadCaptionFile(
91
95
  client,
92
96
  "test-id",
93
- readableFromBuffers(Buffer.from("nice")),
97
+ webReadableFromBuffers(Buffer.from("nice")),
94
98
  4,
95
99
  ),
96
100
  ).rejects.toThrowError(
@@ -111,11 +115,58 @@ describe("CaptionFile", () => {
111
115
  const response = await uploadCaptionFile(
112
116
  client,
113
117
  "test-id",
114
- readableFromBuffers(Buffer.from("nice")),
118
+ webReadableFromBuffers(Buffer.from("nice")),
115
119
  4,
116
120
  );
117
121
 
118
122
  expect(response).toEqual({ id: "test-id" });
119
123
  });
120
124
  });
125
+
126
+ describe("lookupCaptionFileByMd5", () => {
127
+ test("Returns json data from the http response", async () => {
128
+ server.use(
129
+ http.get("http://localhost/api/v1/caption_files/md5/test-md5", () =>
130
+ HttpResponse.json(
131
+ { id: "test-id", md5: "test-md5", complete: true },
132
+ { status: 200, statusText: "OK" },
133
+ ),
134
+ ),
135
+ );
136
+
137
+ const response = await lookupCaptionFileByMd5(client, "test-md5");
138
+
139
+ expect(response).toEqual({
140
+ id: "test-id",
141
+ md5: "test-md5",
142
+ complete: true,
143
+ });
144
+ });
145
+
146
+ test("Returns null when file is not found", async () => {
147
+ server.use(
148
+ http.get("http://localhost/api/v1/caption_files/md5/test-md5", () =>
149
+ HttpResponse.json({}, { status: 404 }),
150
+ ),
151
+ );
152
+
153
+ const response = await lookupCaptionFileByMd5(client, "test-md5");
154
+
155
+ expect(response).toBeNull();
156
+ });
157
+
158
+ test("Throws when server returns an error", async () => {
159
+ server.use(
160
+ http.get("http://localhost/api/v1/caption_files/md5/test-md5", () =>
161
+ HttpResponse.text("Internal Server Error", { status: 500 }),
162
+ ),
163
+ );
164
+
165
+ await expect(
166
+ lookupCaptionFileByMd5(client, "test-md5"),
167
+ ).rejects.toThrowError(
168
+ "Failed to lookup caption by md5 test-md5 500 Internal Server Error",
169
+ );
170
+ });
171
+ });
121
172
  });
@@ -1,7 +1,5 @@
1
- import type { Readable } from "node:stream";
2
-
3
- import { z } from "zod";
4
1
  import debug from "debug";
2
+ import { z } from "zod";
5
3
 
6
4
  import type { Client } from "../client.ts";
7
5
 
@@ -19,7 +17,12 @@ export interface CreateCaptionFileResult {
19
17
  complete: boolean | null;
20
18
  id: string;
21
19
  md5: string;
22
- asset_id: string;
20
+ }
21
+
22
+ export interface LookupCaptionFileByMd5Result {
23
+ complete: boolean | null;
24
+ id: string;
25
+ md5: string;
23
26
  }
24
27
 
25
28
  const restrictSize = (size: number) => {
@@ -71,7 +74,7 @@ export const createCaptionFile = async (
71
74
  export const uploadCaptionFile = async (
72
75
  client: Client,
73
76
  fileId: string,
74
- fileStream: Readable,
77
+ fileStream: ReadableStream,
75
78
  fileSize: number,
76
79
  ) => {
77
80
  log("Uploading caption file", fileId);
@@ -82,6 +85,7 @@ export const uploadCaptionFile = async (
82
85
  {
83
86
  method: "POST",
84
87
  body: fileStream,
88
+ duplex: "half",
85
89
  },
86
90
  );
87
91
  log("Caption file uploaded", response);
@@ -94,3 +98,28 @@ export const uploadCaptionFile = async (
94
98
  `Failed to upload caption ${response.status} ${response.statusText}`,
95
99
  );
96
100
  };
101
+
102
+ export const lookupCaptionFileByMd5 = async (
103
+ client: Client,
104
+ md5: string,
105
+ ): Promise<LookupCaptionFileByMd5Result | null> => {
106
+ const response = await client.authenticatedFetch(
107
+ `/api/v1/caption_files/md5/${md5}`,
108
+ {
109
+ method: "GET",
110
+ },
111
+ );
112
+ log("Caption file lookup", response);
113
+
114
+ if (response.ok) {
115
+ return (await response.json()) as LookupCaptionFileByMd5Result;
116
+ }
117
+
118
+ if (response.status === 404) {
119
+ return null;
120
+ }
121
+
122
+ throw new Error(
123
+ `Failed to lookup caption by md5 ${md5} ${response.status} ${response.statusText}`,
124
+ );
125
+ };
@@ -4,8 +4,12 @@ import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
4
4
  import { ZodError } from "zod";
5
5
 
6
6
  import { Client } from "../client.ts";
7
- import { readableFromBuffers } from "../readableFromBuffers.ts";
8
- import { createImageFile, uploadImageFile } from "./image-file.ts";
7
+ import { webReadableFromBuffers } from "../readableFromBuffers.ts";
8
+ import {
9
+ createImageFile,
10
+ lookupImageFileByMd5,
11
+ uploadImageFile,
12
+ } from "./image-file.ts";
9
13
 
10
14
  const server = setupServer();
11
15
  const client = new Client("ef_TEST_TOKEN", "http://localhost");
@@ -94,7 +98,7 @@ describe("ImageFile", () => {
94
98
  uploadImageFile(
95
99
  client,
96
100
  "test-file-id",
97
- readableFromBuffers(Buffer.from("test")),
101
+ webReadableFromBuffers(Buffer.from("test")),
98
102
  1024 * 1024 * 17,
99
103
  ).whenUploaded(),
100
104
  ).rejects.toThrowError(
@@ -115,7 +119,7 @@ describe("ImageFile", () => {
115
119
  uploadImageFile(
116
120
  client,
117
121
  "test-file-id",
118
- readableFromBuffers(Buffer.from("test")),
122
+ webReadableFromBuffers(Buffer.from("test")),
119
123
  4,
120
124
  ).whenUploaded(),
121
125
  ).rejects.toThrowError(
@@ -136,7 +140,7 @@ describe("ImageFile", () => {
136
140
  uploadImageFile(
137
141
  client,
138
142
  "test-file-id",
139
- readableFromBuffers(Buffer.from("test")),
143
+ webReadableFromBuffers(Buffer.from("test")),
140
144
  4,
141
145
  ).whenUploaded(),
142
146
  ).resolves.toEqual([
@@ -145,4 +149,51 @@ describe("ImageFile", () => {
145
149
  ]);
146
150
  });
147
151
  });
152
+
153
+ describe("lookupImageFileByMd5", () => {
154
+ test("Returns json data from the http response", async () => {
155
+ server.use(
156
+ http.get("http://localhost/api/v1/image_files/md5/test-md5", () =>
157
+ HttpResponse.json(
158
+ { id: "test-id", md5: "test-md5", complete: true },
159
+ { status: 200, statusText: "OK" },
160
+ ),
161
+ ),
162
+ );
163
+
164
+ const response = await lookupImageFileByMd5(client, "test-md5");
165
+
166
+ expect(response).toEqual({
167
+ id: "test-id",
168
+ md5: "test-md5",
169
+ complete: true,
170
+ });
171
+ });
172
+
173
+ test("Returns null when file is not found", async () => {
174
+ server.use(
175
+ http.get("http://localhost/api/v1/image_files/md5/test-md5", () =>
176
+ HttpResponse.json({}, { status: 404 }),
177
+ ),
178
+ );
179
+
180
+ const response = await lookupImageFileByMd5(client, "test-md5");
181
+
182
+ expect(response).toBeNull();
183
+ });
184
+
185
+ test("Throws when server returns an error", async () => {
186
+ server.use(
187
+ http.get("http://localhost/api/v1/image_files/md5/test-md5", () =>
188
+ HttpResponse.text("Internal Server Error", { status: 500 }),
189
+ ),
190
+ );
191
+
192
+ await expect(
193
+ lookupImageFileByMd5(client, "test-md5"),
194
+ ).rejects.toThrowError(
195
+ "Failed to lookup image by md5 test-md5 500 Internal Server Error",
196
+ );
197
+ });
198
+ });
148
199
  });
@@ -1,5 +1,3 @@
1
- import type { Readable } from "node:stream";
2
-
3
1
  import debug from "debug";
4
2
  import { z } from "zod";
5
3
 
@@ -23,7 +21,12 @@ export interface CreateImageFileResult {
23
21
  complete: boolean | null;
24
22
  id: string;
25
23
  md5: string;
26
- asset_id: string;
24
+ }
25
+
26
+ export interface LookupImageFileByMd5Result {
27
+ complete: boolean | null;
28
+ id: string;
29
+ md5: string;
27
30
  }
28
31
 
29
32
  export const createImageFile = async (
@@ -51,7 +54,7 @@ export const createImageFile = async (
51
54
  export const uploadImageFile = (
52
55
  client: Client,
53
56
  fileId: string,
54
- fileStream: Readable,
57
+ fileStream: ReadableStream,
55
58
  fileSize: number,
56
59
  ) => {
57
60
  log("Uploading image file", fileId);
@@ -63,3 +66,28 @@ export const uploadImageFile = (
63
66
  maxSize: MAX_IMAGE_SIZE,
64
67
  });
65
68
  };
69
+
70
+ export const lookupImageFileByMd5 = async (
71
+ client: Client,
72
+ md5: string,
73
+ ): Promise<LookupImageFileByMd5Result | null> => {
74
+ const response = await client.authenticatedFetch(
75
+ `/api/v1/image_files/md5/${md5}`,
76
+ {
77
+ method: "GET",
78
+ },
79
+ );
80
+ log("Image file lookup", response);
81
+
82
+ if (response.ok) {
83
+ return (await response.json()) as LookupImageFileByMd5Result;
84
+ }
85
+
86
+ if (response.status === 404) {
87
+ return null;
88
+ }
89
+
90
+ throw new Error(
91
+ `Failed to lookup image by md5 ${md5} ${response.status} ${response.statusText}`,
92
+ );
93
+ };
@@ -1,10 +1,14 @@
1
- import { test, expect, beforeAll, afterEach, afterAll, describe } from "vitest";
2
1
  import { http, HttpResponse } from "msw";
3
2
  import { setupServer } from "msw/node";
3
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest";
4
4
 
5
5
  import { Client } from "../client.ts";
6
- import { createISOBMFFFile, uploadFragmentIndex } from "./isobmff-file.ts";
7
- import { readableFromBuffers } from "../readableFromBuffers.ts";
6
+ import { webReadableFromBuffers } from "../readableFromBuffers.ts";
7
+ import {
8
+ createISOBMFFFile,
9
+ lookupISOBMFFFileByMd5,
10
+ uploadFragmentIndex,
11
+ } from "./isobmff-file.ts";
8
12
 
9
13
  const server = setupServer();
10
14
  const client = new Client("ef_TEST_TOKEN", "http://localhost");
@@ -57,7 +61,7 @@ describe("ISOBMFFFile", () => {
57
61
  uploadFragmentIndex(
58
62
  client,
59
63
  "test-id",
60
- readableFromBuffers(Buffer.from("test")),
64
+ webReadableFromBuffers(Buffer.from("test")),
61
65
  1024 * 1024 * 3,
62
66
  ),
63
67
  ).rejects.toThrowError("File size exceeds limit of 2097152 bytes");
@@ -75,7 +79,7 @@ describe("ISOBMFFFile", () => {
75
79
  uploadFragmentIndex(
76
80
  client,
77
81
  "test-id",
78
- readableFromBuffers(Buffer.from("test")),
82
+ webReadableFromBuffers(Buffer.from("test")),
79
83
  4,
80
84
  ),
81
85
  ).rejects.toThrowError(
@@ -98,11 +102,58 @@ describe("ISOBMFFFile", () => {
98
102
  const response = await uploadFragmentIndex(
99
103
  client,
100
104
  "test-id",
101
- readableFromBuffers(Buffer.from("test")),
105
+ webReadableFromBuffers(Buffer.from("test")),
102
106
  4,
103
107
  );
104
108
 
105
109
  expect(response).toEqual({ fragment_index_complete: true });
106
110
  });
107
111
  });
112
+
113
+ describe("lookupISOBMFFFileByMd5", () => {
114
+ test("Returns json data from the http response", async () => {
115
+ server.use(
116
+ http.get("http://localhost/api/v1/isobmff_files/md5/test-md5", () =>
117
+ HttpResponse.json(
118
+ { id: "test-id", md5: "test-md5", fragment_index_complete: true },
119
+ { status: 200, statusText: "OK" },
120
+ ),
121
+ ),
122
+ );
123
+
124
+ const response = await lookupISOBMFFFileByMd5(client, "test-md5");
125
+
126
+ expect(response).toEqual({
127
+ id: "test-id",
128
+ md5: "test-md5",
129
+ fragment_index_complete: true,
130
+ });
131
+ });
132
+
133
+ test("Returns null when file is not found", async () => {
134
+ server.use(
135
+ http.get("http://localhost/api/v1/isobmff_files/md5/test-md5", () =>
136
+ HttpResponse.json({}, { status: 404 }),
137
+ ),
138
+ );
139
+
140
+ const response = await lookupISOBMFFFileByMd5(client, "test-md5");
141
+
142
+ expect(response).toBeNull();
143
+ });
144
+
145
+ test("Throws when server returns an error", async () => {
146
+ server.use(
147
+ http.get("http://localhost/api/v1/isobmff_files/md5/test-md5", () =>
148
+ HttpResponse.text("Internal Server Error", { status: 500 }),
149
+ ),
150
+ );
151
+
152
+ await expect(
153
+ lookupISOBMFFFileByMd5(client, "test-md5"),
154
+ ).rejects.toThrowError(
155
+ "Failed to lookup isobmff file by md5 test-md5 500 Internal Server Error",
156
+ );
157
+ });
158
+ });
108
159
  });
@@ -1,7 +1,5 @@
1
- import type { Readable } from "node:stream";
2
-
3
- import { z } from "zod";
4
1
  import debug from "debug";
2
+ import { z } from "zod";
5
3
 
6
4
  import type { Client } from "../client.ts";
7
5
 
@@ -18,7 +16,21 @@ export interface CreateISOBMFFFileResult {
18
16
  filename: string;
19
17
  id: string;
20
18
  md5: string;
21
- asset_id: string;
19
+ }
20
+
21
+ export interface LookupISOBMFFFileByMd5Result {
22
+ fragment_index_complete: boolean;
23
+ filename: string;
24
+ id: string;
25
+ md5: string;
26
+ }
27
+
28
+ export interface GetISOBMFFFileTranscriptionResult {
29
+ id: string;
30
+ work_slice_ms: number;
31
+ isobmff_track: {
32
+ duration_ms: number;
33
+ };
22
34
  }
23
35
 
24
36
  export const createISOBMFFFile = async (
@@ -45,7 +57,7 @@ export const createISOBMFFFile = async (
45
57
  export const uploadFragmentIndex = async (
46
58
  client: Client,
47
59
  fileId: string,
48
- fileStream: Readable,
60
+ fileStream: ReadableStream,
49
61
  fileSize: number,
50
62
  ) => {
51
63
  log("Uploading fragment index", fileId);
@@ -57,6 +69,7 @@ export const uploadFragmentIndex = async (
57
69
  {
58
70
  method: "POST",
59
71
  body: fileStream,
72
+ duplex: "half",
60
73
  },
61
74
  );
62
75
 
@@ -69,3 +82,49 @@ export const uploadFragmentIndex = async (
69
82
  `Failed to create fragment index ${response.status} ${response.statusText}`,
70
83
  );
71
84
  };
85
+
86
+ export const lookupISOBMFFFileByMd5 = async (
87
+ client: Client,
88
+ md5: string,
89
+ ): Promise<LookupISOBMFFFileByMd5Result | null> => {
90
+ const response = await client.authenticatedFetch(
91
+ `/api/v1/isobmff_files/md5/${md5}`,
92
+ {
93
+ method: "GET",
94
+ },
95
+ );
96
+ log("ISOBMFF file lookup", response);
97
+
98
+ if (response.ok) {
99
+ return (await response.json()) as LookupISOBMFFFileByMd5Result;
100
+ }
101
+
102
+ if (response.status === 404) {
103
+ return null;
104
+ }
105
+
106
+ throw new Error(
107
+ `Failed to lookup isobmff file by md5 ${md5} ${response.status} ${response.statusText}`,
108
+ );
109
+ };
110
+
111
+ export const getISOBMFFFileTranscription = async (
112
+ client: Client,
113
+ id: string,
114
+ ): Promise<GetISOBMFFFileTranscriptionResult | null> => {
115
+ const response = await client.authenticatedFetch(
116
+ `/api/v1/isobmff_files/${id}/transcription`,
117
+ );
118
+
119
+ if (response.ok) {
120
+ return (await response.json()) as GetISOBMFFFileTranscriptionResult;
121
+ }
122
+
123
+ if (response.status === 404) {
124
+ return null;
125
+ }
126
+
127
+ throw new Error(
128
+ `Failed to get isobmff file transcription ${id} ${response.status} ${response.statusText}`,
129
+ );
130
+ };
@@ -5,7 +5,7 @@ import { ZodError } from "zod";
5
5
 
6
6
  import { createTestTrack } from "TEST/createTestTrack.ts";
7
7
  import { Client } from "../client.ts";
8
- import { readableFromBuffers } from "../readableFromBuffers.ts";
8
+ import { webReadableFromBuffers } from "../readableFromBuffers.ts";
9
9
  import { createISOBMFFTrack, uploadISOBMFFTrack } from "./isobmff-track.ts";
10
10
 
11
11
  const server = setupServer();
@@ -92,7 +92,7 @@ describe("ISOBMFF Track", () => {
92
92
  client,
93
93
  "test-file",
94
94
  1,
95
- readableFromBuffers(Buffer.from("test")),
95
+ webReadableFromBuffers(Buffer.from("test")),
96
96
  4,
97
97
  ).whenUploaded(),
98
98
  ).rejects.toThrowError(
@@ -114,7 +114,7 @@ describe("ISOBMFF Track", () => {
114
114
  client,
115
115
  "test-file",
116
116
  1,
117
- readableFromBuffers(Buffer.from("test")),
117
+ webReadableFromBuffers(Buffer.from("test")),
118
118
  4,
119
119
  ).whenUploaded(),
120
120
  ).resolves.toEqual([
@@ -1,9 +1,55 @@
1
- import type { Readable } from "node:stream";
2
-
3
1
  import debug from "debug";
4
2
  import { z } from "zod";
5
3
 
6
- import { AudioStreamSchema, VideoStreamSchema } from "@editframe/assets";
4
+ const AudioStreamSchema = z.object({
5
+ index: z.number(),
6
+ codec_name: z.string(),
7
+ codec_long_name: z.string(),
8
+ codec_type: z.literal("audio"),
9
+ codec_tag_string: z.string(),
10
+ codec_tag: z.string(),
11
+ sample_fmt: z.string(),
12
+ sample_rate: z.string(),
13
+ channels: z.number(),
14
+ channel_layout: z.string(),
15
+ bits_per_sample: z.number(),
16
+ initial_padding: z.number().optional(),
17
+ r_frame_rate: z.string(),
18
+ avg_frame_rate: z.string(),
19
+ time_base: z.string(),
20
+ start_pts: z.number(),
21
+ start_time: z.coerce.number(),
22
+ duration_ts: z.number(),
23
+ duration: z.coerce.number(),
24
+ bit_rate: z.string(),
25
+ disposition: z.record(z.unknown()),
26
+ });
27
+
28
+ type AudioStreamSchema = z.infer<typeof AudioStreamSchema>;
29
+
30
+ const VideoStreamSchema = z.object({
31
+ index: z.number(),
32
+ codec_name: z.string(),
33
+ codec_long_name: z.string(),
34
+ codec_type: z.literal("video"),
35
+ codec_tag_string: z.string(),
36
+ codec_tag: z.string(),
37
+ width: z.number(),
38
+ height: z.number(),
39
+ coded_width: z.number(),
40
+ coded_height: z.number(),
41
+ r_frame_rate: z.string(),
42
+ avg_frame_rate: z.string(),
43
+ time_base: z.string(),
44
+ start_pts: z.number().optional(),
45
+ start_time: z.coerce.number().optional(),
46
+ duration_ts: z.number().optional(),
47
+ duration: z.coerce.number().optional(),
48
+ bit_rate: z.string().optional(),
49
+ disposition: z.record(z.unknown()),
50
+ });
51
+
52
+ type VideoStreamSchema = z.infer<typeof VideoStreamSchema>;
7
53
 
8
54
  import type { Client } from "../client.ts";
9
55
  import { uploadChunks } from "../uploadChunks.ts";
@@ -38,7 +84,6 @@ export interface CreateISOBMFFTrackResult {
38
84
  byte_size: number;
39
85
  track_id: number;
40
86
  file_id: string;
41
- asset_id: string;
42
87
  complete: boolean;
43
88
  }
44
89
 
@@ -67,7 +112,7 @@ export const uploadISOBMFFTrack = (
67
112
  client: Client,
68
113
  fileId: string,
69
114
  trackId: number,
70
- fileStream: Readable,
115
+ fileStream: ReadableStream,
71
116
  trackSize: number,
72
117
  ) => {
73
118
  log("Uploading fragment track", fileId);
@@ -0,0 +1,62 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import {
3
+ getIsobmffProcessInfo,
4
+ getIsobmffProcessProgress,
5
+ } from "./process-isobmff.ts";
6
+
7
+ import { useMSW } from "TEST/useMSW.ts";
8
+ import { http, HttpResponse } from "msw";
9
+ import { Client } from "../client.ts";
10
+
11
+ const client = new Client("ef_TEST_TOKEN", "http://localhost");
12
+
13
+ describe("process-isobmff", () => {
14
+ const server = useMSW();
15
+ describe("getIsobmffProcessInfo", () => {
16
+ test("returns the process info", async () => {
17
+ server.use(
18
+ http.get("http://localhost/api/v1/process_isobmff/123", async () => {
19
+ return HttpResponse.json({
20
+ id: "123",
21
+ created_at: "2021-01-01T00:00:00.000Z",
22
+ updated_at: "2021-01-01T00:00:00.000Z",
23
+ });
24
+ }),
25
+ );
26
+ const info = await getIsobmffProcessInfo(client, "123");
27
+ expect(info).toEqual({
28
+ id: "123",
29
+ created_at: "2021-01-01T00:00:00.000Z",
30
+ updated_at: "2021-01-01T00:00:00.000Z",
31
+ });
32
+ });
33
+
34
+ test("throws when the server returns an error", async () => {
35
+ server.use(
36
+ http.get("http://localhost/api/v1/process_isobmff/123", () =>
37
+ HttpResponse.text("Internal Server Error", { status: 500 }),
38
+ ),
39
+ );
40
+ await expect(getIsobmffProcessInfo(client, "123")).rejects.toThrow(
41
+ "Failed to get isobmff process info 500 Internal Server Error",
42
+ );
43
+ });
44
+ });
45
+
46
+ describe("getIsobmffProcessProgress", () => {
47
+ test("returns the progress", async () => {
48
+ server.use(
49
+ http.get(
50
+ "http://localhost/api/v1/process_isobmff/123/progress",
51
+ async () => {
52
+ return HttpResponse.text("event: complete\ndata: {}\n\n");
53
+ },
54
+ ),
55
+ );
56
+ const progress = await getIsobmffProcessProgress(client, "123");
57
+ await expect(progress.whenComplete()).resolves.toEqual([
58
+ { type: "complete", data: {} },
59
+ ]);
60
+ });
61
+ });
62
+ });