@editframe/cli 0.7.0-beta.1 → 0.7.0-beta.11

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 (53) hide show
  1. package/dist/VERSION.cjs +1 -1
  2. package/dist/VERSION.js +1 -1
  3. package/dist/commands/auth.cjs +14 -11
  4. package/dist/commands/auth.js +15 -12
  5. package/dist/commands/check.cjs +2 -2
  6. package/dist/commands/check.js +2 -2
  7. package/dist/commands/process.cjs +36 -0
  8. package/dist/commands/process.js +35 -0
  9. package/dist/commands/render.cjs +34 -25
  10. package/dist/commands/render.js +34 -25
  11. package/dist/index.cjs +1 -11
  12. package/dist/index.js +1 -12
  13. package/dist/operations/getRenderInfo.cjs +59 -0
  14. package/dist/operations/getRenderInfo.js +59 -0
  15. package/dist/operations/processRenderInfo.cjs +30 -0
  16. package/dist/operations/processRenderInfo.js +30 -0
  17. package/dist/operations/syncAssetsDirectory.cjs +83 -40
  18. package/dist/operations/syncAssetsDirectory.js +82 -39
  19. package/dist/utils/index.cjs +8 -15
  20. package/dist/utils/index.js +8 -15
  21. package/dist/utils/launchBrowserAndWaitForSDK.cjs +7 -3
  22. package/dist/utils/launchBrowserAndWaitForSDK.js +7 -3
  23. package/dist/utils/validateVideoResolution.cjs +27 -0
  24. package/dist/utils/validateVideoResolution.js +27 -0
  25. package/package.json +6 -12
  26. package/src/commands/auth.ts +14 -12
  27. package/src/commands/check.ts +2 -2
  28. package/src/commands/process.ts +43 -37
  29. package/src/commands/render.ts +32 -30
  30. package/src/operations/getRenderInfo.ts +80 -0
  31. package/src/operations/processRenderInfo.ts +37 -0
  32. package/src/operations/syncAssetsDirectory.ts +77 -40
  33. package/src/utils/index.ts +7 -16
  34. package/src/utils/launchBrowserAndWaitForSDK.ts +9 -3
  35. package/src/utils/validateVideoResolution.ts +33 -0
  36. package/dist/api/caption-file.cjs +0 -48
  37. package/dist/api/caption-file.js +0 -48
  38. package/dist/api/image-file.cjs +0 -49
  39. package/dist/api/image-file.js +0 -49
  40. package/dist/api/index.cjs +0 -12
  41. package/dist/api/index.js +0 -12
  42. package/dist/api/isobmff-file.cjs +0 -48
  43. package/dist/api/isobmff-file.js +0 -48
  44. package/dist/api/isobmff-track.cjs +0 -63
  45. package/dist/api/isobmff-track.js +0 -63
  46. package/dist/api/renders.cjs +0 -51
  47. package/dist/api/renders.js +0 -51
  48. package/src/api/caption-file.ts +0 -60
  49. package/src/api/image-file.ts +0 -58
  50. package/src/api/index.ts +0 -17
  51. package/src/api/isobmff-file.ts +0 -59
  52. package/src/api/isobmff-track.ts +0 -77
  53. package/src/api/renders.ts +0 -59
@@ -3,11 +3,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const assets = require("@editframe/assets");
4
4
  const fs = require("node:fs/promises");
5
5
  const path = require("node:path");
6
- const captionFile = require("../api/caption-file.cjs");
7
- const imageFile = require("../api/image-file.cjs");
8
- const isobmffFile = require("../api/isobmff-file.cjs");
9
- const isobmffTrack = require("../api/isobmff-track.cjs");
6
+ const api = require("@editframe/api");
10
7
  const node_fs = require("node:fs");
8
+ const index = require("../utils/index.cjs");
11
9
  const imageMatch = /\.(png|jpe?g|gif|webp)$/i;
12
10
  const trackMatch = /\.track-[\d]+.mp4$/i;
13
11
  const fragmentIndexMatch = /\.tracks.json$/i;
@@ -27,7 +25,8 @@ class SyncStatus {
27
25
  return !!result;
28
26
  }
29
27
  async markSynced() {
30
- console.log(`✏️ Marking asset as synced: ${this.assetPath}`);
28
+ process.stderr.write(`✏️ Marking asset as synced: ${this.assetPath}
29
+ `);
31
30
  await fs.writeFile(this.infoPath, "{}", "utf-8");
32
31
  }
33
32
  }
@@ -39,19 +38,26 @@ const syncAssetDirectory = async (projectDirectory) => {
39
38
  "assets",
40
39
  ".cache"
41
40
  );
42
- const stat = await fs.stat(fullPath);
43
- if (!stat.isDirectory()) {
41
+ const stat = await fs.stat(fullPath).catch((error) => {
42
+ if (error.code === "ENOENT") {
43
+ return;
44
+ }
45
+ throw error;
46
+ });
47
+ if (!stat?.isDirectory()) {
44
48
  console.error(`No assets cache directory found at ${fullPath}`);
45
49
  return;
46
50
  }
47
51
  const assets$1 = await fs.readdir(fullPath);
48
- console.log(`Syncing asset dir: ${fullPath}`);
52
+ process.stderr.write(`Syncing asset dir: ${fullPath}
53
+ `);
49
54
  for (const asset of assets$1) {
50
- console.log(`Syncing asset: ${asset}`);
55
+ process.stderr.write(`Syncing asset: ${asset}
56
+ `);
51
57
  const assetDir = path.join(fullPath, asset);
52
58
  const stat2 = await fs.stat(assetDir);
53
59
  if (!stat2.isDirectory()) {
54
- console.error("Invalid asset. Did not find asset directory.");
60
+ process.stderr.write("Invalid asset. Did not find asset directory.\n");
55
61
  return;
56
62
  }
57
63
  const subAssets = await fs.readdir(assetDir);
@@ -62,7 +68,10 @@ const syncAssetDirectory = async (projectDirectory) => {
62
68
  const subAssetPath = path.join(assetDir, subAsset);
63
69
  const syncStatus = new SyncStatus(subAssetPath);
64
70
  if (await syncStatus.isSynced()) {
65
- console.log(` ✔ Sub-asset has already been synced: ${subAsset}`);
71
+ process.stderr.write(
72
+ ` ✔ Sub-asset has already been synced: ${subAsset}
73
+ `
74
+ );
66
75
  continue;
67
76
  }
68
77
  switch (true) {
@@ -70,16 +79,21 @@ const syncAssetDirectory = async (projectDirectory) => {
70
79
  const probeResult = await assets.Probe.probePath(subAssetPath);
71
80
  const [videoProbe] = probeResult.videoStreams;
72
81
  if (!videoProbe) {
73
- console.error(`🚫 No video stream found in image: ${subAsset}`);
82
+ process.stderr.write(
83
+ `🚫 No video stream found in image: ${subAsset}
84
+ `
85
+ );
74
86
  break;
75
87
  }
76
88
  const ext = path.extname(subAsset).slice(1);
77
89
  if (!(ext === "jpg" || ext === "jpeg" || ext === "png" || ext === "webp")) {
78
- console.error(`🚫 Invalid image format: ${subAsset}`);
90
+ process.stderr.write(`🚫 Invalid image format: ${subAsset}
91
+ `);
79
92
  break;
80
93
  }
81
- console.log(`🖼️ Syncing image: ${subAsset}`);
82
- const created = await imageFile.createImageFile({
94
+ process.stderr.write(`🖼️ Syncing image: ${subAsset}
95
+ `);
96
+ const created = await api.createImageFile(index.getClient(), {
83
97
  id: asset,
84
98
  filename: subAsset,
85
99
  width: videoProbe.width,
@@ -88,18 +102,23 @@ const syncAssetDirectory = async (projectDirectory) => {
88
102
  });
89
103
  if (created) {
90
104
  if (created.complete) {
91
- console.log(" ✔ Image has already been synced.");
105
+ process.stderr.write(" ✔ Image has already been synced.\n");
92
106
  } else {
93
- await imageFile.uploadImageFile(created.id, node_fs.createReadStream(subAssetPath));
94
- console.log(" ✅ Image has been synced.");
107
+ await api.uploadImageFile(
108
+ index.getClient(),
109
+ created.id,
110
+ node_fs.createReadStream(subAssetPath)
111
+ );
112
+ process.stderr.write(" ✅ Image has been synced.\n");
95
113
  }
96
114
  await syncStatus.markSynced();
97
115
  }
98
116
  break;
99
117
  }
100
118
  case trackMatch.test(subAsset): {
101
- console.log(`📼 Syncing a/v track: ${subAsset}`);
102
- const createdFile = await isobmffFile.createISOBMFFFile({
119
+ process.stderr.write(`📼 Syncing a/v track: ${subAsset}
120
+ `);
121
+ const createdFile = await api.createISOBMFFFile(index.getClient(), {
103
122
  id: asset,
104
123
  filename: subAsset.replace(/\.track-[\d]+.mp4$/, "")
105
124
  });
@@ -107,16 +126,25 @@ const syncAssetDirectory = async (projectDirectory) => {
107
126
  const probe = await assets.Probe.probePath(subAssetPath);
108
127
  const trackId = subAsset.match(/track-([\d]+).mp4/)?.[1];
109
128
  if (!trackId) {
110
- console.error(`🚫 No track ID found for track: ${subAsset}`);
129
+ process.stderr.write(
130
+ `🚫 No track ID found for track: ${subAsset}
131
+ `
132
+ );
111
133
  break;
112
134
  }
113
135
  const [track] = probe.streams;
114
136
  if (!track) {
115
- console.error(`🚫 No track stream found in track: ${subAsset}`);
137
+ process.stderr.write(
138
+ `🚫 No track stream found in track: ${subAsset}
139
+ `
140
+ );
116
141
  break;
117
142
  }
118
143
  if (track.duration === void 0) {
119
- console.error(`🚫 No duration found in track: ${subAsset}`);
144
+ process.stderr.write(
145
+ `🚫 No duration found in track: ${subAsset}
146
+ `
147
+ );
120
148
  break;
121
149
  }
122
150
  const stat3 = await fs.stat(subAssetPath);
@@ -137,17 +165,21 @@ const syncAssetDirectory = async (projectDirectory) => {
137
165
  codec_name: track.codec_name,
138
166
  byte_size: stat3.size
139
167
  };
140
- const createdTrack = await isobmffTrack.createISOBMFFTrack(createPayload);
168
+ const createdTrack = await api.createISOBMFFTrack(
169
+ index.getClient(),
170
+ createPayload
171
+ );
141
172
  if (createdTrack) {
142
173
  if (createdTrack.last_received_byte === createdTrack.byte_size - 1) {
143
- console.log(" ✔ Track has already been synced.");
174
+ process.stderr.write(" ✔ Track has already been synced.\n");
144
175
  } else {
145
- await isobmffTrack.uploadISOBMFFTrack(
176
+ await api.uploadISOBMFFTrack(
177
+ index.getClient(),
146
178
  createdFile.id,
147
179
  Number(trackId),
148
180
  node_fs.createReadStream(subAssetPath)
149
181
  );
150
- console.log(" ✅ Track has been synced.");
182
+ process.stderr.write(" ✅ Track has been synced.\n");
151
183
  }
152
184
  await syncStatus.markSynced();
153
185
  }
@@ -155,49 +187,60 @@ const syncAssetDirectory = async (projectDirectory) => {
155
187
  break;
156
188
  }
157
189
  case fragmentIndexMatch.test(subAsset): {
158
- console.log(`📋 Syncing fragment index: ${subAsset}`);
159
- const createdFile = await isobmffFile.createISOBMFFFile({
190
+ process.stderr.write(`📋 Syncing fragment index: ${subAsset}
191
+ `);
192
+ const createdFile = await api.createISOBMFFFile(index.getClient(), {
160
193
  id: asset,
161
194
  filename: subAsset.replace(/\.tracks.json$/, "")
162
195
  });
163
196
  if (createdFile) {
164
197
  if (createdFile.fragment_index_complete) {
165
- console.log(" ✔ Fragment index has already been synced.");
198
+ process.stderr.write(
199
+ " ✔ Fragment index has already been synced.\n"
200
+ );
166
201
  } else {
167
202
  const readStream = node_fs.createReadStream(subAssetPath);
168
- await isobmffFile.uploadFragmentIndex(asset, readStream);
169
- console.log(" ✅ Fragment index has been synced.");
203
+ await api.uploadFragmentIndex(index.getClient(), asset, readStream);
204
+ process.stderr.write(" ✅ Fragment index has been synced.\n");
170
205
  }
171
206
  await syncStatus.markSynced();
172
207
  } else {
173
- console.error(`🚫 No file found for fragment index: ${subAsset}`);
208
+ process.stderr.write(
209
+ `🚫 No file found for fragment index: ${subAsset}
210
+ `
211
+ );
174
212
  break;
175
213
  }
176
214
  break;
177
215
  }
178
216
  case captionsMatch.test(subAsset): {
179
- console.log(`📝 Syncing captions: ${subAsset}`);
180
- const createdFile = await captionFile.createCaptionFile({
217
+ process.stderr.write(`📝 Syncing captions: ${subAsset}
218
+ `);
219
+ const createdFile = await api.createCaptionFile(index.getClient(), {
181
220
  id: asset,
182
221
  filename: subAsset.replace(/\.captions.json$/, "")
183
222
  });
184
223
  if (createdFile) {
185
224
  if (createdFile.complete) {
186
- console.log(" ✔ Captions have already been synced.");
225
+ process.stderr.write(" ✔ Captions have already been synced.\n");
187
226
  } else {
188
227
  const readStream = node_fs.createReadStream(subAssetPath);
189
- await captionFile.uploadCaptionFile(asset, readStream);
190
- console.log(" ✅ Captions have been synced.");
228
+ await api.uploadCaptionFile(index.getClient(), asset, readStream);
229
+ process.stderr.write(" ✅ Captions have been synced.\n");
191
230
  }
192
231
  await syncStatus.markSynced();
193
232
  } else {
194
- console.error(`🚫 No file found for captions: ${subAsset}`);
233
+ process.stderr.write(
234
+ `🚫 No file found for captions: ${subAsset}
235
+ `
236
+ );
195
237
  break;
196
238
  }
197
239
  break;
198
240
  }
199
241
  default: {
200
- console.error(`🚫 Unknown sub-asset: ${subAsset}`);
242
+ process.stderr.write(`🚫 Unknown sub-asset: ${subAsset}
243
+ `);
201
244
  break;
202
245
  }
203
246
  }
@@ -1,11 +1,9 @@
1
1
  import { Probe } from "@editframe/assets";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { createCaptionFile, uploadCaptionFile } from "../api/caption-file.js";
5
- import { createImageFile, uploadImageFile } from "../api/image-file.js";
6
- import { createISOBMFFFile, uploadFragmentIndex } from "../api/isobmff-file.js";
7
- import { createISOBMFFTrack, uploadISOBMFFTrack } from "../api/isobmff-track.js";
4
+ import { createCaptionFile, uploadCaptionFile, createISOBMFFFile, uploadFragmentIndex, createISOBMFFTrack, uploadISOBMFFTrack, createImageFile, uploadImageFile } from "@editframe/api";
8
5
  import { createReadStream } from "node:fs";
6
+ import { getClient } from "../utils/index.js";
9
7
  const imageMatch = /\.(png|jpe?g|gif|webp)$/i;
10
8
  const trackMatch = /\.track-[\d]+.mp4$/i;
11
9
  const fragmentIndexMatch = /\.tracks.json$/i;
@@ -25,7 +23,8 @@ class SyncStatus {
25
23
  return !!result;
26
24
  }
27
25
  async markSynced() {
28
- console.log(`✏️ Marking asset as synced: ${this.assetPath}`);
26
+ process.stderr.write(`✏️ Marking asset as synced: ${this.assetPath}
27
+ `);
29
28
  await fs.writeFile(this.infoPath, "{}", "utf-8");
30
29
  }
31
30
  }
@@ -37,19 +36,26 @@ const syncAssetDirectory = async (projectDirectory) => {
37
36
  "assets",
38
37
  ".cache"
39
38
  );
40
- const stat = await fs.stat(fullPath);
41
- if (!stat.isDirectory()) {
39
+ const stat = await fs.stat(fullPath).catch((error) => {
40
+ if (error.code === "ENOENT") {
41
+ return;
42
+ }
43
+ throw error;
44
+ });
45
+ if (!stat?.isDirectory()) {
42
46
  console.error(`No assets cache directory found at ${fullPath}`);
43
47
  return;
44
48
  }
45
49
  const assets = await fs.readdir(fullPath);
46
- console.log(`Syncing asset dir: ${fullPath}`);
50
+ process.stderr.write(`Syncing asset dir: ${fullPath}
51
+ `);
47
52
  for (const asset of assets) {
48
- console.log(`Syncing asset: ${asset}`);
53
+ process.stderr.write(`Syncing asset: ${asset}
54
+ `);
49
55
  const assetDir = path.join(fullPath, asset);
50
56
  const stat2 = await fs.stat(assetDir);
51
57
  if (!stat2.isDirectory()) {
52
- console.error("Invalid asset. Did not find asset directory.");
58
+ process.stderr.write("Invalid asset. Did not find asset directory.\n");
53
59
  return;
54
60
  }
55
61
  const subAssets = await fs.readdir(assetDir);
@@ -60,7 +66,10 @@ const syncAssetDirectory = async (projectDirectory) => {
60
66
  const subAssetPath = path.join(assetDir, subAsset);
61
67
  const syncStatus = new SyncStatus(subAssetPath);
62
68
  if (await syncStatus.isSynced()) {
63
- console.log(` ✔ Sub-asset has already been synced: ${subAsset}`);
69
+ process.stderr.write(
70
+ ` ✔ Sub-asset has already been synced: ${subAsset}
71
+ `
72
+ );
64
73
  continue;
65
74
  }
66
75
  switch (true) {
@@ -68,16 +77,21 @@ const syncAssetDirectory = async (projectDirectory) => {
68
77
  const probeResult = await Probe.probePath(subAssetPath);
69
78
  const [videoProbe] = probeResult.videoStreams;
70
79
  if (!videoProbe) {
71
- console.error(`🚫 No video stream found in image: ${subAsset}`);
80
+ process.stderr.write(
81
+ `🚫 No video stream found in image: ${subAsset}
82
+ `
83
+ );
72
84
  break;
73
85
  }
74
86
  const ext = path.extname(subAsset).slice(1);
75
87
  if (!(ext === "jpg" || ext === "jpeg" || ext === "png" || ext === "webp")) {
76
- console.error(`🚫 Invalid image format: ${subAsset}`);
88
+ process.stderr.write(`🚫 Invalid image format: ${subAsset}
89
+ `);
77
90
  break;
78
91
  }
79
- console.log(`🖼️ Syncing image: ${subAsset}`);
80
- const created = await createImageFile({
92
+ process.stderr.write(`🖼️ Syncing image: ${subAsset}
93
+ `);
94
+ const created = await createImageFile(getClient(), {
81
95
  id: asset,
82
96
  filename: subAsset,
83
97
  width: videoProbe.width,
@@ -86,18 +100,23 @@ const syncAssetDirectory = async (projectDirectory) => {
86
100
  });
87
101
  if (created) {
88
102
  if (created.complete) {
89
- console.log(" ✔ Image has already been synced.");
103
+ process.stderr.write(" ✔ Image has already been synced.\n");
90
104
  } else {
91
- await uploadImageFile(created.id, createReadStream(subAssetPath));
92
- console.log(" ✅ Image has been synced.");
105
+ await uploadImageFile(
106
+ getClient(),
107
+ created.id,
108
+ createReadStream(subAssetPath)
109
+ );
110
+ process.stderr.write(" ✅ Image has been synced.\n");
93
111
  }
94
112
  await syncStatus.markSynced();
95
113
  }
96
114
  break;
97
115
  }
98
116
  case trackMatch.test(subAsset): {
99
- console.log(`📼 Syncing a/v track: ${subAsset}`);
100
- const createdFile = await createISOBMFFFile({
117
+ process.stderr.write(`📼 Syncing a/v track: ${subAsset}
118
+ `);
119
+ const createdFile = await createISOBMFFFile(getClient(), {
101
120
  id: asset,
102
121
  filename: subAsset.replace(/\.track-[\d]+.mp4$/, "")
103
122
  });
@@ -105,16 +124,25 @@ const syncAssetDirectory = async (projectDirectory) => {
105
124
  const probe = await Probe.probePath(subAssetPath);
106
125
  const trackId = subAsset.match(/track-([\d]+).mp4/)?.[1];
107
126
  if (!trackId) {
108
- console.error(`🚫 No track ID found for track: ${subAsset}`);
127
+ process.stderr.write(
128
+ `🚫 No track ID found for track: ${subAsset}
129
+ `
130
+ );
109
131
  break;
110
132
  }
111
133
  const [track] = probe.streams;
112
134
  if (!track) {
113
- console.error(`🚫 No track stream found in track: ${subAsset}`);
135
+ process.stderr.write(
136
+ `🚫 No track stream found in track: ${subAsset}
137
+ `
138
+ );
114
139
  break;
115
140
  }
116
141
  if (track.duration === void 0) {
117
- console.error(`🚫 No duration found in track: ${subAsset}`);
142
+ process.stderr.write(
143
+ `🚫 No duration found in track: ${subAsset}
144
+ `
145
+ );
118
146
  break;
119
147
  }
120
148
  const stat3 = await fs.stat(subAssetPath);
@@ -135,17 +163,21 @@ const syncAssetDirectory = async (projectDirectory) => {
135
163
  codec_name: track.codec_name,
136
164
  byte_size: stat3.size
137
165
  };
138
- const createdTrack = await createISOBMFFTrack(createPayload);
166
+ const createdTrack = await createISOBMFFTrack(
167
+ getClient(),
168
+ createPayload
169
+ );
139
170
  if (createdTrack) {
140
171
  if (createdTrack.last_received_byte === createdTrack.byte_size - 1) {
141
- console.log(" ✔ Track has already been synced.");
172
+ process.stderr.write(" ✔ Track has already been synced.\n");
142
173
  } else {
143
174
  await uploadISOBMFFTrack(
175
+ getClient(),
144
176
  createdFile.id,
145
177
  Number(trackId),
146
178
  createReadStream(subAssetPath)
147
179
  );
148
- console.log(" ✅ Track has been synced.");
180
+ process.stderr.write(" ✅ Track has been synced.\n");
149
181
  }
150
182
  await syncStatus.markSynced();
151
183
  }
@@ -153,49 +185,60 @@ const syncAssetDirectory = async (projectDirectory) => {
153
185
  break;
154
186
  }
155
187
  case fragmentIndexMatch.test(subAsset): {
156
- console.log(`📋 Syncing fragment index: ${subAsset}`);
157
- const createdFile = await createISOBMFFFile({
188
+ process.stderr.write(`📋 Syncing fragment index: ${subAsset}
189
+ `);
190
+ const createdFile = await createISOBMFFFile(getClient(), {
158
191
  id: asset,
159
192
  filename: subAsset.replace(/\.tracks.json$/, "")
160
193
  });
161
194
  if (createdFile) {
162
195
  if (createdFile.fragment_index_complete) {
163
- console.log(" ✔ Fragment index has already been synced.");
196
+ process.stderr.write(
197
+ " ✔ Fragment index has already been synced.\n"
198
+ );
164
199
  } else {
165
200
  const readStream = createReadStream(subAssetPath);
166
- await uploadFragmentIndex(asset, readStream);
167
- console.log(" ✅ Fragment index has been synced.");
201
+ await uploadFragmentIndex(getClient(), asset, readStream);
202
+ process.stderr.write(" ✅ Fragment index has been synced.\n");
168
203
  }
169
204
  await syncStatus.markSynced();
170
205
  } else {
171
- console.error(`🚫 No file found for fragment index: ${subAsset}`);
206
+ process.stderr.write(
207
+ `🚫 No file found for fragment index: ${subAsset}
208
+ `
209
+ );
172
210
  break;
173
211
  }
174
212
  break;
175
213
  }
176
214
  case captionsMatch.test(subAsset): {
177
- console.log(`📝 Syncing captions: ${subAsset}`);
178
- const createdFile = await createCaptionFile({
215
+ process.stderr.write(`📝 Syncing captions: ${subAsset}
216
+ `);
217
+ const createdFile = await createCaptionFile(getClient(), {
179
218
  id: asset,
180
219
  filename: subAsset.replace(/\.captions.json$/, "")
181
220
  });
182
221
  if (createdFile) {
183
222
  if (createdFile.complete) {
184
- console.log(" ✔ Captions have already been synced.");
223
+ process.stderr.write(" ✔ Captions have already been synced.\n");
185
224
  } else {
186
225
  const readStream = createReadStream(subAssetPath);
187
- await uploadCaptionFile(asset, readStream);
188
- console.log(" ✅ Captions have been synced.");
226
+ await uploadCaptionFile(getClient(), asset, readStream);
227
+ process.stderr.write(" ✅ Captions have been synced.\n");
189
228
  }
190
229
  await syncStatus.markSynced();
191
230
  } else {
192
- console.error(`🚫 No file found for captions: ${subAsset}`);
231
+ process.stderr.write(
232
+ `🚫 No file found for captions: ${subAsset}
233
+ `
234
+ );
193
235
  break;
194
236
  }
195
237
  break;
196
238
  }
197
239
  default: {
198
- console.error(`🚫 Unknown sub-asset: ${subAsset}`);
240
+ process.stderr.write(`🚫 Unknown sub-asset: ${subAsset}
241
+ `);
199
242
  break;
200
243
  }
201
244
  }
@@ -2,20 +2,13 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const commander = require("commander");
4
4
  require("dotenv/config");
5
- const fetch = require("node-fetch");
6
- const authenticatedFetch = (path, init = {}) => {
7
- const programOpts = commander.program.opts();
8
- if (!programOpts.token) {
9
- throw new Error(
10
- "API Token is required to make authenticated requests.\nSet it with --token or EF_TOKEN env variable.\n\n(This tool will read from a .env file if it is present.)"
11
- );
5
+ const api = require("@editframe/api");
6
+ let client;
7
+ const getClient = () => {
8
+ if (!client) {
9
+ const programOpts = commander.program.opts();
10
+ client = new api.Client(programOpts.token, programOpts.efHost);
12
11
  }
13
- init.headers ||= {};
14
- Object.assign(init.headers, {
15
- Authorization: `Bearer ${programOpts.token}`,
16
- "Content-Type": "application/json"
17
- });
18
- const url = new URL(path, programOpts.efHost);
19
- return fetch(url, init);
12
+ return client;
20
13
  };
21
- exports.authenticatedFetch = authenticatedFetch;
14
+ exports.getClient = getClient;
@@ -1,21 +1,14 @@
1
1
  import { program } from "commander";
2
2
  import "dotenv/config";
3
- import fetch from "node-fetch";
4
- const authenticatedFetch = (path, init = {}) => {
5
- const programOpts = program.opts();
6
- if (!programOpts.token) {
7
- throw new Error(
8
- "API Token is required to make authenticated requests.\nSet it with --token or EF_TOKEN env variable.\n\n(This tool will read from a .env file if it is present.)"
9
- );
3
+ import { Client } from "@editframe/api";
4
+ let client;
5
+ const getClient = () => {
6
+ if (!client) {
7
+ const programOpts = program.opts();
8
+ client = new Client(programOpts.token, programOpts.efHost);
10
9
  }
11
- init.headers ||= {};
12
- Object.assign(init.headers, {
13
- Authorization: `Bearer ${programOpts.token}`,
14
- "Content-Type": "application/json"
15
- });
16
- const url = new URL(path, programOpts.efHost);
17
- return fetch(url, init);
10
+ return client;
18
11
  };
19
12
  export {
20
- authenticatedFetch
13
+ getClient
21
14
  };
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const chalk = require("chalk");
4
4
  const playwright = require("playwright");
5
+ const debug = require("debug");
5
6
  const withSpinner = require("./withSpinner.cjs");
7
+ const browserLog = debug("ef:cli::browser");
6
8
  async function launchBrowserAndWaitForSDK(options, fn) {
7
9
  const browser = await withSpinner.withSpinner("Launching chrome", async () => {
8
10
  return playwright.chromium.launch({
@@ -19,10 +21,12 @@ async function launchBrowserAndWaitForSDK(options, fn) {
19
21
  }
20
22
  const page2 = await browser.newPage(pageOptions);
21
23
  page2.on("console", (msg) => {
22
- console.error(chalk.blue(`browser (${msg.type()}) |`), msg.text());
24
+ browserLog(chalk.blue(`browser (${msg.type()}) |`), msg.text());
23
25
  });
24
26
  const url = options.url + (options.efInteractive ? "" : "?EF_NONINTERACTIVE=1");
25
- console.log("Loading url", url);
27
+ process.stderr.write("\nLoading url: ");
28
+ process.stderr.write(url);
29
+ process.stderr.write("\n");
26
30
  await page2.goto(url);
27
31
  await page2.waitForFunction(
28
32
  () => {
@@ -32,7 +36,7 @@ async function launchBrowserAndWaitForSDK(options, fn) {
32
36
  );
33
37
  },
34
38
  [],
35
- { timeout: 1e5 }
39
+ { timeout: 1e4 }
36
40
  );
37
41
  return page2;
38
42
  });
@@ -1,6 +1,8 @@
1
1
  import chalk from "chalk";
2
2
  import { chromium } from "playwright";
3
+ import debug from "debug";
3
4
  import { withSpinner } from "./withSpinner.js";
5
+ const browserLog = debug("ef:cli::browser");
4
6
  async function launchBrowserAndWaitForSDK(options, fn) {
5
7
  const browser = await withSpinner("Launching chrome", async () => {
6
8
  return chromium.launch({
@@ -17,10 +19,12 @@ async function launchBrowserAndWaitForSDK(options, fn) {
17
19
  }
18
20
  const page2 = await browser.newPage(pageOptions);
19
21
  page2.on("console", (msg) => {
20
- console.error(chalk.blue(`browser (${msg.type()}) |`), msg.text());
22
+ browserLog(chalk.blue(`browser (${msg.type()}) |`), msg.text());
21
23
  });
22
24
  const url = options.url + (options.efInteractive ? "" : "?EF_NONINTERACTIVE=1");
23
- console.log("Loading url", url);
25
+ process.stderr.write("\nLoading url: ");
26
+ process.stderr.write(url);
27
+ process.stderr.write("\n");
24
28
  await page2.goto(url);
25
29
  await page2.waitForFunction(
26
30
  () => {
@@ -30,7 +34,7 @@ async function launchBrowserAndWaitForSDK(options, fn) {
30
34
  );
31
35
  },
32
36
  [],
33
- { timeout: 1e5 }
37
+ { timeout: 1e4 }
34
38
  );
35
39
  return page2;
36
40
  });
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const zod = require("zod");
4
+ const ora = require("ora");
5
+ const debug = require("debug");
6
+ const log = debug("ef:cli:auth");
7
+ const schema = zod.z.object({
8
+ width: zod.z.number().int(),
9
+ height: zod.z.number().int()
10
+ }).refine((data) => data.width % 2 === 0 && data.height % 2 === 0, {
11
+ message: "Both width and height must be divisible by 2.",
12
+ path: ["width", "height"]
13
+ });
14
+ const validateVideoResolution = async (rawPayload) => {
15
+ const spinner = ora("Validating video resolution").start();
16
+ const result = schema.safeParse(rawPayload);
17
+ if (result.success) {
18
+ spinner.succeed("Video resolution is valid");
19
+ return result.data;
20
+ }
21
+ spinner.fail("Invalid video resolution");
22
+ process.stderr.write(result.error?.errors.map((e) => e.message).join("\n"));
23
+ process.stderr.write("\n");
24
+ log("Error:", result.error?.errors.map((e) => e.message).join("\n"));
25
+ process.exit(1);
26
+ };
27
+ exports.validateVideoResolution = validateVideoResolution;