@editframe/api 0.7.0-beta.4

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.
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const debug = require("debug");
4
+ const log = debug("ef:api:client");
5
+ class Client {
6
+ constructor(token, efHost) {
7
+ this.token = token;
8
+ this.efHost = efHost;
9
+ this.authenticatedFetch = async (path, init = {}) => {
10
+ init.headers ||= {};
11
+ log(
12
+ "Authenticated fetch",
13
+ { path, init },
14
+ "(Token will be added as Bearer token)"
15
+ );
16
+ Object.assign(init.headers, {
17
+ Authorization: `Bearer ${this.token}`,
18
+ "Content-Type": "application/json"
19
+ });
20
+ const url = new URL(path, this.efHost);
21
+ const response = await fetch(url, init);
22
+ log("Authenticated fetch response", response.status, response.statusText);
23
+ return response;
24
+ };
25
+ log("Creating client with efHost", efHost, "and !!token", !!token);
26
+ }
27
+ }
28
+ exports.Client = Client;
package/dist/client.js ADDED
@@ -0,0 +1,28 @@
1
+ import debug from "debug";
2
+ const log = debug("ef:api:client");
3
+ class Client {
4
+ constructor(token, efHost) {
5
+ this.token = token;
6
+ this.efHost = efHost;
7
+ this.authenticatedFetch = async (path, init = {}) => {
8
+ init.headers ||= {};
9
+ log(
10
+ "Authenticated fetch",
11
+ { path, init },
12
+ "(Token will be added as Bearer token)"
13
+ );
14
+ Object.assign(init.headers, {
15
+ Authorization: `Bearer ${this.token}`,
16
+ "Content-Type": "application/json"
17
+ });
18
+ const url = new URL(path, this.efHost);
19
+ const response = await fetch(url, init);
20
+ log("Authenticated fetch response", response.status, response.statusText);
21
+ return response;
22
+ };
23
+ log("Creating client with efHost", efHost, "and !!token", !!token);
24
+ }
25
+ }
26
+ export {
27
+ Client
28
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const captionFile = require("./resources/caption-file.cjs");
4
+ const imageFile = require("./resources/image-file.cjs");
5
+ const isobmffFile = require("./resources/isobmff-file.cjs");
6
+ const isobmffTrack = require("./resources/isobmff-track.cjs");
7
+ const renders = require("./resources/renders.cjs");
8
+ const client = require("./client.cjs");
9
+ exports.CreateCaptionFilePayload = captionFile.CreateCaptionFilePayload;
10
+ exports.createCaptionFile = captionFile.createCaptionFile;
11
+ exports.uploadCaptionFile = captionFile.uploadCaptionFile;
12
+ exports.CreateImageFilePayload = imageFile.CreateImageFilePayload;
13
+ exports.createImageFile = imageFile.createImageFile;
14
+ exports.uploadImageFile = imageFile.uploadImageFile;
15
+ exports.CreateISOBMFFFilePayload = isobmffFile.CreateISOBMFFFilePayload;
16
+ exports.createISOBMFFFile = isobmffFile.createISOBMFFFile;
17
+ exports.uploadFragmentIndex = isobmffFile.uploadFragmentIndex;
18
+ exports.CreateISOBMFFTrackPayload = isobmffTrack.CreateISOBMFFTrackPayload;
19
+ exports.createISOBMFFTrack = isobmffTrack.createISOBMFFTrack;
20
+ exports.uploadISOBMFFTrack = isobmffTrack.uploadISOBMFFTrack;
21
+ exports.CreateRenderPayload = renders.CreateRenderPayload;
22
+ exports.createRender = renders.createRender;
23
+ exports.uploadRender = renders.uploadRender;
24
+ exports.Client = client.Client;
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import { CreateCaptionFilePayload, createCaptionFile, uploadCaptionFile } from "./resources/caption-file.js";
2
+ import { CreateImageFilePayload, createImageFile, uploadImageFile } from "./resources/image-file.js";
3
+ import { CreateISOBMFFFilePayload, createISOBMFFFile, uploadFragmentIndex } from "./resources/isobmff-file.js";
4
+ import { CreateISOBMFFTrackPayload, createISOBMFFTrack, uploadISOBMFFTrack } from "./resources/isobmff-track.js";
5
+ import { CreateRenderPayload, createRender, uploadRender } from "./resources/renders.js";
6
+ import { Client } from "./client.js";
7
+ export {
8
+ Client,
9
+ CreateCaptionFilePayload,
10
+ CreateISOBMFFFilePayload,
11
+ CreateISOBMFFTrackPayload,
12
+ CreateImageFilePayload,
13
+ CreateRenderPayload,
14
+ createCaptionFile,
15
+ createISOBMFFFile,
16
+ createISOBMFFTrack,
17
+ createImageFile,
18
+ createRender,
19
+ uploadCaptionFile,
20
+ uploadFragmentIndex,
21
+ uploadISOBMFFTrack,
22
+ uploadImageFile,
23
+ uploadRender
24
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const zod = require("zod");
4
+ const debug = require("debug");
5
+ const nodeStreamToWebStream = require("../util/nodeStreamToWebStream.cjs");
6
+ const log = debug("ef:api:caption-file");
7
+ const CreateCaptionFilePayload = zod.z.object({
8
+ id: zod.z.string(),
9
+ filename: zod.z.string()
10
+ });
11
+ const createCaptionFile = async (client, payload) => {
12
+ log("Creating caption file", payload);
13
+ const fileCreation = await client.authenticatedFetch(
14
+ "/api/video2/caption_files",
15
+ {
16
+ method: "POST",
17
+ body: JSON.stringify(payload)
18
+ }
19
+ );
20
+ log("Caption file created", fileCreation);
21
+ switch (fileCreation.status) {
22
+ case 200: {
23
+ return await fileCreation.json();
24
+ }
25
+ default: {
26
+ console.error(
27
+ `Failed to create file ${fileCreation.status} ${fileCreation.statusText}`
28
+ );
29
+ return;
30
+ }
31
+ }
32
+ };
33
+ const uploadCaptionFile = async (client, fileId, fileStream) => {
34
+ log("Uploading caption file", fileId);
35
+ const fileIndex = await client.authenticatedFetch(
36
+ `/api/video2/caption_files/${fileId}/upload`,
37
+ {
38
+ method: "POST",
39
+ body: nodeStreamToWebStream.nodeStreamToWebStream(fileStream)
40
+ }
41
+ );
42
+ log("Caption file uploaded", fileIndex);
43
+ switch (fileIndex.status) {
44
+ case 200: {
45
+ return fileIndex.json();
46
+ }
47
+ default: {
48
+ console.error(
49
+ `Failed to upload caption ${fileIndex.status} ${fileIndex.statusText}`
50
+ );
51
+ return;
52
+ }
53
+ }
54
+ };
55
+ exports.CreateCaptionFilePayload = CreateCaptionFilePayload;
56
+ exports.createCaptionFile = createCaptionFile;
57
+ exports.uploadCaptionFile = uploadCaptionFile;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import debug from "debug";
3
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream.js";
4
+ const log = debug("ef:api:caption-file");
5
+ const CreateCaptionFilePayload = z.object({
6
+ id: z.string(),
7
+ filename: z.string()
8
+ });
9
+ const createCaptionFile = async (client, payload) => {
10
+ log("Creating caption file", payload);
11
+ const fileCreation = await client.authenticatedFetch(
12
+ "/api/video2/caption_files",
13
+ {
14
+ method: "POST",
15
+ body: JSON.stringify(payload)
16
+ }
17
+ );
18
+ log("Caption file created", fileCreation);
19
+ switch (fileCreation.status) {
20
+ case 200: {
21
+ return await fileCreation.json();
22
+ }
23
+ default: {
24
+ console.error(
25
+ `Failed to create file ${fileCreation.status} ${fileCreation.statusText}`
26
+ );
27
+ return;
28
+ }
29
+ }
30
+ };
31
+ const uploadCaptionFile = async (client, fileId, fileStream) => {
32
+ log("Uploading caption file", fileId);
33
+ const fileIndex = await client.authenticatedFetch(
34
+ `/api/video2/caption_files/${fileId}/upload`,
35
+ {
36
+ method: "POST",
37
+ body: nodeStreamToWebStream(fileStream)
38
+ }
39
+ );
40
+ log("Caption file uploaded", fileIndex);
41
+ switch (fileIndex.status) {
42
+ case 200: {
43
+ return fileIndex.json();
44
+ }
45
+ default: {
46
+ console.error(
47
+ `Failed to upload caption ${fileIndex.status} ${fileIndex.statusText}`
48
+ );
49
+ return;
50
+ }
51
+ }
52
+ };
53
+ export {
54
+ CreateCaptionFilePayload,
55
+ createCaptionFile,
56
+ uploadCaptionFile
57
+ };
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const zod = require("zod");
4
+ const debug = require("debug");
5
+ const nodeStreamToWebStream = require("../util/nodeStreamToWebStream.cjs");
6
+ const log = debug("ef:api:image-file");
7
+ const CreateImageFilePayload = zod.z.object({
8
+ id: zod.z.string(),
9
+ height: zod.z.number().int(),
10
+ width: zod.z.number().int(),
11
+ mime_type: zod.z.enum(["image/jpeg", "image/png", "image/jpg", "image/webp"]),
12
+ filename: zod.z.string()
13
+ });
14
+ const createImageFile = async (client, payload) => {
15
+ log("Creating image file", payload);
16
+ const response = await client.authenticatedFetch("/api/video2/image_files", {
17
+ method: "POST",
18
+ body: JSON.stringify(payload)
19
+ });
20
+ log("Image file created", response);
21
+ switch (response.status) {
22
+ case 200: {
23
+ return await response.json();
24
+ }
25
+ default: {
26
+ console.error(
27
+ `Failed to create file ${response.status} ${response.statusText}`
28
+ );
29
+ return;
30
+ }
31
+ }
32
+ };
33
+ const uploadImageFile = async (client, fileId, fileStream) => {
34
+ const fileIndex = await client.authenticatedFetch(
35
+ `/api/video2/image_files/${fileId}/upload`,
36
+ {
37
+ method: "POST",
38
+ body: nodeStreamToWebStream.nodeStreamToWebStream(fileStream)
39
+ }
40
+ );
41
+ switch (fileIndex.status) {
42
+ case 200: {
43
+ return fileIndex.json();
44
+ }
45
+ default: {
46
+ console.error("Failed to upload image");
47
+ return;
48
+ }
49
+ }
50
+ };
51
+ exports.CreateImageFilePayload = CreateImageFilePayload;
52
+ exports.createImageFile = createImageFile;
53
+ exports.uploadImageFile = uploadImageFile;
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ import debug from "debug";
3
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream.js";
4
+ const log = debug("ef:api:image-file");
5
+ const CreateImageFilePayload = z.object({
6
+ id: z.string(),
7
+ height: z.number().int(),
8
+ width: z.number().int(),
9
+ mime_type: z.enum(["image/jpeg", "image/png", "image/jpg", "image/webp"]),
10
+ filename: z.string()
11
+ });
12
+ const createImageFile = async (client, payload) => {
13
+ log("Creating image file", payload);
14
+ const response = await client.authenticatedFetch("/api/video2/image_files", {
15
+ method: "POST",
16
+ body: JSON.stringify(payload)
17
+ });
18
+ log("Image file created", response);
19
+ switch (response.status) {
20
+ case 200: {
21
+ return await response.json();
22
+ }
23
+ default: {
24
+ console.error(
25
+ `Failed to create file ${response.status} ${response.statusText}`
26
+ );
27
+ return;
28
+ }
29
+ }
30
+ };
31
+ const uploadImageFile = async (client, fileId, fileStream) => {
32
+ const fileIndex = await client.authenticatedFetch(
33
+ `/api/video2/image_files/${fileId}/upload`,
34
+ {
35
+ method: "POST",
36
+ body: nodeStreamToWebStream(fileStream)
37
+ }
38
+ );
39
+ switch (fileIndex.status) {
40
+ case 200: {
41
+ return fileIndex.json();
42
+ }
43
+ default: {
44
+ console.error("Failed to upload image");
45
+ return;
46
+ }
47
+ }
48
+ };
49
+ export {
50
+ CreateImageFilePayload,
51
+ createImageFile,
52
+ uploadImageFile
53
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const zod = require("zod");
4
+ const debug = require("debug");
5
+ const nodeStreamToWebStream = require("../util/nodeStreamToWebStream.cjs");
6
+ const log = debug("ef:api:isobmff-file");
7
+ const CreateISOBMFFFilePayload = zod.z.object({
8
+ id: zod.z.string(),
9
+ filename: zod.z.string()
10
+ });
11
+ const createISOBMFFFile = async (client, payload) => {
12
+ log("Creating isobmff file", payload);
13
+ const response = await client.authenticatedFetch(
14
+ "/api/video2/isobmff_files",
15
+ {
16
+ method: "POST",
17
+ body: JSON.stringify(payload)
18
+ }
19
+ );
20
+ log("ISOBMFF file created", response);
21
+ switch (response.status) {
22
+ case 200: {
23
+ return await response.json();
24
+ }
25
+ default: {
26
+ console.error(
27
+ `Failed to create file ${response.status} ${response.statusText}`
28
+ );
29
+ return;
30
+ }
31
+ }
32
+ };
33
+ const uploadFragmentIndex = async (client, fileId, fileStream) => {
34
+ log("Uploading fragment index", fileId);
35
+ const fileIndex = await client.authenticatedFetch(
36
+ `/api/video2/isobmff_files/${fileId}/index/upload`,
37
+ {
38
+ method: "POST",
39
+ body: nodeStreamToWebStream.nodeStreamToWebStream(fileStream)
40
+ }
41
+ );
42
+ log("Fragment index uploaded", fileIndex);
43
+ switch (fileIndex.status) {
44
+ case 200: {
45
+ return fileIndex.json();
46
+ }
47
+ default: {
48
+ console.error(
49
+ `Failed to create fragment index ${fileIndex.status} ${fileIndex.statusText}`
50
+ );
51
+ return;
52
+ }
53
+ }
54
+ };
55
+ exports.CreateISOBMFFFilePayload = CreateISOBMFFFilePayload;
56
+ exports.createISOBMFFFile = createISOBMFFFile;
57
+ exports.uploadFragmentIndex = uploadFragmentIndex;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import debug from "debug";
3
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream.js";
4
+ const log = debug("ef:api:isobmff-file");
5
+ const CreateISOBMFFFilePayload = z.object({
6
+ id: z.string(),
7
+ filename: z.string()
8
+ });
9
+ const createISOBMFFFile = async (client, payload) => {
10
+ log("Creating isobmff file", payload);
11
+ const response = await client.authenticatedFetch(
12
+ "/api/video2/isobmff_files",
13
+ {
14
+ method: "POST",
15
+ body: JSON.stringify(payload)
16
+ }
17
+ );
18
+ log("ISOBMFF file created", response);
19
+ switch (response.status) {
20
+ case 200: {
21
+ return await response.json();
22
+ }
23
+ default: {
24
+ console.error(
25
+ `Failed to create file ${response.status} ${response.statusText}`
26
+ );
27
+ return;
28
+ }
29
+ }
30
+ };
31
+ const uploadFragmentIndex = async (client, fileId, fileStream) => {
32
+ log("Uploading fragment index", fileId);
33
+ const fileIndex = await client.authenticatedFetch(
34
+ `/api/video2/isobmff_files/${fileId}/index/upload`,
35
+ {
36
+ method: "POST",
37
+ body: nodeStreamToWebStream(fileStream)
38
+ }
39
+ );
40
+ log("Fragment index uploaded", fileIndex);
41
+ switch (fileIndex.status) {
42
+ case 200: {
43
+ return fileIndex.json();
44
+ }
45
+ default: {
46
+ console.error(
47
+ `Failed to create fragment index ${fileIndex.status} ${fileIndex.statusText}`
48
+ );
49
+ return;
50
+ }
51
+ }
52
+ };
53
+ export {
54
+ CreateISOBMFFFilePayload,
55
+ createISOBMFFFile,
56
+ uploadFragmentIndex
57
+ };
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const zod = require("zod");
4
+ const debug = require("debug");
5
+ const assets = require("@editframe/assets");
6
+ const nodeStreamToWebStream = require("../util/nodeStreamToWebStream.cjs");
7
+ const log = debug("ef:api:isobmff-track");
8
+ const CreateISOBMFFTrackPayload = zod.z.discriminatedUnion("type", [
9
+ zod.z.object({
10
+ file_id: zod.z.string(),
11
+ track_id: zod.z.number().int(),
12
+ type: zod.z.literal("audio"),
13
+ probe_info: assets.AudioStreamSchema,
14
+ duration_ms: zod.z.number().int(),
15
+ codec_name: zod.z.string(),
16
+ byte_size: zod.z.number().int()
17
+ }),
18
+ zod.z.object({
19
+ file_id: zod.z.string(),
20
+ track_id: zod.z.number().int(),
21
+ type: zod.z.literal("video"),
22
+ probe_info: assets.VideoStreamSchema,
23
+ duration_ms: zod.z.number().int(),
24
+ codec_name: zod.z.string(),
25
+ byte_size: zod.z.number().int()
26
+ })
27
+ ]);
28
+ const createISOBMFFTrack = async (client, payload) => {
29
+ log("Creating isobmff track", payload);
30
+ const response = await client.authenticatedFetch(
31
+ "/api/video2/isobmff_tracks",
32
+ {
33
+ method: "POST",
34
+ body: JSON.stringify(payload)
35
+ }
36
+ );
37
+ log("ISOBMFF track created", response);
38
+ switch (response.status) {
39
+ case 200: {
40
+ return await response.json();
41
+ }
42
+ default: {
43
+ console.error("Failed to create track");
44
+ console.error(await response.json());
45
+ return;
46
+ }
47
+ }
48
+ };
49
+ const uploadISOBMFFTrack = async (client, fileId, trackId, fileStream) => {
50
+ log("Uploading isobmff track", fileId, trackId);
51
+ const trackIndex = await client.authenticatedFetch(
52
+ `/api/video2/isobmff_tracks/${fileId}/${trackId}/upload`,
53
+ {
54
+ method: "POST",
55
+ body: nodeStreamToWebStream.nodeStreamToWebStream(fileStream)
56
+ }
57
+ );
58
+ log("ISOBMFF track uploaded", trackIndex);
59
+ switch (trackIndex.status) {
60
+ case 200: {
61
+ return trackIndex.json();
62
+ }
63
+ default: {
64
+ console.error("Failed to upload track");
65
+ console.error(trackIndex.status, trackIndex.statusText);
66
+ return;
67
+ }
68
+ }
69
+ };
70
+ exports.CreateISOBMFFTrackPayload = CreateISOBMFFTrackPayload;
71
+ exports.createISOBMFFTrack = createISOBMFFTrack;
72
+ exports.uploadISOBMFFTrack = uploadISOBMFFTrack;
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import debug from "debug";
3
+ import { AudioStreamSchema, VideoStreamSchema } from "@editframe/assets";
4
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream.js";
5
+ const log = debug("ef:api:isobmff-track");
6
+ const CreateISOBMFFTrackPayload = z.discriminatedUnion("type", [
7
+ z.object({
8
+ file_id: z.string(),
9
+ track_id: z.number().int(),
10
+ type: z.literal("audio"),
11
+ probe_info: AudioStreamSchema,
12
+ duration_ms: z.number().int(),
13
+ codec_name: z.string(),
14
+ byte_size: z.number().int()
15
+ }),
16
+ z.object({
17
+ file_id: z.string(),
18
+ track_id: z.number().int(),
19
+ type: z.literal("video"),
20
+ probe_info: VideoStreamSchema,
21
+ duration_ms: z.number().int(),
22
+ codec_name: z.string(),
23
+ byte_size: z.number().int()
24
+ })
25
+ ]);
26
+ const createISOBMFFTrack = async (client, payload) => {
27
+ log("Creating isobmff track", payload);
28
+ const response = await client.authenticatedFetch(
29
+ "/api/video2/isobmff_tracks",
30
+ {
31
+ method: "POST",
32
+ body: JSON.stringify(payload)
33
+ }
34
+ );
35
+ log("ISOBMFF track created", response);
36
+ switch (response.status) {
37
+ case 200: {
38
+ return await response.json();
39
+ }
40
+ default: {
41
+ console.error("Failed to create track");
42
+ console.error(await response.json());
43
+ return;
44
+ }
45
+ }
46
+ };
47
+ const uploadISOBMFFTrack = async (client, fileId, trackId, fileStream) => {
48
+ log("Uploading isobmff track", fileId, trackId);
49
+ const trackIndex = await client.authenticatedFetch(
50
+ `/api/video2/isobmff_tracks/${fileId}/${trackId}/upload`,
51
+ {
52
+ method: "POST",
53
+ body: nodeStreamToWebStream(fileStream)
54
+ }
55
+ );
56
+ log("ISOBMFF track uploaded", trackIndex);
57
+ switch (trackIndex.status) {
58
+ case 200: {
59
+ return trackIndex.json();
60
+ }
61
+ default: {
62
+ console.error("Failed to upload track");
63
+ console.error(trackIndex.status, trackIndex.statusText);
64
+ return;
65
+ }
66
+ }
67
+ };
68
+ export {
69
+ CreateISOBMFFTrackPayload,
70
+ createISOBMFFTrack,
71
+ uploadISOBMFFTrack
72
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const zod = require("zod");
4
+ const debug = require("debug");
5
+ const nodeStreamToWebStream = require("../util/nodeStreamToWebStream.cjs");
6
+ const log = debug("ef:api:renders");
7
+ const CreateRenderPayload = zod.z.object({
8
+ id: zod.z.string().uuid(),
9
+ fps: zod.z.number(),
10
+ width: zod.z.number().int(),
11
+ height: zod.z.number().int(),
12
+ work_slice_ms: zod.z.number().int(),
13
+ duration_ms: zod.z.number().int(),
14
+ strategy: zod.z.enum(["v1", "v2"])
15
+ });
16
+ const createRender = async (client, payload) => {
17
+ log("Creating render", payload);
18
+ const response = await client.authenticatedFetch("/api/video2/renders", {
19
+ method: "POST",
20
+ body: JSON.stringify(payload)
21
+ });
22
+ log("Render created", response);
23
+ switch (response.status) {
24
+ case 200: {
25
+ return await response.json();
26
+ }
27
+ default: {
28
+ console.error("Failed to create render");
29
+ console.error(await response.json());
30
+ return;
31
+ }
32
+ }
33
+ };
34
+ const uploadRender = async (client, fileId, fileStream) => {
35
+ log("Uploading render", fileId);
36
+ const fileIndex = await client.authenticatedFetch(
37
+ `/api/video2/renders/${fileId}/upload`,
38
+ {
39
+ method: "POST",
40
+ body: nodeStreamToWebStream.nodeStreamToWebStream(fileStream)
41
+ }
42
+ );
43
+ log("Render uploaded", fileIndex);
44
+ switch (fileIndex.status) {
45
+ case 200: {
46
+ return fileIndex.json();
47
+ }
48
+ default: {
49
+ console.error("Failed to upload render");
50
+ console.error(fileIndex.status, fileIndex.statusText);
51
+ return;
52
+ }
53
+ }
54
+ };
55
+ exports.CreateRenderPayload = CreateRenderPayload;
56
+ exports.createRender = createRender;
57
+ exports.uploadRender = uploadRender;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import debug from "debug";
3
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream.js";
4
+ const log = debug("ef:api:renders");
5
+ const CreateRenderPayload = z.object({
6
+ id: z.string().uuid(),
7
+ fps: z.number(),
8
+ width: z.number().int(),
9
+ height: z.number().int(),
10
+ work_slice_ms: z.number().int(),
11
+ duration_ms: z.number().int(),
12
+ strategy: z.enum(["v1", "v2"])
13
+ });
14
+ const createRender = async (client, payload) => {
15
+ log("Creating render", payload);
16
+ const response = await client.authenticatedFetch("/api/video2/renders", {
17
+ method: "POST",
18
+ body: JSON.stringify(payload)
19
+ });
20
+ log("Render created", response);
21
+ switch (response.status) {
22
+ case 200: {
23
+ return await response.json();
24
+ }
25
+ default: {
26
+ console.error("Failed to create render");
27
+ console.error(await response.json());
28
+ return;
29
+ }
30
+ }
31
+ };
32
+ const uploadRender = async (client, fileId, fileStream) => {
33
+ log("Uploading render", fileId);
34
+ const fileIndex = await client.authenticatedFetch(
35
+ `/api/video2/renders/${fileId}/upload`,
36
+ {
37
+ method: "POST",
38
+ body: nodeStreamToWebStream(fileStream)
39
+ }
40
+ );
41
+ log("Render uploaded", fileIndex);
42
+ switch (fileIndex.status) {
43
+ case 200: {
44
+ return fileIndex.json();
45
+ }
46
+ default: {
47
+ console.error("Failed to upload render");
48
+ console.error(fileIndex.status, fileIndex.statusText);
49
+ return;
50
+ }
51
+ }
52
+ };
53
+ export {
54
+ CreateRenderPayload,
55
+ createRender,
56
+ uploadRender
57
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const nodeStreamToWebStream = (nodeStream) => {
4
+ return new ReadableStream({
5
+ start(controller) {
6
+ nodeStream.on("data", (chunk) => {
7
+ controller.enqueue(chunk);
8
+ });
9
+ nodeStream.on("end", () => {
10
+ controller.close();
11
+ });
12
+ nodeStream.on("error", (err) => {
13
+ controller.error(err);
14
+ });
15
+ },
16
+ cancel() {
17
+ nodeStream.destroy();
18
+ }
19
+ });
20
+ };
21
+ exports.nodeStreamToWebStream = nodeStreamToWebStream;
@@ -0,0 +1,21 @@
1
+ const nodeStreamToWebStream = (nodeStream) => {
2
+ return new ReadableStream({
3
+ start(controller) {
4
+ nodeStream.on("data", (chunk) => {
5
+ controller.enqueue(chunk);
6
+ });
7
+ nodeStream.on("end", () => {
8
+ controller.close();
9
+ });
10
+ nodeStream.on("error", (err) => {
11
+ controller.error(err);
12
+ });
13
+ },
14
+ cancel() {
15
+ nodeStream.destroy();
16
+ }
17
+ });
18
+ };
19
+ export {
20
+ nodeStreamToWebStream
21
+ };
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@editframe/api",
3
+ "version": "0.7.0-beta.4",
4
+ "description": "API functions for EditFrame",
5
+ "exports": {
6
+ ".": {
7
+ "import": "./dist/index.js",
8
+ "require": "./dist/index.cjs",
9
+ "default": "./dist/index.js"
10
+ }
11
+ },
12
+ "types": "./dist/index.d.ts",
13
+ "type": "module",
14
+ "scripts": {
15
+ "typecheck": "tsc --noEmit --emitDeclarationOnly false",
16
+ "build": "vite build",
17
+ "build:watch": "vite build --watch"
18
+ },
19
+ "author": "",
20
+ "license": "UNLICENSED",
21
+ "devDependencies": {
22
+ "@types/node": "^20.14.9",
23
+ "typescript": "^5.2.2",
24
+ "vite": "^5.2.11",
25
+ "vite-plugin-dts": "^3.9.1",
26
+ "vite-tsconfig-paths": "^4.3.2"
27
+ },
28
+ "dependencies": {
29
+ "@editframe/assets": "0.7.0-beta.4",
30
+ "debug": "^4.3.5",
31
+ "zod": "^3.23.8"
32
+ }
33
+ }
@@ -0,0 +1,73 @@
1
+ import type { Readable } from "node:stream";
2
+
3
+ import { z } from "zod";
4
+ import debug from "debug";
5
+
6
+ import type { Client } from "../client";
7
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream";
8
+
9
+ const log = debug("ef:api:caption-file");
10
+
11
+ export const CreateCaptionFilePayload = z.object({
12
+ id: z.string(),
13
+ filename: z.string(),
14
+ });
15
+
16
+ export interface CreateCaptionFileResult {
17
+ complete: boolean | null;
18
+ id: string;
19
+ }
20
+
21
+ export const createCaptionFile = async (
22
+ client: Client,
23
+ payload: z.infer<typeof CreateCaptionFilePayload>,
24
+ ) => {
25
+ log("Creating caption file", payload);
26
+ const fileCreation = await client.authenticatedFetch(
27
+ "/api/video2/caption_files",
28
+ {
29
+ method: "POST",
30
+ body: JSON.stringify(payload),
31
+ },
32
+ );
33
+ log("Caption file created", fileCreation);
34
+
35
+ switch (fileCreation.status) {
36
+ case 200: {
37
+ return (await fileCreation.json()) as CreateCaptionFileResult;
38
+ }
39
+ default: {
40
+ console.error(
41
+ `Failed to create file ${fileCreation.status} ${fileCreation.statusText}`,
42
+ );
43
+ return;
44
+ }
45
+ }
46
+ };
47
+
48
+ export const uploadCaptionFile = async (
49
+ client: Client,
50
+ fileId: string,
51
+ fileStream: Readable,
52
+ ) => {
53
+ log("Uploading caption file", fileId);
54
+ const fileIndex = await client.authenticatedFetch(
55
+ `/api/video2/caption_files/${fileId}/upload`,
56
+ {
57
+ method: "POST",
58
+ body: nodeStreamToWebStream(fileStream),
59
+ },
60
+ );
61
+ log("Caption file uploaded", fileIndex);
62
+ switch (fileIndex.status) {
63
+ case 200: {
64
+ return fileIndex.json();
65
+ }
66
+ default: {
67
+ console.error(
68
+ `Failed to upload caption ${fileIndex.status} ${fileIndex.statusText}`,
69
+ );
70
+ return;
71
+ }
72
+ }
73
+ };
@@ -0,0 +1,69 @@
1
+ import type { Readable } from "node:stream";
2
+
3
+ import { z } from "zod";
4
+ import debug from "debug";
5
+
6
+ import type { Client } from "../client";
7
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream";
8
+
9
+ const log = debug("ef:api:image-file");
10
+
11
+ export const CreateImageFilePayload = z.object({
12
+ id: z.string(),
13
+ height: z.number().int(),
14
+ width: z.number().int(),
15
+ mime_type: z.enum(["image/jpeg", "image/png", "image/jpg", "image/webp"]),
16
+ filename: z.string(),
17
+ });
18
+
19
+ export interface CreateImageFileResult {
20
+ complete: boolean | null;
21
+ id: string;
22
+ }
23
+
24
+ export const createImageFile = async (
25
+ client: Client,
26
+ payload: z.infer<typeof CreateImageFilePayload>,
27
+ ) => {
28
+ log("Creating image file", payload);
29
+ const response = await client.authenticatedFetch("/api/video2/image_files", {
30
+ method: "POST",
31
+ body: JSON.stringify(payload),
32
+ });
33
+
34
+ log("Image file created", response);
35
+ switch (response.status) {
36
+ case 200: {
37
+ return (await response.json()) as CreateImageFileResult;
38
+ }
39
+ default: {
40
+ console.error(
41
+ `Failed to create file ${response.status} ${response.statusText}`,
42
+ );
43
+ return;
44
+ }
45
+ }
46
+ };
47
+
48
+ export const uploadImageFile = async (
49
+ client: Client,
50
+ fileId: string,
51
+ fileStream: Readable,
52
+ ) => {
53
+ const fileIndex = await client.authenticatedFetch(
54
+ `/api/video2/image_files/${fileId}/upload`,
55
+ {
56
+ method: "POST",
57
+ body: nodeStreamToWebStream(fileStream),
58
+ },
59
+ );
60
+ switch (fileIndex.status) {
61
+ case 200: {
62
+ return fileIndex.json();
63
+ }
64
+ default: {
65
+ console.error("Failed to upload image");
66
+ return;
67
+ }
68
+ }
69
+ };
@@ -0,0 +1,75 @@
1
+ import type { Readable } from "node:stream";
2
+
3
+ import { z } from "zod";
4
+ import debug from "debug";
5
+
6
+ import type { Client } from "../client";
7
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream";
8
+
9
+ const log = debug("ef:api:isobmff-file");
10
+
11
+ export const CreateISOBMFFFilePayload = z.object({
12
+ id: z.string(),
13
+ filename: z.string(),
14
+ });
15
+
16
+ export interface CreateISOBMFFFileResult {
17
+ fragment_index_complete: boolean;
18
+ id: string;
19
+ }
20
+
21
+ export const createISOBMFFFile = async (
22
+ client: Client,
23
+ payload: z.infer<typeof CreateISOBMFFFilePayload>,
24
+ ) => {
25
+ log("Creating isobmff file", payload);
26
+ const response = await client.authenticatedFetch(
27
+ "/api/video2/isobmff_files",
28
+ {
29
+ method: "POST",
30
+ body: JSON.stringify(payload),
31
+ },
32
+ );
33
+
34
+ log("ISOBMFF file created", response);
35
+
36
+ switch (response.status) {
37
+ case 200: {
38
+ return (await response.json()) as CreateISOBMFFFileResult;
39
+ }
40
+ default: {
41
+ console.error(
42
+ `Failed to create file ${response.status} ${response.statusText}`,
43
+ );
44
+ return;
45
+ }
46
+ }
47
+ };
48
+
49
+ export const uploadFragmentIndex = async (
50
+ client: Client,
51
+ fileId: string,
52
+ fileStream: Readable,
53
+ ) => {
54
+ log("Uploading fragment index", fileId);
55
+ const fileIndex = await client.authenticatedFetch(
56
+ `/api/video2/isobmff_files/${fileId}/index/upload`,
57
+ {
58
+ method: "POST",
59
+ body: nodeStreamToWebStream(fileStream),
60
+ },
61
+ );
62
+
63
+ log("Fragment index uploaded", fileIndex);
64
+ switch (fileIndex.status) {
65
+ case 200: {
66
+ return fileIndex.json();
67
+ }
68
+ default: {
69
+ console.error(
70
+ `Failed to create fragment index ${fileIndex.status} ${fileIndex.statusText}`,
71
+ );
72
+ return;
73
+ }
74
+ }
75
+ };
@@ -0,0 +1,93 @@
1
+ import type { Readable } from "node:stream";
2
+
3
+ import { z } from "zod";
4
+ import debug from "debug";
5
+
6
+ import { AudioStreamSchema, VideoStreamSchema } from "@editframe/assets";
7
+
8
+ import type { Client } from "../client";
9
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream";
10
+
11
+ const log = debug("ef:api:isobmff-track");
12
+
13
+ export const CreateISOBMFFTrackPayload = z.discriminatedUnion("type", [
14
+ z.object({
15
+ file_id: z.string(),
16
+ track_id: z.number().int(),
17
+ type: z.literal("audio"),
18
+ probe_info: AudioStreamSchema,
19
+ duration_ms: z.number().int(),
20
+ codec_name: z.string(),
21
+ byte_size: z.number().int(),
22
+ }),
23
+ z.object({
24
+ file_id: z.string(),
25
+ track_id: z.number().int(),
26
+ type: z.literal("video"),
27
+ probe_info: VideoStreamSchema,
28
+ duration_ms: z.number().int(),
29
+ codec_name: z.string(),
30
+ byte_size: z.number().int(),
31
+ }),
32
+ ]);
33
+
34
+ export interface CreateISOBMFFTrackResult {
35
+ last_received_byte: number;
36
+ byte_size: number;
37
+ track_id: number;
38
+ file_id: string;
39
+ }
40
+
41
+ export const createISOBMFFTrack = async (
42
+ client: Client,
43
+ payload: z.infer<typeof CreateISOBMFFTrackPayload>,
44
+ ) => {
45
+ log("Creating isobmff track", payload);
46
+ const response = await client.authenticatedFetch(
47
+ "/api/video2/isobmff_tracks",
48
+ {
49
+ method: "POST",
50
+ body: JSON.stringify(payload),
51
+ },
52
+ );
53
+
54
+ log("ISOBMFF track created", response);
55
+ switch (response.status) {
56
+ case 200: {
57
+ return (await response.json()) as CreateISOBMFFTrackResult;
58
+ }
59
+ default: {
60
+ console.error("Failed to create track");
61
+ console.error(await response.json());
62
+ return;
63
+ }
64
+ }
65
+ };
66
+
67
+ export const uploadISOBMFFTrack = async (
68
+ client: Client,
69
+ fileId: string,
70
+ trackId: number,
71
+ fileStream: Readable,
72
+ ) => {
73
+ log("Uploading isobmff track", fileId, trackId);
74
+ const trackIndex = await client.authenticatedFetch(
75
+ `/api/video2/isobmff_tracks/${fileId}/${trackId}/upload`,
76
+ {
77
+ method: "POST",
78
+ body: nodeStreamToWebStream(fileStream),
79
+ },
80
+ );
81
+
82
+ log("ISOBMFF track uploaded", trackIndex);
83
+ switch (trackIndex.status) {
84
+ case 200: {
85
+ return trackIndex.json();
86
+ }
87
+ default: {
88
+ console.error("Failed to upload track");
89
+ console.error(trackIndex.status, trackIndex.statusText);
90
+ return;
91
+ }
92
+ }
93
+ };
@@ -0,0 +1,74 @@
1
+ import type { Readable } from "node:stream";
2
+
3
+ import { z } from "zod";
4
+ import debug from "debug";
5
+
6
+ import type { Client } from "../client";
7
+ import { nodeStreamToWebStream } from "../util/nodeStreamToWebStream";
8
+
9
+ const log = debug("ef:api:renders");
10
+
11
+ export const CreateRenderPayload = z.object({
12
+ id: z.string().uuid(),
13
+ fps: z.number(),
14
+ width: z.number().int(),
15
+ height: z.number().int(),
16
+ work_slice_ms: z.number().int(),
17
+ duration_ms: z.number().int(),
18
+ strategy: z.enum(["v1", "v2"]),
19
+ });
20
+
21
+ export interface CreateRenderResult {
22
+ status: "complete" | "created" | "failed" | "pending" | "rendering";
23
+ id: string;
24
+ }
25
+
26
+ export const createRender = async (
27
+ client: Client,
28
+ payload: z.infer<typeof CreateRenderPayload>,
29
+ ) => {
30
+ log("Creating render", payload);
31
+ const response = await client.authenticatedFetch("/api/video2/renders", {
32
+ method: "POST",
33
+ body: JSON.stringify(payload),
34
+ });
35
+
36
+ log("Render created", response);
37
+ switch (response.status) {
38
+ case 200: {
39
+ return (await response.json()) as CreateRenderResult;
40
+ }
41
+ default: {
42
+ console.error("Failed to create render");
43
+ console.error(await response.json());
44
+ return;
45
+ }
46
+ }
47
+ };
48
+
49
+ export const uploadRender = async (
50
+ client: Client,
51
+ fileId: string,
52
+ fileStream: Readable,
53
+ ) => {
54
+ log("Uploading render", fileId);
55
+ const fileIndex = await client.authenticatedFetch(
56
+ `/api/video2/renders/${fileId}/upload`,
57
+ {
58
+ method: "POST",
59
+ body: nodeStreamToWebStream(fileStream),
60
+ },
61
+ );
62
+
63
+ log("Render uploaded", fileIndex);
64
+ switch (fileIndex.status) {
65
+ case 200: {
66
+ return fileIndex.json();
67
+ }
68
+ default: {
69
+ console.error("Failed to upload render");
70
+ console.error(fileIndex.status, fileIndex.statusText);
71
+ return;
72
+ }
73
+ }
74
+ };
@@ -0,0 +1,20 @@
1
+ import type { Readable } from "node:stream";
2
+
3
+ export const nodeStreamToWebStream = (nodeStream: Readable): ReadableStream => {
4
+ return new ReadableStream({
5
+ start(controller) {
6
+ nodeStream.on("data", (chunk) => {
7
+ controller.enqueue(chunk);
8
+ });
9
+ nodeStream.on("end", () => {
10
+ controller.close();
11
+ });
12
+ nodeStream.on("error", (err) => {
13
+ controller.error(err);
14
+ });
15
+ },
16
+ cancel() {
17
+ nodeStream.destroy();
18
+ },
19
+ });
20
+ };