hyperframes 0.8.123 → 0.8.125

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 (165) hide show
  1. package/dist/{add-CJXLRVWK.js → add-IFW36THF.js} +14 -14
  2. package/dist/{animatedGifPrep-VHXPTSJL.js → animatedGifPrep-RWLNZGK4.js} +5 -5
  3. package/dist/{asset-KTRZSJ5R.js → asset-WMPG6T2H.js} +2 -2
  4. package/dist/{assetCataloger-NH6UQG4Y.js → assetCataloger-KJRYDRTK.js} +2 -2
  5. package/dist/{auth-T52MOHC7.js → auth-552SJTZY.js} +2 -2
  6. package/dist/{autoUpdate-EI6JX53V.js → autoUpdate-2EEU2WEN.js} +2 -2
  7. package/dist/{backgroundChecks-7N3FFYIV.js → backgroundChecks-EO47KLYR.js} +3 -3
  8. package/dist/backgroundChecksWorker.js +3 -3
  9. package/dist/{batchRender-JDH4PXPD.js → batchRender-ZKBWCNPW.js} +3 -3
  10. package/dist/{beats-TG2TOST6.js → beats-JSLKCIMO.js} +11 -11
  11. package/dist/{benchmark-WGXMGPUI.js → benchmark-4OITC52U.js} +11 -11
  12. package/dist/{browser-VMEADLNK.js → browser-7KKHZVZG.js} +8 -8
  13. package/dist/{bundleWithLocalizedFonts-EDBQ5EME.js → bundleWithLocalizedFonts-VYYJV4MC.js} +2 -2
  14. package/dist/{capture-UZFI2G65.js → capture-6OXDGVSK.js} +13 -18
  15. package/dist/{capture-22IWCYV2.js → capture-Q4HT2YI3.js} +2 -2
  16. package/dist/{catalog-3V4SSSYE.js → catalog-PZXB7JKY.js} +14 -14
  17. package/dist/{check-LTKOTPFI.js → check-O4VPFH7X.js} +30 -30
  18. package/dist/{checkBrowser-LTZPCRBO.js → checkBrowser-FKXDR2O3.js} +29 -29
  19. package/dist/{chunk-2QAAOW5T.js → chunk-2K3QXNHK.js} +1 -1
  20. package/dist/{chunk-KQ7BAEVP.js → chunk-6AGYEZQ7.js} +2 -2
  21. package/dist/{chunk-4TIUZ6Z7.js → chunk-75Z3SG7S.js} +2 -2
  22. package/dist/{chunk-HISVSZH7.js → chunk-AZP4Q3HX.js} +2 -2
  23. package/dist/{chunk-OCH6V4FB.js → chunk-BVC2TTOR.js} +2 -2
  24. package/dist/{chunk-MBSCHJQZ.js → chunk-CANIQ65S.js} +1 -1
  25. package/dist/{chunk-IOMMM4AX.js → chunk-CML2M4A5.js} +1 -1
  26. package/dist/{chunk-4XAAOWFC.js → chunk-CYILDWZD.js} +1 -1
  27. package/dist/{chunk-PQQZNS5K.js → chunk-CZBP6WD7.js} +1 -1
  28. package/dist/{chunk-ELHC6CLH.js → chunk-EJA7FDVA.js} +3 -3
  29. package/dist/{chunk-XIJTGR4O.js → chunk-EZ54IXGG.js} +1 -1
  30. package/dist/{chunk-DR7F77AN.js → chunk-FMTOCJN6.js} +1 -1
  31. package/dist/{chunk-IML47HIH.js → chunk-FWJDB65E.js} +7 -7
  32. package/dist/chunk-GULOKZLI.js +155 -0
  33. package/dist/{chunk-4EZKLNMD.js → chunk-HIPHGIMM.js} +1 -1
  34. package/dist/{chunk-BET5FXMM.js → chunk-HN63O2Y6.js} +1 -1
  35. package/dist/{chunk-SKZ6H3JT.js → chunk-HUJT2WV7.js} +1 -1
  36. package/dist/{chunk-EYNWMEWX.js → chunk-I33AB6HW.js} +9 -9
  37. package/dist/{chunk-XQSMY5HF.js → chunk-IBSKMPBO.js} +2 -2
  38. package/dist/{chunk-AICUP6TU.js → chunk-IJPINTW6.js} +1 -1
  39. package/dist/{chunk-RTINVJNS.js → chunk-IWF6XF2V.js} +1 -1
  40. package/dist/{chunk-Z3SUEG2T.js → chunk-JD6UVTTT.js} +5 -5
  41. package/dist/{chunk-ILOJE2TE.js → chunk-K4DH364E.js} +1 -1
  42. package/dist/{chunk-EJF6CESB.js → chunk-M4LHIME7.js} +1 -1
  43. package/dist/{chunk-24AS45UQ.js → chunk-MKTOQKW4.js} +71 -22
  44. package/dist/{dotEnv-AI4SYVTX.js → chunk-NGKM64BP.js} +2 -2
  45. package/dist/{chunk-E26WHQFM.js → chunk-NGQ5NP2Q.js} +2 -2
  46. package/dist/{chunk-7NWNDQID.js → chunk-OHE54L2X.js} +3 -3
  47. package/dist/{chunk-2FH6HOQ2.js → chunk-OJ3NJ54J.js} +1 -1
  48. package/dist/{chunk-CZRQH5SP.js → chunk-OLLALODH.js} +1 -1
  49. package/dist/{chunk-VEGNMQZI.js → chunk-PEOAH4LM.js} +2 -2
  50. package/dist/{chunk-RYP46ARK.js → chunk-QM7YQ35N.js} +1 -1
  51. package/dist/{chunk-GPUM6BRL.js → chunk-QV4PJ5EE.js} +1 -1
  52. package/dist/{chunk-UI2I6ZQE.js → chunk-RGDS435K.js} +1 -1
  53. package/dist/{chunk-3SHYUYXR.js → chunk-SBMSZEBS.js} +9 -9
  54. package/dist/{chunk-MUAFAG77.js → chunk-SD4TJSOZ.js} +4 -4
  55. package/dist/{chunk-QLKCB3NY.js → chunk-SDRIDMMN.js} +7 -7
  56. package/dist/{chunk-3V6V66SZ.js → chunk-T64K236B.js} +2 -2
  57. package/dist/{chunk-WAD4ACBZ.js → chunk-T7KM6AG5.js} +2 -2
  58. package/dist/{chunk-PUFPAYTJ.js → chunk-TSJNOSJF.js} +1 -1
  59. package/dist/{chunk-UMMVYWDI.js → chunk-WZQYKSDF.js} +5 -5
  60. package/dist/{chunk-73KPBRCO.js → chunk-Y6UZPO7H.js} +1 -1
  61. package/dist/{chunk-53IO4HLZ.js → chunk-YKSQOWAL.js} +31 -1
  62. package/dist/{chunk-S3JOM6L4.js → chunk-YVFBNUUH.js} +3 -3
  63. package/dist/{chunk-TLA5RBEB.js → chunk-ZGGEWKPA.js} +1 -1
  64. package/dist/{clean-YZQXCSXZ.js → clean-ZQ3QVGVU.js} +14 -14
  65. package/dist/cli.js +52 -52
  66. package/dist/{cloud-TYUXSEGA.js → cloud-E4GWT7KZ.js} +4 -4
  67. package/dist/{cloudrun-MA2JVRHV.js → cloudrun-RRNAJMHQ.js} +3 -3
  68. package/dist/{compare-6DSDY2IF.js → compare-4IMB3KDE.js} +24 -24
  69. package/dist/{compiler-4FHYKPNR.js → compiler-GM4XUGUA.js} +2 -2
  70. package/dist/{component-NY4JERQ5.js → component-ZIKBZXGS.js} +3 -3
  71. package/dist/{compositions-SI2SKZAF.js → compositions-DRFZ36DG.js} +10 -10
  72. package/dist/{delete-YU7XRF6M.js → delete-7LIHYMTQ.js} +2 -2
  73. package/dist/{dist-AMQZTIJP.js → dist-57EISMJZ.js} +2 -2
  74. package/dist/{doctor-MXX7AHXT.js → doctor-GVRY22DC.js} +9 -9
  75. package/dist/dotEnv-AECLXQSO.js +14 -0
  76. package/dist/{events-R5N3EVAF.js → events-P3XLY3QN.js} +7 -7
  77. package/dist/{events-LLCZN2LK.js → events-XHIAV6Q6.js} +8 -8
  78. package/dist/{feedback-MIZ3HJT4.js → feedback-I2IJMVE6.js} +9 -9
  79. package/dist/{figma-4ESVBLHH.js → figma-KXZD5OXU.js} +3 -3
  80. package/dist/fontLocalizeCli.js +7 -7
  81. package/dist/{get-OF3I77OW.js → get-3TF6CQRJ.js} +2 -2
  82. package/dist/{gpuPolicy-KDI7HVOA.js → gpuPolicy-GUILWNQI.js} +5 -5
  83. package/dist/{grade-compare-QXE4ZEZU.js → grade-compare-6A4MPRDT.js} +24 -24
  84. package/dist/{help-NFHZFSQN.js → help-P2LXSWPH.js} +2 -2
  85. package/dist/{history-DTRCFREW.js → history-TIEBO3TQ.js} +14 -14
  86. package/dist/hyperframe-runtime.js +45 -45
  87. package/dist/hyperframe.manifest.json +1 -1
  88. package/dist/hyperframe.runtime.iife.js +45 -45
  89. package/dist/hyperframes-player.global.js +1 -1
  90. package/dist/{info-KRDLMYKB.js → info-RDYN6M4J.js} +10 -10
  91. package/dist/{init-XTXSP6IU.js → init-FWKYWNED.js} +21 -21
  92. package/dist/{inspect-KH3CTX62.js → inspect-4X3GCH7D.js} +25 -25
  93. package/dist/{installer-M5OHZ3QU.js → installer-HBBKRFDP.js} +4 -4
  94. package/dist/{keyframes-K5UWQDSW.js → keyframes-7D4TUZZ2.js} +11 -11
  95. package/dist/{lambda-PXGK25LH.js → lambda-AYYSPAYH.js} +4 -4
  96. package/dist/{layout-SYWCNF2S.js → layout-J2IBMYTZ.js} +25 -25
  97. package/dist/{lint-A5W6BCKC.js → lint-H7QFZNTA.js} +11 -11
  98. package/dist/{list-CXWE53HJ.js → list-SPHCGWNR.js} +2 -2
  99. package/dist/{login-WUPTUIG2.js → login-A4GMDPEZ.js} +4 -4
  100. package/dist/{media-treatment-INJWEP6H.js → media-treatment-QOA3QGWO.js} +11 -11
  101. package/dist/{models-D5CMY6VB.js → models-ZDGTC4SZ.js} +6 -6
  102. package/dist/{motionShot-HS4M4WOQ.js → motionShot-QS5SVOHF.js} +11 -11
  103. package/dist/{normalize-audio-ILF3IDZC.js → normalize-audio-OPQAYTZV.js} +10 -10
  104. package/dist/{open-4V3RXCR6.js → open-UKGA7TPU.js} +18 -18
  105. package/dist/{pipeline-CPGRA375.js → pipeline-G5NLBVNJ.js} +5 -5
  106. package/dist/{play-IFATKPFL.js → play-C7GBF6WB.js} +19 -19
  107. package/dist/{preflight-IQEYFD33.js → preflight-DIJQBGM4.js} +6 -6
  108. package/dist/{present-A3EXMPEB.js → present-DWKHRNIC.js} +15 -15
  109. package/dist/{preview-6OFPNSRQ.js → preview-FGLYZD5S.js} +17 -17
  110. package/dist/{producer-T4HGO327.js → producer-NP2763FP.js} +1 -1
  111. package/dist/{projectConfig-VKUAJTKN.js → projectConfig-MVB3R3H4.js} +6 -6
  112. package/dist/{publication-EYW5DW5Q.js → publication-UBT6VC5K.js} +2 -2
  113. package/dist/{publish-7N3KAN23.js → publish-EP4CNDPL.js} +7 -7
  114. package/dist/{remove-background-76NDLWX2.js → remove-background-BSWFZHW3.js} +6 -6
  115. package/dist/{render-FVVTP6IC.js → render-4BL4C55X.js} +11 -11
  116. package/dist/{render-WWSM5VDX.js → render-4Q23SIOZ.js} +3 -3
  117. package/dist/{render-SGKRP4OI.js → render-I3S3XTXQ.js} +22 -22
  118. package/dist/{render-batch-UHVLIDQ6.js → render-batch-6MCTZTJR.js} +3 -3
  119. package/dist/{renderCancellation-TZ2YQXLI.js → renderCancellation-N3E4RU7B.js} +5 -5
  120. package/dist/{resolver-BERTN5TY.js → resolver-2D5RWIQP.js} +4 -4
  121. package/dist/{sherpa-WAI3BU35.js → sherpa-XLMKWU7U.js} +6 -6
  122. package/dist/skills/hyperframes/SKILL.md +9 -0
  123. package/dist/skills/hyperframes/references/brief-contract.md +1 -1
  124. package/dist/skills/hyperframes/references/review-loop.md +1 -1
  125. package/dist/skills/hyperframes-cli/SKILL.md +2 -1
  126. package/dist/skills/media-use/audio/references/tts.md +24 -7
  127. package/dist/skills/media-use/audio/scripts/heygen-tts.mjs +3 -2
  128. package/dist/skills/media-use/audio/scripts/heygen-tts.test.mjs +38 -0
  129. package/dist/skills/media-use/audio/scripts/heygen-voice.mjs +98 -0
  130. package/dist/skills/media-use/audio/scripts/heygen-voice.test.mjs +233 -0
  131. package/dist/skills/media-use/audio/scripts/lib/heygen.mjs +19 -5
  132. package/dist/skills/media-use/audio/scripts/lib/heygen.test.mjs +17 -0
  133. package/dist/skills/media-use/audio/scripts/lib/tts.mjs +2 -2
  134. package/dist/{skills-4J56N4BF.js → skills-HIHYTIAV.js} +10 -10
  135. package/dist/{skillsUpdateCheck-GPLLGZTN.js → skillsUpdateCheck-5YHBTQ6C.js} +3 -3
  136. package/dist/{snapshot-XPPNHMIG.js → snapshot-OHAYOW4C.js} +25 -25
  137. package/dist/{src-K6L2URKG.js → src-ESCXJW7I.js} +4 -4
  138. package/dist/{src-6ZDBAHYH.js → src-IXQPVJNK.js} +6 -6
  139. package/dist/{staticProjectServer-ETIXS3GJ.js → staticProjectServer-BP5PM77J.js} +13 -13
  140. package/dist/{status-P2I66DU7.js → status-BB22DSC3.js} +5 -5
  141. package/dist/studio/assets/{hyperframes-player-yABdb6yk.js → hyperframes-player-CmIh-wq9.js} +1 -1
  142. package/dist/studio/assets/{index-D77MIjSJ.js → index-4LRR6o2F.js} +1 -1
  143. package/dist/studio/assets/{index-Dt7lWtY7.js → index-CrYoEZ5p.js} +139 -139
  144. package/dist/studio/assets/{index-LrNlT5Tg.css → index-D11atkBt.css} +1 -1
  145. package/dist/studio/assets/{index-DWjF2Kxw.js → index-yCK8osBg.js} +1 -1
  146. package/dist/studio/index.d.ts +43 -35
  147. package/dist/studio/index.html +2 -2
  148. package/dist/studio/index.js +283 -143
  149. package/dist/studio/index.js.map +1 -1
  150. package/dist/studio/styles.css +1 -1
  151. package/dist/{studio-api-PTVN2GZ5.js → studio-api-MPH3F7Y5.js} +7 -7
  152. package/dist/{studioServer-55366NG4.js → studioServer-JD5KIYR6.js} +49 -42
  153. package/dist/{system-M44QRAAZ.js → system-JPG4ILMN.js} +5 -5
  154. package/dist/{telemetry-6GQL3BIP.js → telemetry-VP5MPNOI.js} +8 -8
  155. package/dist/{timeline-NMG3JG3V.js → timeline-TKJJ7RHM.js} +14 -14
  156. package/dist/{tokens-5LYIBBEF.js → tokens-DRCIONI6.js} +2 -2
  157. package/dist/{transcribe-4DGPFZTU.js → transcribe-7TASY37D.js} +11 -11
  158. package/dist/{transcribe-3SONDYLT.js → transcribe-ZOGMUKWL.js} +6 -6
  159. package/dist/{updateCheck-CXNND3CL.js → updateCheck-G5JNP5U5.js} +2 -2
  160. package/dist/{upgrade-RFTKDIVZ.js → upgrade-B2IT4JO4.js} +2 -2
  161. package/dist/{urlDownloader-VRZX26OK.js → urlDownloader-VQNIYP7Y.js} +4 -4
  162. package/dist/{validate-3BFHVVZH.js → validate-ENFIOU6R.js} +15 -15
  163. package/dist/{video-ECPRKRRP.js → video-MJBFMRFI.js} +5 -5
  164. package/package.json +1 -1
  165. package/dist/chunk-AMV2OPXR.js +0 -82
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ // HeyGen voice clones: `clone <audio> --name <n>`, `delete <voice_id>`, `list --prefix <p>` (references/tts.md).
3
+ // The clone id works as `heygen-tts.mjs --voice <id>`. A refusal prints HeyGen's own message and exits 1.
4
+ // Auth: same resolver as heygen-tts.mjs (lib/heygen.mjs).
5
+
6
+ import { readFileSync } from "node:fs";
7
+ import { extname } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { parseArgs } from "node:util";
10
+ import { heygenAuthHeaders, heygenJSON, heygenMessage, loadEnvFromDir } from "./lib/heygen.mjs";
11
+
12
+ const MEDIA_TYPES = { ".mp3": "audio/mpeg", ".wav": "audio/wav" };
13
+ const POLL_MS = 2_000;
14
+ const DEADLINE_MS = 120_000;
15
+
16
+ async function clone(file, name, headers, { sleep, now }) {
17
+ const mediaType = MEDIA_TYPES[extname(file).toLowerCase()];
18
+ if (!mediaType) throw new Error(`unsupported audio file ${file}: use .mp3 or .wav`);
19
+ const data = readFileSync(file).toString("base64");
20
+ const created = await heygenJSON("/voices/clone", {
21
+ method: "POST",
22
+ headers,
23
+ body: { voice_name: name, audio: { type: "base64", media_type: mediaType, data } },
24
+ });
25
+ const id = created.data.voice_clone_id;
26
+ const deadline = now() + DEADLINE_MS;
27
+ for (;;) {
28
+ const { data: voice } = await heygenJSON(`/voices/${id}`, { headers });
29
+ if (voice.status === "complete") return { voice_id: voice.voice_id ?? id };
30
+ if (voice.status === "failed") throw new Error(voice.failure_message || "voice clone failed");
31
+ if (now() >= deadline) throw new Error(`voice clone ${id} not ready after 120 s`);
32
+ await sleep(POLL_MS);
33
+ }
34
+ }
35
+
36
+ async function list(prefix, headers) {
37
+ const mine = [];
38
+ const seen = new Set();
39
+ let token;
40
+ do {
41
+ if (token && seen.has(token)) throw new Error(`HeyGen returned page token ${token} twice`);
42
+ if (token) seen.add(token);
43
+ const query = new URLSearchParams({ type: "private", limit: "100" });
44
+ if (token) query.set("token", token);
45
+ const page = await heygenJSON(`/voices?${query}`, { headers });
46
+ mine.push(...page.data.filter((v) => (v.name ?? "").startsWith(prefix)));
47
+ token = page.has_more ? page.next_token : null;
48
+ } while (token);
49
+ // ponytail: the list response has no created_at, so one GET per match; bounded by the clone limit.
50
+ return Promise.all(
51
+ mine.map(async ({ voice_id, name }) => {
52
+ const { data } = await heygenJSON(`/voices/${voice_id}`, { headers });
53
+ return { voice_id, name, created_at: data.created_at ?? null };
54
+ }),
55
+ );
56
+ }
57
+
58
+ export async function main(
59
+ argv,
60
+ {
61
+ sleep = (ms) => new Promise((r) => setTimeout(r, ms)),
62
+ now = Date.now,
63
+ out = (s) => process.stdout.write(`${s}\n`),
64
+ err = (s) => process.stderr.write(`${s}\n`),
65
+ } = {},
66
+ ) {
67
+ try {
68
+ const { positionals, values } = parseArgs({
69
+ args: argv,
70
+ allowPositionals: true,
71
+ options: { name: { type: "string" }, prefix: { type: "string", default: "" } },
72
+ });
73
+ const [command, arg] = positionals;
74
+ if (command === "clone") {
75
+ if (!arg || !values.name) throw new Error("usage: clone <audio-file> --name <name>");
76
+ out(JSON.stringify(await clone(arg, values.name, heygenAuthHeaders(), { sleep, now })));
77
+ } else if (command === "delete") {
78
+ if (!arg) throw new Error("usage: delete <voice_id>");
79
+ await heygenJSON(`/voices/${encodeURIComponent(arg)}`, {
80
+ method: "DELETE",
81
+ headers: heygenAuthHeaders(),
82
+ });
83
+ } else if (command === "list") {
84
+ out(JSON.stringify(await list(values.prefix, heygenAuthHeaders())));
85
+ } else {
86
+ throw new Error("usage: heygen-voice.mjs clone|delete|list (see the header of this file)");
87
+ }
88
+ return 0;
89
+ } catch (e) {
90
+ err(heygenMessage(e));
91
+ return 1;
92
+ }
93
+ }
94
+
95
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
96
+ loadEnvFromDir(process.cwd());
97
+ process.exitCode = await main(process.argv.slice(2));
98
+ }
@@ -0,0 +1,233 @@
1
+ import { afterEach, beforeEach, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { main } from "./heygen-voice.mjs";
7
+
8
+ const realFetch = globalThis.fetch;
9
+ const savedEnv = {
10
+ HEYGEN_ACCESS_TOKEN: process.env.HEYGEN_ACCESS_TOKEN,
11
+ HEYGEN_API_KEY: process.env.HEYGEN_API_KEY,
12
+ };
13
+ let dir;
14
+ let calls;
15
+
16
+ beforeEach(() => {
17
+ dir = mkdtempSync(join(tmpdir(), "heygen-voice-"));
18
+ delete process.env.HEYGEN_ACCESS_TOKEN;
19
+ process.env.HEYGEN_API_KEY = "hg_test";
20
+ calls = [];
21
+ });
22
+
23
+ afterEach(() => {
24
+ globalThis.fetch = realFetch;
25
+ for (const [k, v] of Object.entries(savedEnv)) {
26
+ if (v === undefined) delete process.env[k];
27
+ else process.env[k] = v;
28
+ }
29
+ rmSync(dir, { recursive: true, force: true });
30
+ });
31
+
32
+ // routes: "METHOD /path" → array of [status, body] answered in order (last one repeats).
33
+ function mockFetch(routes) {
34
+ globalThis.fetch = async (url, opts) => {
35
+ const key = `${opts.method} ${String(url).replace("https://api.heygen.com/v3", "")}`;
36
+ calls.push({ key, opts });
37
+ const queue = routes[key];
38
+ if (!queue) throw new Error(`unexpected request ${key}`);
39
+ const [status, body] = queue.length > 1 ? queue.shift() : queue[0];
40
+ return new Response(body === undefined ? null : JSON.stringify(body), { status });
41
+ };
42
+ }
43
+
44
+ async function run(argv, { sleep = async () => {}, now = () => 0 } = {}) {
45
+ const out = [];
46
+ const err = [];
47
+ const code = await main(argv, {
48
+ sleep,
49
+ now,
50
+ out: (s) => out.push(s),
51
+ err: (s) => err.push(s),
52
+ });
53
+ return { code, out: out.join("\n"), err: err.join("\n") };
54
+ }
55
+
56
+ function audioFile(name = "sample.mp3") {
57
+ const path = join(dir, name);
58
+ writeFileSync(path, Buffer.from("fake-audio"));
59
+ return path;
60
+ }
61
+
62
+ test("clone uploads base64 audio, polls until complete, prints the voice id", async () => {
63
+ mockFetch({
64
+ "POST /voices/clone": [[200, { data: { voice_clone_id: "vc1" } }]],
65
+ "GET /voices/vc1": [
66
+ [200, { data: { status: "processing", voice_id: "vc1" } }],
67
+ [200, { data: { status: "complete", voice_id: "vc1", name: "Me" } }],
68
+ ],
69
+ });
70
+ const sleeps = [];
71
+ const r = await run(["clone", audioFile(), "--name", "Me"], {
72
+ sleep: async (ms) => sleeps.push(ms),
73
+ });
74
+ assert.deepEqual(r, { code: 0, out: '{"voice_id":"vc1"}', err: "" });
75
+ assert.deepEqual(sleeps, [2000]);
76
+ const post = calls[0];
77
+ assert.equal(post.opts.headers["X-Api-Key"], "hg_test");
78
+ assert.deepEqual(JSON.parse(post.opts.body), {
79
+ voice_name: "Me",
80
+ audio: {
81
+ type: "base64",
82
+ media_type: "audio/mpeg",
83
+ data: Buffer.from("fake-audio").toString("base64"),
84
+ },
85
+ });
86
+ });
87
+
88
+ test("clone sends audio/wav for a .wav file", async () => {
89
+ mockFetch({
90
+ "POST /voices/clone": [[200, { data: { voice_clone_id: "vc1" } }]],
91
+ "GET /voices/vc1": [[200, { data: { status: "complete", voice_id: "vc1" } }]],
92
+ });
93
+ const r = await run(["clone", audioFile("take.WAV"), "--name", "Me"]);
94
+ assert.equal(r.code, 0);
95
+ assert.equal(JSON.parse(calls[0].opts.body).audio.media_type, "audio/wav");
96
+ });
97
+
98
+ test("clone prints HeyGen's refusal verbatim and exits 1", async () => {
99
+ const message =
100
+ "Voice clone limit reached (10). Delete unused clones or contact support to increase your limit.";
101
+ mockFetch({
102
+ "POST /voices/clone": [[400, { error: { code: "resource_limit_reached", message } }]],
103
+ });
104
+ const r = await run(["clone", audioFile(), "--name", "Me"]);
105
+ assert.deepEqual(r, { code: 1, out: "", err: message });
106
+ });
107
+
108
+ test("clone surfaces a failed clone's failure_message", async () => {
109
+ mockFetch({
110
+ "POST /voices/clone": [[200, { data: { voice_clone_id: "vc1" } }]],
111
+ "GET /voices/vc1": [[200, { data: { status: "failed", failure_message: "Audio too noisy" } }]],
112
+ });
113
+ const r = await run(["clone", audioFile(), "--name", "Me"]);
114
+ assert.deepEqual(r, { code: 1, out: "", err: "Audio too noisy" });
115
+ });
116
+
117
+ test("clone gives up after the 120 s deadline", async () => {
118
+ mockFetch({
119
+ "POST /voices/clone": [[200, { data: { voice_clone_id: "vc1" } }]],
120
+ "GET /voices/vc1": [[200, { data: { status: "processing" } }]],
121
+ });
122
+ let clock = 0;
123
+ const r = await run(["clone", audioFile(), "--name", "Me"], {
124
+ now: () => clock,
125
+ sleep: async (ms) => {
126
+ clock += ms;
127
+ },
128
+ });
129
+ assert.deepEqual(r, { code: 1, out: "", err: "voice clone vc1 not ready after 120 s" });
130
+ assert.equal(calls.filter((c) => c.key === "GET /voices/vc1").length, 61);
131
+ });
132
+
133
+ test("clone rejects an audio type other than mp3 or wav without calling HeyGen", async () => {
134
+ mockFetch({});
135
+ const r = await run(["clone", audioFile("take.ogg"), "--name", "Me"]);
136
+ assert.equal(r.code, 1);
137
+ assert.match(r.err, /use \.mp3 or \.wav/);
138
+ assert.equal(calls.length, 0);
139
+ });
140
+
141
+ test("delete calls DELETE /voices/<id> and exits 0", async () => {
142
+ mockFetch({ "DELETE /voices/vc1": [[200, { data: {} }]] });
143
+ const r = await run(["delete", "vc1"]);
144
+ assert.deepEqual(r, { code: 0, out: "", err: "" });
145
+ });
146
+
147
+ test("delete exits 0 on a 204 with no body, and escapes the id in the path", async () => {
148
+ mockFetch({ "DELETE /voices/a%2Fb": [[204]] });
149
+ const r = await run(["delete", "a/b"]);
150
+ assert.deepEqual(r, { code: 0, out: "", err: "" });
151
+ });
152
+
153
+ test("clone falls back to the clone id when the finished voice has no voice_id", async () => {
154
+ mockFetch({
155
+ "POST /voices/clone": [[200, { data: { voice_clone_id: "vc9" } }]],
156
+ "GET /voices/vc9": [[200, { data: { status: "complete" } }]],
157
+ });
158
+ const r = await run(["clone", audioFile(), "--name", "Me"]);
159
+ assert.deepEqual(r, { code: 0, out: '{"voice_id":"vc9"}', err: "" });
160
+ });
161
+
162
+ test("list skips a nameless voice and stops on a page token HeyGen repeats", async () => {
163
+ mockFetch({
164
+ "GET /voices?type=private&limit=100": [
165
+ [200, { data: [{ voice_id: "n", name: null }], has_more: true, next_token: "t2" }],
166
+ ],
167
+ "GET /voices?type=private&limit=100&token=t2": [
168
+ [200, { data: [], has_more: true, next_token: "t2" }],
169
+ ],
170
+ });
171
+ // A fake answers at once, so a list that never stops would starve any timeout: cap the calls instead.
172
+ const answer = globalThis.fetch;
173
+ globalThis.fetch = (...args) =>
174
+ calls.length >= 10 ? Promise.reject(new Error("paged forever")) : answer(...args);
175
+ const r = await run(["list", "--prefix", "desk-"]);
176
+ assert.deepEqual(r, { code: 1, out: "", err: "HeyGen returned page token t2 twice" });
177
+ });
178
+
179
+ test("delete prints HeyGen's 404 message verbatim and exits 1", async () => {
180
+ mockFetch({
181
+ "DELETE /voices/gone": [
182
+ [404, { error: { code: "voice_not_found", message: "Voice not found: gone" } }],
183
+ ],
184
+ });
185
+ const r = await run(["delete", "gone"]);
186
+ assert.deepEqual(r, { code: 1, out: "", err: "Voice not found: gone" });
187
+ });
188
+
189
+ test("list pages through private voices and returns prefix matches with created_at", async () => {
190
+ mockFetch({
191
+ "GET /voices?type=private&limit=100": [
192
+ [
193
+ 200,
194
+ {
195
+ data: [
196
+ { voice_id: "a", name: "desk-1" },
197
+ { voice_id: "b", name: "other" },
198
+ ],
199
+ has_more: true,
200
+ next_token: "t2",
201
+ },
202
+ ],
203
+ ],
204
+ "GET /voices?type=private&limit=100&token=t2": [
205
+ [200, { data: [{ voice_id: "c", name: "desk-2" }], has_more: false }],
206
+ ],
207
+ "GET /voices/a": [[200, { data: { voice_id: "a", created_at: 1700000000 } }]],
208
+ "GET /voices/c": [[200, { data: { voice_id: "c", created_at: 1700000100 } }]],
209
+ });
210
+ const r = await run(["list", "--prefix", "desk-"]);
211
+ assert.equal(r.code, 0);
212
+ assert.deepEqual(JSON.parse(r.out), [
213
+ { voice_id: "a", name: "desk-1", created_at: 1700000000 },
214
+ { voice_id: "c", name: "desk-2", created_at: 1700000100 },
215
+ ]);
216
+ });
217
+
218
+ test("list prints HeyGen's refusal verbatim and exits 1", async () => {
219
+ const message = "Invalid or expired API key. Verify your x-api-key header.";
220
+ mockFetch({
221
+ "GET /voices?type=private&limit=100": [[401, { error: { code: "unauthorized", message } }]],
222
+ });
223
+ const r = await run(["list", "--prefix", "desk-"]);
224
+ assert.deepEqual(r, { code: 1, out: "", err: message });
225
+ });
226
+
227
+ test("a host-injected HEYGEN_ACCESS_TOKEN is sent as Bearer", async () => {
228
+ process.env.HEYGEN_ACCESS_TOKEN = "at_host";
229
+ mockFetch({ "DELETE /voices/vc1": [[200, { data: {} }]] });
230
+ await run(["delete", "vc1"]);
231
+ assert.equal(calls[0].opts.headers.Authorization, "Bearer at_host");
232
+ assert.equal(calls[0].opts.headers["X-Api-Key"], undefined);
233
+ });
@@ -1,7 +1,8 @@
1
1
  import { fetchMedia } from "../../../scripts/lib/media-fetch.mjs";
2
2
  // heygen.mjs — vendored HeyGen REST helpers (auth + transport) for the audio
3
3
  // pipeline. The credential resolver matches the hyperframes CLI auth: first
4
- // usable source wins — $HEYGEN_API_KEY / $HYPERFRAMES_API_KEY → a nearby .env → ~/.heygen/
4
+ // usable source wins — a host-injected OAuth $HEYGEN_ACCESS_TOKEN (Bearer) →
5
+ // $HEYGEN_API_KEY / $HYPERFRAMES_API_KEY → a nearby .env → ~/.heygen/
5
6
  // credentials (oauth → Bearer, else api_key → X-Api-Key; $HEYGEN_CONFIG_DIR
6
7
  // overrides the dir). Vendored so the skill ships standalone. Pure node.
7
8
 
@@ -67,6 +68,8 @@ export function heygenCredential() {
67
68
  // (a folder, a locked ~/.heygen), so heygenAuthHeaders can say to fix that path: logging in again would fail there too.
68
69
  // Read without checking first, so the file cannot change between a check and the read.
69
70
  function resolveCredential() {
71
+ const accessToken = process.env.HEYGEN_ACCESS_TOKEN;
72
+ if (accessToken) return { headers: { Authorization: `Bearer ${accessToken}` } };
70
73
  const envKey = process.env.HEYGEN_API_KEY || process.env.HYPERFRAMES_API_KEY;
71
74
  if (envKey) return { headers: { "X-Api-Key": envKey } };
72
75
 
@@ -144,11 +147,22 @@ export async function heygenJSON(path, { method = "GET", headers = {}, body } =
144
147
  const res = await fetch(`${HEYGEN_BASE}${path}`, opts);
145
148
  if (!res.ok) {
146
149
  const detail = await res.text().catch(() => "");
147
- throw new Error(
148
- `HeyGen ${method} ${path} → HTTP ${res.status}${detail ? `\n${detail.slice(0, 300)}` : ""}`,
149
- );
150
+ const message = `HeyGen ${method} ${path} → HTTP ${res.status}${detail ? `\n${detail.slice(0, 300)}` : ""}`;
151
+ throw Object.assign(new Error(message), { status: res.status, body: detail });
152
+ }
153
+ // A DELETE may answer 204 with no body.
154
+ const text = await res.text();
155
+ return text ? JSON.parse(text) : {};
156
+ }
157
+
158
+ // HeyGen's own words for a failed call: its {"error":{"message"}}, else the raw body, else the error's message.
159
+ export function heygenMessage(e) {
160
+ if (!e?.body) return e?.message ? String(e.message) : String(e);
161
+ try {
162
+ return JSON.parse(e.body).error?.message ?? e.body;
163
+ } catch {
164
+ return e.body;
150
165
  }
151
- return res.json();
152
166
  }
153
167
 
154
168
  // Download a (presigned) URL to destPath; returns byte length.
@@ -11,15 +11,19 @@ import {
11
11
  } from "./heygen.mjs";
12
12
 
13
13
  function withCleanHeygenEnv(fn) {
14
+ const previousAccessToken = process.env.HEYGEN_ACCESS_TOKEN;
14
15
  const previousApiKey = process.env.HEYGEN_API_KEY;
15
16
  const previousHyperframesApiKey = process.env.HYPERFRAMES_API_KEY;
16
17
  const previousConfigDir = process.env.HEYGEN_CONFIG_DIR;
17
18
  try {
19
+ delete process.env.HEYGEN_ACCESS_TOKEN;
18
20
  delete process.env.HEYGEN_API_KEY;
19
21
  delete process.env.HYPERFRAMES_API_KEY;
20
22
  delete process.env.HEYGEN_CONFIG_DIR;
21
23
  return fn();
22
24
  } finally {
25
+ if (previousAccessToken === undefined) delete process.env.HEYGEN_ACCESS_TOKEN;
26
+ else process.env.HEYGEN_ACCESS_TOKEN = previousAccessToken;
23
27
  if (previousApiKey === undefined) delete process.env.HEYGEN_API_KEY;
24
28
  else process.env.HEYGEN_API_KEY = previousApiKey;
25
29
  if (previousHyperframesApiKey === undefined) delete process.env.HYPERFRAMES_API_KEY;
@@ -67,6 +71,19 @@ test("heygenAuthHeaders tags OAuth requests as CLI traffic and with the media-us
67
71
  });
68
72
  });
69
73
 
74
+ test("a host-injected HEYGEN_ACCESS_TOKEN wins over an API key and is treated as OAuth", () => {
75
+ withCleanHeygenEnv(() => {
76
+ process.env.HEYGEN_ACCESS_TOKEN = "at_host";
77
+ process.env.HEYGEN_API_KEY = "hg_test";
78
+ assert.deepEqual(heygenAuthHeaders(), {
79
+ Authorization: "Bearer at_host",
80
+ "X-HeyGen-Source": "cli",
81
+ "X-HeyGen-Client-Source": "media-use",
82
+ });
83
+ assert.equal(heygenAuthMethod(), "oauth");
84
+ });
85
+ });
86
+
70
87
  test("heygenAuthMethod returns api_key for an env API key, without tagging headers", () => {
71
88
  withCleanHeygenEnv(() => {
72
89
  process.env.HEYGEN_API_KEY = "hg_test";
@@ -18,7 +18,7 @@ import { spawn, spawnSync } from "node:child_process";
18
18
  import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
19
19
  import { tmpdir } from "node:os";
20
20
  import { dirname, join } from "node:path";
21
- import { heygenAuthHeaders, heygenCredential, heygenJSON } from "./heygen.mjs";
21
+ import { heygenAuthHeaders, heygenCredential, heygenJSON, heygenMessage } from "./heygen.mjs";
22
22
  import { pythonInvocation } from "./python.mjs";
23
23
  import { synthesizeGemini } from "./gemini-tts.mjs";
24
24
  import { geminiConfigured } from "./gemini-auth.mjs";
@@ -350,7 +350,7 @@ export async function synthesizeHeygen({ text, voiceId, lang, speed, wavAbs }, d
350
350
  : [];
351
351
  return { ok: true, words };
352
352
  } catch (e) {
353
- return { ok: false, words: null, error: e?.message ? String(e.message) : String(e) };
353
+ return { ok: false, words: null, error: heygenMessage(e) };
354
354
  }
355
355
  }
356
356
 
@@ -9,15 +9,15 @@ import {
9
9
  } from "./chunk-WMQNIQDJ.js";
10
10
  import {
11
11
  trackSkillsInstallSkipped
12
- } from "./chunk-7NWNDQID.js";
13
- import "./chunk-S3JOM6L4.js";
12
+ } from "./chunk-OHE54L2X.js";
13
+ import "./chunk-YVFBNUUH.js";
14
14
  import {
15
15
  diag
16
16
  } from "./chunk-VWG7OQKU.js";
17
17
  import {
18
18
  c
19
19
  } from "./chunk-ZTZA4UWZ.js";
20
- import "./chunk-ILOJE2TE.js";
20
+ import "./chunk-K4DH364E.js";
21
21
  import "./chunk-AMKC3AXA.js";
22
22
  import {
23
23
  defineCommand
@@ -27,12 +27,12 @@ import {
27
27
  CliResultSignal,
28
28
  setCommandExitCode
29
29
  } from "./chunk-PBN6GBJE.js";
30
- import "./chunk-WAD4ACBZ.js";
31
- import "./chunk-TLA5RBEB.js";
30
+ import "./chunk-T7KM6AG5.js";
31
+ import "./chunk-ZGGEWKPA.js";
32
32
  import "./chunk-F7MXHGU3.js";
33
33
  import "./chunk-DPVXBVLL.js";
34
- import "./chunk-RYP46ARK.js";
35
- import "./chunk-53IO4HLZ.js";
34
+ import "./chunk-QM7YQ35N.js";
35
+ import "./chunk-YKSQOWAL.js";
36
36
  import "./chunk-VC76R6W2.js";
37
37
  import "./chunk-OFQWTKPW.js";
38
38
  import "./chunk-TWWSYAKJ.js";
@@ -51,15 +51,15 @@ import {
51
51
  isCoreSkill,
52
52
  presentSkills,
53
53
  pruneOrphanedLockEntries
54
- } from "./chunk-2FH6HOQ2.js";
54
+ } from "./chunk-OJ3NJ54J.js";
55
55
  import {
56
56
  withMeta
57
- } from "./chunk-CZRQH5SP.js";
57
+ } from "./chunk-OLLALODH.js";
58
58
  import "./chunk-K4WIOZFP.js";
59
59
  import "./chunk-XUXGIA7H.js";
60
60
  import "./chunk-WERLJGIC.js";
61
61
  import "./chunk-ISN5GRYI.js";
62
- import "./chunk-XQSMY5HF.js";
62
+ import "./chunk-IBSKMPBO.js";
63
63
  import "./chunk-KNU5COPB.js";
64
64
  import {
65
65
  buildNpxCommand
@@ -9,13 +9,13 @@ import {
9
9
  printSkillsUpdateNotice,
10
10
  refreshSkillsCache,
11
11
  skillsCheckDue
12
- } from "./chunk-2FH6HOQ2.js";
13
- import "./chunk-CZRQH5SP.js";
12
+ } from "./chunk-OJ3NJ54J.js";
13
+ import "./chunk-OLLALODH.js";
14
14
  import "./chunk-K4WIOZFP.js";
15
15
  import "./chunk-XUXGIA7H.js";
16
16
  import "./chunk-WERLJGIC.js";
17
17
  import "./chunk-ISN5GRYI.js";
18
- import "./chunk-XQSMY5HF.js";
18
+ import "./chunk-IBSKMPBO.js";
19
19
  import "./chunk-KNU5COPB.js";
20
20
  import "./chunk-M2WBOQ2Q.js";
21
21
  export {
@@ -9,16 +9,16 @@ import {
9
9
  } from "./chunk-KZI44OPA.js";
10
10
  import {
11
11
  serveStaticProjectHtml
12
- } from "./chunk-ELHC6CLH.js";
12
+ } from "./chunk-EJA7FDVA.js";
13
13
  import {
14
14
  formatLintFindings
15
15
  } from "./chunk-6CSYCFQV.js";
16
16
  import "./chunk-XUHOIDKG.js";
17
17
  import "./chunk-X7MTZ4T2.js";
18
- import "./chunk-HISVSZH7.js";
18
+ import "./chunk-AZP4Q3HX.js";
19
19
  import {
20
20
  resolveProject
21
- } from "./chunk-UI2I6ZQE.js";
21
+ } from "./chunk-RGDS435K.js";
22
22
  import {
23
23
  DEFAULT_ZOOM_SCALE,
24
24
  captureRegionCrop,
@@ -27,28 +27,28 @@ import {
27
27
  resolveCropRegion,
28
28
  runFfmpegOnce,
29
29
  seekCompositionTimeline
30
- } from "./chunk-Z3SUEG2T.js";
30
+ } from "./chunk-JD6UVTTT.js";
31
31
  import "./chunk-5Z63TBTX.js";
32
- import "./chunk-SKZ6H3JT.js";
33
- import "./chunk-2QAAOW5T.js";
32
+ import "./chunk-HUJT2WV7.js";
33
+ import "./chunk-2K3QXNHK.js";
34
34
  import "./chunk-YEIFI443.js";
35
35
  import "./chunk-IHFUKJOR.js";
36
- import "./chunk-24AS45UQ.js";
37
- import "./chunk-OCH6V4FB.js";
36
+ import "./chunk-MKTOQKW4.js";
37
+ import "./chunk-BVC2TTOR.js";
38
38
  import "./chunk-EOVYQ3IG.js";
39
- import "./chunk-IOMMM4AX.js";
40
- import "./chunk-GPUM6BRL.js";
39
+ import "./chunk-CML2M4A5.js";
40
+ import "./chunk-QV4PJ5EE.js";
41
41
  import {
42
42
  resolveLocalBrowserGpuMode
43
- } from "./chunk-4XAAOWFC.js";
43
+ } from "./chunk-CYILDWZD.js";
44
44
  import "./chunk-PFCFR3KZ.js";
45
- import "./chunk-MBSCHJQZ.js";
45
+ import "./chunk-CANIQ65S.js";
46
46
  import "./chunk-XT7X6QCP.js";
47
47
  import "./chunk-4YYJOFKS.js";
48
48
  import "./chunk-HVW7ABXD.js";
49
- import "./chunk-BET5FXMM.js";
50
- import "./chunk-E26WHQFM.js";
51
- import "./chunk-XIJTGR4O.js";
49
+ import "./chunk-HN63O2Y6.js";
50
+ import "./chunk-NGQ5NP2Q.js";
51
+ import "./chunk-EZ54IXGG.js";
52
52
  import "./chunk-AWDFDFI3.js";
53
53
  import "./chunk-P6LJ4Y32.js";
54
54
  import "./chunk-GMECXFAN.js";
@@ -58,13 +58,13 @@ import {
58
58
  getFFmpegInstallHint
59
59
  } from "./chunk-TVCRUG2S.js";
60
60
  import "./chunk-NSVHO5LZ.js";
61
- import "./chunk-7NWNDQID.js";
62
- import "./chunk-S3JOM6L4.js";
61
+ import "./chunk-OHE54L2X.js";
62
+ import "./chunk-YVFBNUUH.js";
63
63
  import "./chunk-VWG7OQKU.js";
64
64
  import {
65
65
  c
66
66
  } from "./chunk-ZTZA4UWZ.js";
67
- import "./chunk-ILOJE2TE.js";
67
+ import "./chunk-K4DH364E.js";
68
68
  import "./chunk-AMKC3AXA.js";
69
69
  import {
70
70
  defineCommand
@@ -75,19 +75,19 @@ import {
75
75
  } from "./chunk-PBN6GBJE.js";
76
76
  import "./chunk-KC5XXX3X.js";
77
77
  import "./chunk-TJSTGSAW.js";
78
- import "./chunk-WAD4ACBZ.js";
78
+ import "./chunk-T7KM6AG5.js";
79
79
  import {
80
80
  isClipVisibleAt,
81
81
  isInClipWindow
82
- } from "./chunk-TLA5RBEB.js";
82
+ } from "./chunk-ZGGEWKPA.js";
83
83
  import "./chunk-F7MXHGU3.js";
84
84
  import "./chunk-DPVXBVLL.js";
85
- import "./chunk-RYP46ARK.js";
85
+ import "./chunk-QM7YQ35N.js";
86
86
  import {
87
87
  readElementRateSpec,
88
88
  sourceTimeAt,
89
89
  timeAtSourceTime
90
- } from "./chunk-53IO4HLZ.js";
90
+ } from "./chunk-YKSQOWAL.js";
91
91
  import "./chunk-VC76R6W2.js";
92
92
  import "./chunk-OFQWTKPW.js";
93
93
  import {
@@ -110,7 +110,7 @@ import "./chunk-K4WIOZFP.js";
110
110
  import "./chunk-XUXGIA7H.js";
111
111
  import "./chunk-WERLJGIC.js";
112
112
  import "./chunk-ISN5GRYI.js";
113
- import "./chunk-XQSMY5HF.js";
113
+ import "./chunk-IBSKMPBO.js";
114
114
  import {
115
115
  normalizeErrorMessage
116
116
  } from "./chunk-KNU5COPB.js";
@@ -363,7 +363,7 @@ function computeSnapshotTimes(duration, opts) {
363
363
  return { times: times.map(round), appendedTail: false };
364
364
  }
365
365
  async function captureSnapshots(projectDir, opts) {
366
- const { bundleWithLocalizedFonts } = await import("./bundleWithLocalizedFonts-EDBQ5EME.js");
366
+ const { bundleWithLocalizedFonts } = await import("./bundleWithLocalizedFonts-VYYJV4MC.js");
367
367
  const numFrames = opts.frames ?? 5;
368
368
  const html = await bundleWithLocalizedFonts(projectDir);
369
369
  const server = await serveStaticProjectHtml(projectDir, html, void 0, [], opts.autoProxy);
@@ -436,7 +436,7 @@ async function captureSnapshots(projectDir, opts) {
436
436
  let syncVideoFrameVisibility = null;
437
437
  let extractMediaMetadata = null;
438
438
  try {
439
- const engine = await import("./src-K6L2URKG.js");
439
+ const engine = await import("./src-ESCXJW7I.js");
440
440
  injectVideoFramesBatch = engine.injectVideoFramesBatch;
441
441
  syncVideoFrameVisibility = engine.syncVideoFrameVisibility;
442
442
  extractMediaMetadata = engine.extractMediaMetadata;
@@ -212,15 +212,15 @@ import {
212
212
  verifyGpuParity,
213
213
  writeCapturedFrame,
214
214
  writeUrlDownloadTelemetry
215
- } from "./chunk-WAD4ACBZ.js";
215
+ } from "./chunk-T7KM6AG5.js";
216
216
  import {
217
217
  MEDIA_VISUAL_STYLE_PROPERTIES,
218
218
  quantizeTimeToFrame
219
- } from "./chunk-TLA5RBEB.js";
219
+ } from "./chunk-ZGGEWKPA.js";
220
220
  import "./chunk-F7MXHGU3.js";
221
221
  import "./chunk-DPVXBVLL.js";
222
- import "./chunk-RYP46ARK.js";
223
- import "./chunk-53IO4HLZ.js";
222
+ import "./chunk-QM7YQ35N.js";
223
+ import "./chunk-YKSQOWAL.js";
224
224
  import "./chunk-VC76R6W2.js";
225
225
  import "./chunk-OFQWTKPW.js";
226
226
  import {