@editframe/cli 0.16.8-beta.0 → 0.18.3-beta.0

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 (42) hide show
  1. package/dist/VERSION.d.ts +1 -1
  2. package/dist/VERSION.js +2 -4
  3. package/dist/commands/auth.js +16 -25
  4. package/dist/commands/check.js +81 -108
  5. package/dist/commands/mux.d.ts +1 -0
  6. package/dist/commands/preview.js +4 -1
  7. package/dist/commands/process-file.js +18 -34
  8. package/dist/commands/process.js +28 -31
  9. package/dist/commands/render.js +117 -157
  10. package/dist/commands/sync.js +3 -5
  11. package/dist/commands/webhook.js +48 -52
  12. package/dist/index.js +3 -7
  13. package/dist/operations/processRenderInfo.js +25 -31
  14. package/dist/operations/syncAssetsDirectory/SubAssetSync.js +11 -18
  15. package/dist/operations/syncAssetsDirectory/SyncCaption.js +46 -73
  16. package/dist/operations/syncAssetsDirectory/SyncFragmentIndex.js +53 -83
  17. package/dist/operations/syncAssetsDirectory/SyncImage.js +72 -99
  18. package/dist/operations/syncAssetsDirectory/SyncStatus.js +30 -37
  19. package/dist/operations/syncAssetsDirectory/SyncTrack.js +107 -143
  20. package/dist/operations/syncAssetsDirectory/doAssetSync.js +42 -46
  21. package/dist/operations/syncAssetsDirectory.js +55 -78
  22. package/dist/utils/createReadableStreamFromReadable.js +61 -78
  23. package/dist/utils/index.js +10 -16
  24. package/dist/utils/launchBrowserAndWaitForSDK.js +31 -43
  25. package/dist/utils/startDevServer.d.ts +1 -1
  26. package/dist/utils/startPreviewServer.d.ts +1 -1
  27. package/dist/utils/startPreviewServer.js +28 -34
  28. package/dist/utils/validateVideoResolution.js +19 -23
  29. package/dist/utils/withSpinner.js +10 -12
  30. package/package.json +8 -8
  31. package/src/commands/check.ts +2 -2
  32. package/src/commands/mux.ts +10 -0
  33. package/src/operations/syncAssetsDirectory/SyncCaption.test.ts +12 -3
  34. package/src/operations/syncAssetsDirectory/SyncFragmentIndex.test.ts +11 -3
  35. package/src/operations/syncAssetsDirectory/SyncImage.test.ts +12 -3
  36. package/src/operations/syncAssetsDirectory/SyncImage.ts +3 -2
  37. package/src/operations/syncAssetsDirectory/SyncTrack.test.ts +11 -3
  38. package/src/operations/syncAssetsDirectory.test.ts +12 -5
  39. package/src/utils/createReadableStreamFromReadable.ts +3 -7
  40. package/src/utils/startDevServer.ts +5 -5
  41. package/src/utils/startPreviewServer.ts +1 -1
  42. package/test-fixtures/network.ts +38 -9
@@ -1,167 +1,127 @@
1
+ import { getClient } from "../utils/index.js";
2
+ import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.js";
3
+ import { SyncStatus } from "../operations/syncAssetsDirectory/SyncStatus.js";
4
+ import { syncAssetDirectory } from "../operations/syncAssetsDirectory.js";
5
+ import { processRenderInfo } from "../operations/processRenderInfo.js";
6
+ import { withSpinner } from "../utils/withSpinner.js";
7
+ import { launchBrowserAndWaitForSDK } from "../utils/launchBrowserAndWaitForSDK.js";
8
+ import { PreviewServer } from "../utils/startPreviewServer.js";
9
+ import { validateVideoResolution } from "../utils/validateVideoResolution.js";
10
+ import { Option, program } from "commander";
11
+ import debug from "debug";
12
+ import { createRender, uploadRender } from "@editframe/api";
13
+ import path, { basename, join } from "node:path";
1
14
  import { readFile, writeFile } from "node:fs/promises";
2
- import path, { join, basename } from "node:path";
3
15
  import { PassThrough } from "node:stream";
16
+ import { md5Directory, md5FilePath } from "@editframe/assets";
4
17
  import { inspect } from "node:util";
5
- import { program, Option } from "commander";
6
18
  import { parse } from "node-html-parser";
7
19
  import * as tar from "tar";
8
- import { md5Directory, md5FilePath } from "@editframe/assets";
9
20
  import { spawnSync } from "node:child_process";
10
- import { createRender, uploadRender } from "@editframe/api";
11
21
  import { RenderInfo, getRenderInfo } from "@editframe/elements";
12
- import debug from "debug";
13
- import { processRenderInfo } from "../operations/processRenderInfo.js";
14
- import { syncAssetDirectory } from "../operations/syncAssetsDirectory.js";
15
- import { SyncStatus } from "../operations/syncAssetsDirectory/SyncStatus.js";
16
- import { createReadableStreamFromReadable } from "../utils/createReadableStreamFromReadable.js";
17
- import { getClient } from "../utils/index.js";
18
- import { launchBrowserAndWaitForSDK } from "../utils/launchBrowserAndWaitForSDK.js";
19
- import { PreviewServer } from "../utils/startPreviewServer.js";
20
- import { validateVideoResolution } from "../utils/validateVideoResolution.js";
21
- import { withSpinner } from "../utils/withSpinner.js";
22
22
  const log = debug("ef:cli:render");
23
- const buildAssetId = async (srcDir, src, basename2) => {
24
- log(`Building image asset id for ${src}
25
- `);
26
- const assetPath = path.join(srcDir, src);
27
- const assetMd5 = await md5FilePath(assetPath);
28
- const syncStatus = new SyncStatus(
29
- join(srcDir, "assets", ".cache", assetMd5, basename2)
30
- );
31
- const info = await syncStatus.readInfo();
32
- if (!info) {
33
- throw new Error(`SyncStatus info is not found for ${syncStatus.infoPath}`);
34
- }
35
- return info.id;
23
+ const buildAssetId = async (srcDir, src, basename$1) => {
24
+ log(`Building image asset id for ${src}\n`);
25
+ const assetPath = path.join(srcDir, src);
26
+ const assetMd5 = await md5FilePath(assetPath);
27
+ const syncStatus = new SyncStatus(join(srcDir, "assets", ".cache", assetMd5, basename$1));
28
+ const info = await syncStatus.readInfo();
29
+ if (!info) throw new Error(`SyncStatus info is not found for ${syncStatus.infoPath}`);
30
+ return info.id;
36
31
  };
37
- program.command("render [directory]").description(
38
- "Render a directory's index.html file as a video in the editframe cloud"
39
- ).addOption(
40
- new Option("-s, --strategy <strategy>", "Render strategy").choices(["v1"]).default("v1")
41
- ).action(async (directory, options) => {
42
- directory ??= ".";
43
- await syncAssetDirectory(
44
- join(process.cwd(), directory, "src", "assets", ".cache")
45
- );
46
- const srcDir = path.join(directory, "src");
47
- const distDir = path.join(directory, "dist");
48
- await withSpinner("Building\n", async () => {
49
- try {
50
- await withSpinner("Building\n", async () => {
51
- spawnSync(
52
- "npx",
53
- // biome-ignore format: Grouping CLI arguments
54
- [
55
- "vite",
56
- "build",
57
- directory,
58
- "--clearScreen",
59
- "false",
60
- "--logLevel",
61
- "debug"
62
- ],
63
- {
64
- stdio: "inherit"
65
- }
66
- );
67
- });
68
- } catch (error) {
69
- console.error("Build failed:", error);
70
- }
71
- });
72
- const previewServer = await PreviewServer.start(distDir);
73
- process.stderr.write("Preview server started at:");
74
- process.stderr.write(previewServer.url);
75
- process.stderr.write("\n");
76
- await launchBrowserAndWaitForSDK(
77
- {
78
- url: previewServer.url,
79
- efInteractive: false,
80
- interactive: false,
81
- headless: true
82
- },
83
- async (page) => {
84
- const renderInfo = RenderInfo.parse(await page.evaluate(getRenderInfo));
85
- validateVideoResolution({
86
- width: renderInfo.width,
87
- height: renderInfo.height
88
- });
89
- await processRenderInfo(renderInfo);
90
- const doc = parse(
91
- await readFile(path.join(distDir, "index.html"), "utf-8")
92
- );
93
- log("Building asset IDs");
94
- for (const element of doc.querySelectorAll(
95
- "ef-image, ef-audio, ef-video"
96
- )) {
97
- log(`Processing ${element.tagName}`);
98
- if (element.hasAttribute("asset-id")) {
99
- log(
100
- `Asset ID for ${element.tagName} ${element.getAttribute("src")} is ${element.getAttribute("asset-id")}`
101
- );
102
- continue;
103
- }
104
- const src = element.getAttribute("src");
105
- if (!src) {
106
- log(`No src attribute for ${element.tagName}`);
107
- continue;
108
- }
109
- switch (element.tagName) {
110
- case "EF-IMAGE":
111
- element.setAttribute(
112
- "asset-id",
113
- await buildAssetId(srcDir, src, basename(src))
114
- );
115
- break;
116
- case "EF-AUDIO":
117
- case "EF-VIDEO":
118
- element.setAttribute(
119
- "asset-id",
120
- await buildAssetId(srcDir, src, "isobmff")
121
- );
122
- break;
123
- default:
124
- log(`Unknown element type: ${element.tagName}`);
125
- }
126
- }
127
- await writeFile(path.join(distDir, "index.html"), doc.toString());
128
- const md5 = await md5Directory(distDir);
129
- const render = await createRender(getClient(), {
130
- md5,
131
- width: renderInfo.width,
132
- height: renderInfo.height,
133
- fps: renderInfo.fps,
134
- duration_ms: renderInfo.durationMs,
135
- work_slice_ms: 4e3,
136
- strategy: options.strategy
137
- });
138
- if (render?.status !== "created") {
139
- process.stderr.write(
140
- `Render is in '${render?.status}' status. It cannot be recreated while in this status.
141
- `
142
- );
143
- return;
144
- }
145
- const tarStream = tar.create(
146
- {
147
- gzip: true,
148
- cwd: distDir
149
- },
150
- ["."]
151
- );
152
- const readable = new PassThrough();
153
- tarStream.pipe(readable);
154
- await uploadRender(
155
- getClient(),
156
- render.id,
157
- createReadableStreamFromReadable(readable)
158
- );
159
- process.stderr.write("Render assets uploaded\n");
160
- process.stderr.write(inspect(render));
161
- process.stderr.write("\n");
162
- }
163
- );
32
+ program.command("render [directory]").description("Render a directory's index.html file as a video in the editframe cloud").addOption(new Option("-s, --strategy <strategy>", "Render strategy").choices(["v1"]).default("v1")).action(async (directory, options) => {
33
+ directory ??= ".";
34
+ await syncAssetDirectory(join(process.cwd(), directory, "src", "assets", ".cache"));
35
+ const srcDir = path.join(directory, "src");
36
+ const distDir = path.join(directory, "dist");
37
+ await withSpinner("Building\n", async () => {
38
+ try {
39
+ await withSpinner("Building\n", async () => {
40
+ spawnSync("npx", [
41
+ "vite",
42
+ "build",
43
+ directory,
44
+ "--clearScreen",
45
+ "false",
46
+ "--logLevel",
47
+ "debug"
48
+ ], { stdio: "inherit" });
49
+ });
50
+ } catch (error) {
51
+ console.error("Build failed:", error);
52
+ }
53
+ });
54
+ const previewServer = await PreviewServer.start(distDir);
55
+ process.stderr.write("Preview server started at:");
56
+ process.stderr.write(previewServer.url);
57
+ process.stderr.write("\n");
58
+ await launchBrowserAndWaitForSDK({
59
+ url: previewServer.url,
60
+ efInteractive: false,
61
+ interactive: false,
62
+ headless: true
63
+ }, async (page) => {
64
+ const renderInfo = RenderInfo.parse(await page.evaluate(getRenderInfo));
65
+ validateVideoResolution({
66
+ width: renderInfo.width,
67
+ height: renderInfo.height
68
+ });
69
+ await processRenderInfo(renderInfo);
70
+ const doc = parse(await readFile(path.join(distDir, "index.html"), "utf-8"));
71
+ log("Building asset IDs");
72
+ for (const element of doc.querySelectorAll("ef-image, ef-audio, ef-video")) {
73
+ log(`Processing ${element.tagName}`);
74
+ if (element.hasAttribute("asset-id")) {
75
+ log(`Asset ID for ${element.tagName} ${element.getAttribute("src")} is ${element.getAttribute("asset-id")}`);
76
+ continue;
77
+ }
78
+ const src = element.getAttribute("src");
79
+ if (!src) {
80
+ log(`No src attribute for ${element.tagName}`);
81
+ continue;
82
+ }
83
+ switch (element.tagName) {
84
+ case "EF-IMAGE":
85
+ element.setAttribute("asset-id", await buildAssetId(srcDir, src, basename(src)));
86
+ break;
87
+ case "EF-AUDIO":
88
+ case "EF-VIDEO":
89
+ element.setAttribute("asset-id", await buildAssetId(srcDir, src, "isobmff"));
90
+ break;
91
+ default: log(`Unknown element type: ${element.tagName}`);
92
+ }
93
+ }
94
+ await writeFile(path.join(distDir, "index.html"), doc.toString());
95
+ const md5 = await md5Directory(distDir);
96
+ const render = await createRender(getClient(), {
97
+ md5,
98
+ width: renderInfo.width,
99
+ height: renderInfo.height,
100
+ fps: renderInfo.fps,
101
+ duration_ms: renderInfo.durationMs,
102
+ work_slice_ms: 4e3,
103
+ strategy: options.strategy
104
+ });
105
+ if (render?.status !== "created") {
106
+ process.stderr.write(`Render is in '${render?.status}' status. It cannot be recreated while in this status.\n`);
107
+ return;
108
+ }
109
+ /**
110
+ * This tar stream is created with the dist directory as the root.
111
+ * This is acheived by setting the cwd option to the dist directory.
112
+ * And the files to be included in the tar stream are all files in the dist directory.
113
+ *
114
+ * The renderer expects to find the index.html file at the root of the tar stream.
115
+ */
116
+ const tarStream = tar.create({
117
+ gzip: true,
118
+ cwd: distDir
119
+ }, ["."]);
120
+ const readable = new PassThrough();
121
+ tarStream.pipe(readable);
122
+ await uploadRender(getClient(), render.id, createReadableStreamFromReadable(readable));
123
+ process.stderr.write("Render assets uploaded\n");
124
+ process.stderr.write(inspect(render));
125
+ process.stderr.write("\n");
126
+ });
164
127
  });
165
- export {
166
- buildAssetId
167
- };
@@ -1,8 +1,6 @@
1
- import { join } from "node:path";
2
- import { program } from "commander";
3
1
  import { syncAssetDirectory } from "../operations/syncAssetsDirectory.js";
2
+ import { program } from "commander";
3
+ import { join } from "node:path";
4
4
  program.command("sync").description("Sync assets to Editframe servers for rendering").argument("[directory]", "Path to project directory to sync.").action(async (directory = ".") => {
5
- await syncAssetDirectory(
6
- join(process.cwd(), directory, "src", "assets", ".cache")
7
- );
5
+ await syncAssetDirectory(join(process.cwd(), directory, "src", "assets", ".cache"));
8
6
  });
@@ -1,61 +1,57 @@
1
- import { input, select } from "@inquirer/prompts";
1
+ import { getClient } from "../utils/index.js";
2
+ import { Option, program } from "commander";
2
3
  import chalk from "chalk";
3
- import { program, Option } from "commander";
4
4
  import debug from "debug";
5
5
  import ora from "ora";
6
- import { getClient } from "../utils/index.js";
6
+ import { input, select } from "@inquirer/prompts";
7
7
  const log = debug("ef:cli:auth");
8
8
  const topics = [
9
- "render.created",
10
- "render.rendering",
11
- "render.pending",
12
- "render.failed",
13
- "render.completed"
9
+ "render.created",
10
+ "render.rendering",
11
+ "render.pending",
12
+ "render.failed",
13
+ "render.completed"
14
14
  ];
15
- const testWebhookURL = async ({
16
- webhookURL,
17
- topic
18
- }) => {
19
- const response = await getClient().authenticatedFetch(
20
- "/api/v1/test_webhook",
21
- {
22
- method: "POST",
23
- body: JSON.stringify({
24
- webhookURL,
25
- topic
26
- })
27
- }
28
- );
29
- return response.json();
15
+ const testWebhookURL = async ({ webhookURL, topic }) => {
16
+ const response = await getClient().authenticatedFetch("/api/v1/test_webhook", {
17
+ method: "POST",
18
+ body: JSON.stringify({
19
+ webhookURL,
20
+ topic
21
+ })
22
+ });
23
+ return response.json();
30
24
  };
31
25
  const webhookCommand = program.command("webhook").description("Test webhook URL with a topic").option("-u, --webhookURL <webhookURL>", "Webhook URL").addOption(new Option("-t, --topic <topic>", "Topic").choices(topics)).action(async () => {
32
- const options = webhookCommand.opts();
33
- log("Options:", options);
34
- let { webhookURL, topic } = options;
35
- if (!webhookURL) {
36
- const answer = await input({ message: "Enter a webhook URL:" });
37
- webhookURL = answer;
38
- }
39
- if (!topic) {
40
- const answer = await select({
41
- message: "Select a topic:",
42
- choices: [...topics.map((topic2) => ({ title: topic2, value: topic2 }))]
43
- });
44
- topic = answer;
45
- }
46
- const spinner = ora("Testing...").start();
47
- try {
48
- const apiData = await testWebhookURL({ webhookURL, topic });
49
- spinner.succeed("Webhook URL is working! 🎉");
50
- process.stderr.write(chalk.green(`${apiData.message}
51
- `));
52
- } catch (error) {
53
- spinner.fail("Webhook URL is not working!");
54
- process.stderr.write(error?.message);
55
- process.stderr.write("\n");
56
- log("Error:", error);
57
- }
26
+ const options = webhookCommand.opts();
27
+ log("Options:", options);
28
+ let { webhookURL, topic } = options;
29
+ if (!webhookURL) {
30
+ const answer = await input({ message: "Enter a webhook URL:" });
31
+ webhookURL = answer;
32
+ }
33
+ if (!topic) {
34
+ const answer = await select({
35
+ message: "Select a topic:",
36
+ choices: [...topics.map((topic$1) => ({
37
+ title: topic$1,
38
+ value: topic$1
39
+ }))]
40
+ });
41
+ topic = answer;
42
+ }
43
+ const spinner = ora("Testing...").start();
44
+ try {
45
+ const apiData = await testWebhookURL({
46
+ webhookURL,
47
+ topic
48
+ });
49
+ spinner.succeed("Webhook URL is working! 🎉");
50
+ process.stderr.write(chalk.green(`${apiData.message}\n`));
51
+ } catch (error) {
52
+ spinner.fail("Webhook URL is not working!");
53
+ process.stderr.write(error?.message);
54
+ process.stderr.write("\n");
55
+ log("Error:", error);
56
+ }
58
57
  });
59
- export {
60
- testWebhookURL
61
- };
package/dist/index.js CHANGED
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import "dotenv/config";
3
- import { program, Option } from "commander";
4
2
  import { VERSION } from "./VERSION.js";
5
3
  import "./commands/auth.js";
6
4
  import "./commands/sync.js";
@@ -10,9 +8,7 @@ import "./commands/process.js";
10
8
  import "./commands/process-file.js";
11
9
  import "./commands/check.js";
12
10
  import "./commands/webhook.js";
13
- program.name("editframe").addOption(new Option("-t, --token <token>", "API Token").env("EF_TOKEN")).addOption(
14
- new Option("--ef-host <host>", "Editframe Host").env("EF_HOST").default("https://editframe.dev")
15
- ).addOption(
16
- new Option("--ef-render-host <host>", "Editframe Render Host").env("EF_RENDER_HOST").default("https://editframe.dev")
17
- ).version(VERSION);
11
+ import "dotenv/config";
12
+ import { Option, program } from "commander";
13
+ program.name("editframe").addOption(new Option("-t, --token <token>", "API Token").env("EF_TOKEN")).addOption(new Option("--ef-host <host>", "Editframe Host").env("EF_HOST").default("https://editframe.dev")).addOption(new Option("--ef-render-host <host>", "Editframe Render Host").env("EF_RENDER_HOST").default("https://editframe.dev")).version(VERSION);
18
14
  program.parse(process.argv);
@@ -1,33 +1,27 @@
1
- import { generateTrack, cacheImage, findOrCreateCaptions } from "@editframe/assets";
1
+ import { cacheImage, findOrCreateCaptions, generateTrack } from "@editframe/assets";
2
2
  const processRenderInfo = async (renderInfo) => {
3
- for (const [src, tracks] of Object.entries(renderInfo.assets.efMedia)) {
4
- process.stderr.write("Processing media asset: ");
5
- process.stderr.write(src);
6
- process.stderr.write("\n");
7
- for (const trackId in tracks) {
8
- process.stderr.write("Generating track: ");
9
- process.stderr.write(trackId);
10
- process.stderr.write("\n");
11
- await generateTrack(
12
- "./src/assets",
13
- `./src${src}`,
14
- `src?trackId=${trackId}`
15
- );
16
- }
17
- }
18
- for (const imageAsset of renderInfo.assets.efImage) {
19
- process.stderr.write("Processing image asset: ");
20
- process.stderr.write(imageAsset);
21
- process.stderr.write("\n");
22
- await cacheImage("./src/assets", `./src${imageAsset}`);
23
- }
24
- for (const captionsAsset of renderInfo.assets.efCaptions) {
25
- process.stderr.write("Processing captions asset: ");
26
- process.stderr.write(captionsAsset);
27
- process.stderr.write("\n");
28
- await findOrCreateCaptions("./src/assets", `./src${captionsAsset}`);
29
- }
30
- };
31
- export {
32
- processRenderInfo
3
+ for (const [src, tracks] of Object.entries(renderInfo.assets.efMedia)) {
4
+ process.stderr.write("Processing media asset: ");
5
+ process.stderr.write(src);
6
+ process.stderr.write("\n");
7
+ for (const trackId in tracks) {
8
+ process.stderr.write("Generating track: ");
9
+ process.stderr.write(trackId);
10
+ process.stderr.write("\n");
11
+ await generateTrack("./src/assets", `./src${src}`, `src?trackId=${trackId}`);
12
+ }
13
+ }
14
+ for (const imageAsset of renderInfo.assets.efImage) {
15
+ process.stderr.write("Processing image asset: ");
16
+ process.stderr.write(imageAsset);
17
+ process.stderr.write("\n");
18
+ await cacheImage("./src/assets", `./src${imageAsset}`);
19
+ }
20
+ for (const captionsAsset of renderInfo.assets.efCaptions) {
21
+ process.stderr.write("Processing captions asset: ");
22
+ process.stderr.write(captionsAsset);
23
+ process.stderr.write("\n");
24
+ await findOrCreateCaptions("./src/assets", `./src${captionsAsset}`);
25
+ }
33
26
  };
27
+ export { processRenderInfo };
@@ -1,29 +1,22 @@
1
- import debug from "debug";
2
1
  import { SyncCaption } from "./SyncCaption.js";
3
2
  import { SyncFragmentIndex } from "./SyncFragmentIndex.js";
4
3
  import { SyncImage } from "./SyncImage.js";
5
4
  import { SyncTrack } from "./SyncTrack.js";
5
+ import debug from "debug";
6
6
  const trackMatch = /\.track-[\d]+.mp4$/i;
7
7
  const fragmentIndexMatch = /\.tracks.json$/i;
8
8
  const captionsMatch = /\.captions.json$/i;
9
9
  const imageMatch = /\.(png|jpe?g|gif|webp)$/i;
10
10
  const log = debug("ef:SubAssetSync");
11
11
  const getAssetSync = (subAssetPath, md5) => {
12
- log("getAssetSync", { subAssetPath, md5 });
13
- if (imageMatch.test(subAssetPath)) {
14
- return new SyncImage(subAssetPath, md5);
15
- }
16
- if (trackMatch.test(subAssetPath)) {
17
- return new SyncTrack(subAssetPath, md5);
18
- }
19
- if (fragmentIndexMatch.test(subAssetPath)) {
20
- return new SyncFragmentIndex(subAssetPath, md5);
21
- }
22
- if (captionsMatch.test(subAssetPath)) {
23
- return new SyncCaption(subAssetPath, md5);
24
- }
25
- throw new Error(`Unrecognized sub-asset type: ${subAssetPath}`);
26
- };
27
- export {
28
- getAssetSync
12
+ log("getAssetSync", {
13
+ subAssetPath,
14
+ md5
15
+ });
16
+ if (imageMatch.test(subAssetPath)) return new SyncImage(subAssetPath, md5);
17
+ if (trackMatch.test(subAssetPath)) return new SyncTrack(subAssetPath, md5);
18
+ if (fragmentIndexMatch.test(subAssetPath)) return new SyncFragmentIndex(subAssetPath, md5);
19
+ if (captionsMatch.test(subAssetPath)) return new SyncCaption(subAssetPath, md5);
20
+ throw new Error(`Unrecognized sub-asset type: ${subAssetPath}`);
29
21
  };
22
+ export { getAssetSync };