@editframe/api 0.13.0-beta.3 → 0.14.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { PassThrough } from "node:stream";
|
|
3
|
+
import react from "@vitejs/plugin-react";
|
|
4
|
+
import { build } from "vite";
|
|
5
|
+
import { viteSingleFile } from "vite-plugin-singlefile";
|
|
6
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
7
|
+
import * as tar from "tar";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.js";
|
|
10
|
+
const bundleRender = async (options) => {
|
|
11
|
+
const outDir = path.join(process.cwd(), "renders", randomUUID());
|
|
12
|
+
console.log("outDir", outDir);
|
|
13
|
+
await build({
|
|
14
|
+
root: options.root,
|
|
15
|
+
define: {
|
|
16
|
+
RENDER_DATA: JSON.stringify(options.renderData)
|
|
17
|
+
},
|
|
18
|
+
build: {
|
|
19
|
+
outDir,
|
|
20
|
+
rollupOptions: {
|
|
21
|
+
input: path.resolve(options.root, "index.html")
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
plugins: [
|
|
25
|
+
tsconfigPaths(),
|
|
26
|
+
react({
|
|
27
|
+
include: "**/*.{jsx,js,tsx,ts}",
|
|
28
|
+
jsxRuntime: "automatic"
|
|
29
|
+
}),
|
|
30
|
+
viteSingleFile()
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
const tarStream = tar.create(
|
|
34
|
+
{
|
|
35
|
+
gzip: true,
|
|
36
|
+
cwd: outDir
|
|
37
|
+
},
|
|
38
|
+
["."]
|
|
39
|
+
);
|
|
40
|
+
console.log("outDir", outDir);
|
|
41
|
+
const passthrough = new PassThrough();
|
|
42
|
+
tarStream.pipe(passthrough);
|
|
43
|
+
const tarReadStream = createReadableStreamFromReadable(passthrough);
|
|
44
|
+
return tarReadStream;
|
|
45
|
+
};
|
|
46
|
+
export {
|
|
47
|
+
bundleRender
|
|
48
|
+
};
|
|
@@ -4,36 +4,36 @@ import { Client } from '../client.js';
|
|
|
4
4
|
export declare const CreateRenderPayload: z.ZodObject<{
|
|
5
5
|
md5: z.ZodOptional<z.ZodString>;
|
|
6
6
|
fps: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
7
|
-
width: z.ZodNumber
|
|
8
|
-
height: z.ZodNumber
|
|
7
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
9
9
|
work_slice_ms: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
10
|
-
duration_ms: z.ZodNumber
|
|
11
|
-
strategy: z.ZodOptional<z.ZodDefault<z.ZodEnum<["v1"
|
|
10
|
+
duration_ms: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
strategy: z.ZodOptional<z.ZodDefault<z.ZodEnum<["v1"]>>>;
|
|
12
12
|
}, "strip", z.ZodTypeAny, {
|
|
13
|
-
width
|
|
14
|
-
height
|
|
15
|
-
duration_ms: number;
|
|
13
|
+
width?: number | undefined;
|
|
14
|
+
height?: number | undefined;
|
|
16
15
|
md5?: string | undefined;
|
|
17
|
-
strategy?: "v1" |
|
|
16
|
+
strategy?: "v1" | undefined;
|
|
17
|
+
duration_ms?: number | undefined;
|
|
18
18
|
fps?: number | undefined;
|
|
19
19
|
work_slice_ms?: number | undefined;
|
|
20
20
|
}, {
|
|
21
|
-
width
|
|
22
|
-
height
|
|
23
|
-
duration_ms: number;
|
|
21
|
+
width?: number | undefined;
|
|
22
|
+
height?: number | undefined;
|
|
24
23
|
md5?: string | undefined;
|
|
25
|
-
strategy?: "v1" |
|
|
24
|
+
strategy?: "v1" | undefined;
|
|
25
|
+
duration_ms?: number | undefined;
|
|
26
26
|
fps?: number | undefined;
|
|
27
27
|
work_slice_ms?: number | undefined;
|
|
28
28
|
}>;
|
|
29
29
|
export interface CreateRenderPayload {
|
|
30
30
|
md5?: string;
|
|
31
31
|
fps?: number;
|
|
32
|
-
width
|
|
33
|
-
height
|
|
32
|
+
width?: number;
|
|
33
|
+
height?: number;
|
|
34
34
|
work_slice_ms?: number;
|
|
35
|
-
duration_ms
|
|
36
|
-
strategy?: "v1"
|
|
35
|
+
duration_ms?: number;
|
|
36
|
+
strategy?: "v1";
|
|
37
37
|
}
|
|
38
38
|
export interface CreateRenderResult {
|
|
39
39
|
id: string;
|
|
@@ -46,7 +46,7 @@ export interface LookupRenderByMd5Result {
|
|
|
46
46
|
status: "complete" | "created" | "failed" | "pending" | "rendering" | string;
|
|
47
47
|
}
|
|
48
48
|
export declare const createRender: (client: Client, payload: CreateRenderPayload) => Promise<CreateRenderResult>;
|
|
49
|
-
export declare const uploadRender: (client: Client,
|
|
49
|
+
export declare const uploadRender: (client: Client, renderId: string, fileStream: ReadableStream) => Promise<any>;
|
|
50
50
|
export declare const getRenderInfo: (client: Client, id: string) => Promise<LookupRenderByMd5Result>;
|
|
51
51
|
export declare const lookupRenderByMd5: (client: Client, md5: string) => Promise<LookupRenderByMd5Result | null>;
|
|
52
52
|
export declare const getRenderProgress: (client: Client, id: string) => Promise<CompletionIterator>;
|
|
@@ -5,14 +5,16 @@ const log = debug("ef:api:renders");
|
|
|
5
5
|
const CreateRenderPayload = z.object({
|
|
6
6
|
md5: z.string().optional(),
|
|
7
7
|
fps: z.number().int().min(1).max(120).default(30).optional(),
|
|
8
|
-
width: z.number().int().min(2),
|
|
9
|
-
height: z.number().int().min(2),
|
|
8
|
+
width: z.number().int().min(2).optional(),
|
|
9
|
+
height: z.number().int().min(2).optional(),
|
|
10
10
|
work_slice_ms: z.number().int().min(1e3).max(1e4).default(4e3).optional(),
|
|
11
|
-
duration_ms: z.number().int(),
|
|
12
|
-
strategy: z.enum(["v1"
|
|
11
|
+
duration_ms: z.number().int().optional(),
|
|
12
|
+
strategy: z.enum(["v1"]).default("v1").optional()
|
|
13
13
|
});
|
|
14
14
|
const createRender = async (client, payload) => {
|
|
15
15
|
log("Creating render", payload);
|
|
16
|
+
payload.strategy ??= "v1";
|
|
17
|
+
payload.work_slice_ms ??= 4e3;
|
|
16
18
|
const response = await client.authenticatedFetch("/api/v1/renders", {
|
|
17
19
|
method: "POST",
|
|
18
20
|
body: JSON.stringify(payload)
|
|
@@ -25,10 +27,10 @@ const createRender = async (client, payload) => {
|
|
|
25
27
|
`Failed to create render ${response.status} ${response.statusText} ${await response.text()}`
|
|
26
28
|
);
|
|
27
29
|
};
|
|
28
|
-
const uploadRender = async (client,
|
|
29
|
-
log("Uploading render",
|
|
30
|
+
const uploadRender = async (client, renderId, fileStream) => {
|
|
31
|
+
log("Uploading render", renderId);
|
|
30
32
|
const response = await client.authenticatedFetch(
|
|
31
|
-
`/api/v1/renders/${
|
|
33
|
+
`/api/v1/renders/${renderId}/upload`,
|
|
32
34
|
{
|
|
33
35
|
method: "POST",
|
|
34
36
|
body: fileStream,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0-beta.1",
|
|
4
4
|
"description": "API functions for EditFrame",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
"types": "./dist/node.d.ts",
|
|
15
15
|
"default": "./dist/node.js"
|
|
16
16
|
}
|
|
17
|
+
},
|
|
18
|
+
"./bundleRender": {
|
|
19
|
+
"import": {
|
|
20
|
+
"types": "./dist/resources/renders.bundle.d.ts",
|
|
21
|
+
"default": "./dist/resources/renders.bundle.js"
|
|
22
|
+
}
|
|
17
23
|
}
|
|
18
24
|
},
|
|
19
25
|
"type": "module",
|
|
@@ -35,12 +41,15 @@
|
|
|
35
41
|
"vite-tsconfig-paths": "^4.3.2"
|
|
36
42
|
},
|
|
37
43
|
"dependencies": {
|
|
38
|
-
"@editframe/assets": "0.
|
|
44
|
+
"@editframe/assets": "0.14.0-beta.1",
|
|
45
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
39
46
|
"debug": "^4.3.5",
|
|
40
47
|
"eventsource-parser": "^3.0.0",
|
|
41
48
|
"jsonwebtoken": "^9.0.2",
|
|
42
49
|
"mime": "^4.0.4",
|
|
43
50
|
"node-fetch": "^3.3.2",
|
|
51
|
+
"tar": "^7.4.3",
|
|
52
|
+
"vite-plugin-singlefile": "^2.1.0",
|
|
44
53
|
"zod": "^3.23.8"
|
|
45
54
|
}
|
|
46
55
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { PassThrough } from "node:stream";
|
|
3
|
+
|
|
4
|
+
import react from "@vitejs/plugin-react";
|
|
5
|
+
import { build } from "vite";
|
|
6
|
+
import { viteSingleFile } from "vite-plugin-singlefile";
|
|
7
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
8
|
+
|
|
9
|
+
import * as tar from "tar";
|
|
10
|
+
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.ts";
|
|
13
|
+
|
|
14
|
+
interface BundlerOptions {
|
|
15
|
+
root: string;
|
|
16
|
+
renderData: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const bundleRender = async (options: BundlerOptions) => {
|
|
20
|
+
const outDir = path.join(process.cwd(), "renders", randomUUID());
|
|
21
|
+
|
|
22
|
+
console.log("outDir", outDir);
|
|
23
|
+
|
|
24
|
+
await build({
|
|
25
|
+
root: options.root,
|
|
26
|
+
define: {
|
|
27
|
+
RENDER_DATA: JSON.stringify(options.renderData),
|
|
28
|
+
},
|
|
29
|
+
build: {
|
|
30
|
+
outDir,
|
|
31
|
+
rollupOptions: {
|
|
32
|
+
input: path.resolve(options.root, "index.html"),
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
plugins: [
|
|
36
|
+
tsconfigPaths(),
|
|
37
|
+
react({
|
|
38
|
+
include: "**/*.{jsx,js,tsx,ts}",
|
|
39
|
+
jsxRuntime: "automatic",
|
|
40
|
+
}),
|
|
41
|
+
viteSingleFile(),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const tarStream = tar.create(
|
|
46
|
+
{
|
|
47
|
+
gzip: true,
|
|
48
|
+
cwd: outDir,
|
|
49
|
+
},
|
|
50
|
+
["."],
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
console.log("outDir", outDir);
|
|
54
|
+
|
|
55
|
+
const passthrough = new PassThrough();
|
|
56
|
+
tarStream.pipe(passthrough);
|
|
57
|
+
const tarReadStream = createReadableStreamFromReadable(passthrough);
|
|
58
|
+
|
|
59
|
+
return tarReadStream;
|
|
60
|
+
};
|
package/src/resources/renders.ts
CHANGED
|
@@ -10,8 +10,8 @@ const log = debug("ef:api:renders");
|
|
|
10
10
|
export const CreateRenderPayload = z.object({
|
|
11
11
|
md5: z.string().optional(),
|
|
12
12
|
fps: z.number().int().min(1).max(120).default(30).optional(),
|
|
13
|
-
width: z.number().int().min(2),
|
|
14
|
-
height: z.number().int().min(2),
|
|
13
|
+
width: z.number().int().min(2).optional(),
|
|
14
|
+
height: z.number().int().min(2).optional(),
|
|
15
15
|
work_slice_ms: z
|
|
16
16
|
.number()
|
|
17
17
|
.int()
|
|
@@ -19,18 +19,18 @@ export const CreateRenderPayload = z.object({
|
|
|
19
19
|
.max(10_000)
|
|
20
20
|
.default(4_000)
|
|
21
21
|
.optional(),
|
|
22
|
-
duration_ms: z.number().int(),
|
|
23
|
-
strategy: z.enum(["v1"
|
|
22
|
+
duration_ms: z.number().int().optional(),
|
|
23
|
+
strategy: z.enum(["v1"]).default("v1").optional(),
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
export interface CreateRenderPayload {
|
|
27
27
|
md5?: string;
|
|
28
28
|
fps?: number;
|
|
29
|
-
width
|
|
30
|
-
height
|
|
29
|
+
width?: number;
|
|
30
|
+
height?: number;
|
|
31
31
|
work_slice_ms?: number;
|
|
32
|
-
duration_ms
|
|
33
|
-
strategy?: "v1"
|
|
32
|
+
duration_ms?: number;
|
|
33
|
+
strategy?: "v1";
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
assertTypesMatch<CreateRenderPayload, z.infer<typeof CreateRenderPayload>>(
|
|
@@ -54,6 +54,11 @@ export const createRender = async (
|
|
|
54
54
|
payload: CreateRenderPayload,
|
|
55
55
|
) => {
|
|
56
56
|
log("Creating render", payload);
|
|
57
|
+
// FIXME: The order of optional/default matters in zod
|
|
58
|
+
// And if we set the default last, the type is not inferred correctly
|
|
59
|
+
// Manually applying defaults here is a hack
|
|
60
|
+
payload.strategy ??= "v1";
|
|
61
|
+
payload.work_slice_ms ??= 4_000;
|
|
57
62
|
const response = await client.authenticatedFetch("/api/v1/renders", {
|
|
58
63
|
method: "POST",
|
|
59
64
|
body: JSON.stringify(payload),
|
|
@@ -71,12 +76,12 @@ export const createRender = async (
|
|
|
71
76
|
|
|
72
77
|
export const uploadRender = async (
|
|
73
78
|
client: Client,
|
|
74
|
-
|
|
79
|
+
renderId: string,
|
|
75
80
|
fileStream: ReadableStream,
|
|
76
81
|
) => {
|
|
77
|
-
log("Uploading render",
|
|
82
|
+
log("Uploading render", renderId);
|
|
78
83
|
const response = await client.authenticatedFetch(
|
|
79
|
-
`/api/v1/renders/${
|
|
84
|
+
`/api/v1/renders/${renderId}/upload`,
|
|
80
85
|
{
|
|
81
86
|
method: "POST",
|
|
82
87
|
body: fileStream,
|