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.
- package/dist/{add-CJXLRVWK.js → add-IFW36THF.js} +14 -14
- package/dist/{animatedGifPrep-VHXPTSJL.js → animatedGifPrep-RWLNZGK4.js} +5 -5
- package/dist/{asset-KTRZSJ5R.js → asset-WMPG6T2H.js} +2 -2
- package/dist/{assetCataloger-NH6UQG4Y.js → assetCataloger-KJRYDRTK.js} +2 -2
- package/dist/{auth-T52MOHC7.js → auth-552SJTZY.js} +2 -2
- package/dist/{autoUpdate-EI6JX53V.js → autoUpdate-2EEU2WEN.js} +2 -2
- package/dist/{backgroundChecks-7N3FFYIV.js → backgroundChecks-EO47KLYR.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-JDH4PXPD.js → batchRender-ZKBWCNPW.js} +3 -3
- package/dist/{beats-TG2TOST6.js → beats-JSLKCIMO.js} +11 -11
- package/dist/{benchmark-WGXMGPUI.js → benchmark-4OITC52U.js} +11 -11
- package/dist/{browser-VMEADLNK.js → browser-7KKHZVZG.js} +8 -8
- package/dist/{bundleWithLocalizedFonts-EDBQ5EME.js → bundleWithLocalizedFonts-VYYJV4MC.js} +2 -2
- package/dist/{capture-UZFI2G65.js → capture-6OXDGVSK.js} +13 -18
- package/dist/{capture-22IWCYV2.js → capture-Q4HT2YI3.js} +2 -2
- package/dist/{catalog-3V4SSSYE.js → catalog-PZXB7JKY.js} +14 -14
- package/dist/{check-LTKOTPFI.js → check-O4VPFH7X.js} +30 -30
- package/dist/{checkBrowser-LTZPCRBO.js → checkBrowser-FKXDR2O3.js} +29 -29
- package/dist/{chunk-2QAAOW5T.js → chunk-2K3QXNHK.js} +1 -1
- package/dist/{chunk-KQ7BAEVP.js → chunk-6AGYEZQ7.js} +2 -2
- package/dist/{chunk-4TIUZ6Z7.js → chunk-75Z3SG7S.js} +2 -2
- package/dist/{chunk-HISVSZH7.js → chunk-AZP4Q3HX.js} +2 -2
- package/dist/{chunk-OCH6V4FB.js → chunk-BVC2TTOR.js} +2 -2
- package/dist/{chunk-MBSCHJQZ.js → chunk-CANIQ65S.js} +1 -1
- package/dist/{chunk-IOMMM4AX.js → chunk-CML2M4A5.js} +1 -1
- package/dist/{chunk-4XAAOWFC.js → chunk-CYILDWZD.js} +1 -1
- package/dist/{chunk-PQQZNS5K.js → chunk-CZBP6WD7.js} +1 -1
- package/dist/{chunk-ELHC6CLH.js → chunk-EJA7FDVA.js} +3 -3
- package/dist/{chunk-XIJTGR4O.js → chunk-EZ54IXGG.js} +1 -1
- package/dist/{chunk-DR7F77AN.js → chunk-FMTOCJN6.js} +1 -1
- package/dist/{chunk-IML47HIH.js → chunk-FWJDB65E.js} +7 -7
- package/dist/chunk-GULOKZLI.js +155 -0
- package/dist/{chunk-4EZKLNMD.js → chunk-HIPHGIMM.js} +1 -1
- package/dist/{chunk-BET5FXMM.js → chunk-HN63O2Y6.js} +1 -1
- package/dist/{chunk-SKZ6H3JT.js → chunk-HUJT2WV7.js} +1 -1
- package/dist/{chunk-EYNWMEWX.js → chunk-I33AB6HW.js} +9 -9
- package/dist/{chunk-XQSMY5HF.js → chunk-IBSKMPBO.js} +2 -2
- package/dist/{chunk-AICUP6TU.js → chunk-IJPINTW6.js} +1 -1
- package/dist/{chunk-RTINVJNS.js → chunk-IWF6XF2V.js} +1 -1
- package/dist/{chunk-Z3SUEG2T.js → chunk-JD6UVTTT.js} +5 -5
- package/dist/{chunk-ILOJE2TE.js → chunk-K4DH364E.js} +1 -1
- package/dist/{chunk-EJF6CESB.js → chunk-M4LHIME7.js} +1 -1
- package/dist/{chunk-24AS45UQ.js → chunk-MKTOQKW4.js} +71 -22
- package/dist/{dotEnv-AI4SYVTX.js → chunk-NGKM64BP.js} +2 -2
- package/dist/{chunk-E26WHQFM.js → chunk-NGQ5NP2Q.js} +2 -2
- package/dist/{chunk-7NWNDQID.js → chunk-OHE54L2X.js} +3 -3
- package/dist/{chunk-2FH6HOQ2.js → chunk-OJ3NJ54J.js} +1 -1
- package/dist/{chunk-CZRQH5SP.js → chunk-OLLALODH.js} +1 -1
- package/dist/{chunk-VEGNMQZI.js → chunk-PEOAH4LM.js} +2 -2
- package/dist/{chunk-RYP46ARK.js → chunk-QM7YQ35N.js} +1 -1
- package/dist/{chunk-GPUM6BRL.js → chunk-QV4PJ5EE.js} +1 -1
- package/dist/{chunk-UI2I6ZQE.js → chunk-RGDS435K.js} +1 -1
- package/dist/{chunk-3SHYUYXR.js → chunk-SBMSZEBS.js} +9 -9
- package/dist/{chunk-MUAFAG77.js → chunk-SD4TJSOZ.js} +4 -4
- package/dist/{chunk-QLKCB3NY.js → chunk-SDRIDMMN.js} +7 -7
- package/dist/{chunk-3V6V66SZ.js → chunk-T64K236B.js} +2 -2
- package/dist/{chunk-WAD4ACBZ.js → chunk-T7KM6AG5.js} +2 -2
- package/dist/{chunk-PUFPAYTJ.js → chunk-TSJNOSJF.js} +1 -1
- package/dist/{chunk-UMMVYWDI.js → chunk-WZQYKSDF.js} +5 -5
- package/dist/{chunk-73KPBRCO.js → chunk-Y6UZPO7H.js} +1 -1
- package/dist/{chunk-53IO4HLZ.js → chunk-YKSQOWAL.js} +31 -1
- package/dist/{chunk-S3JOM6L4.js → chunk-YVFBNUUH.js} +3 -3
- package/dist/{chunk-TLA5RBEB.js → chunk-ZGGEWKPA.js} +1 -1
- package/dist/{clean-YZQXCSXZ.js → clean-ZQ3QVGVU.js} +14 -14
- package/dist/cli.js +52 -52
- package/dist/{cloud-TYUXSEGA.js → cloud-E4GWT7KZ.js} +4 -4
- package/dist/{cloudrun-MA2JVRHV.js → cloudrun-RRNAJMHQ.js} +3 -3
- package/dist/{compare-6DSDY2IF.js → compare-4IMB3KDE.js} +24 -24
- package/dist/{compiler-4FHYKPNR.js → compiler-GM4XUGUA.js} +2 -2
- package/dist/{component-NY4JERQ5.js → component-ZIKBZXGS.js} +3 -3
- package/dist/{compositions-SI2SKZAF.js → compositions-DRFZ36DG.js} +10 -10
- package/dist/{delete-YU7XRF6M.js → delete-7LIHYMTQ.js} +2 -2
- package/dist/{dist-AMQZTIJP.js → dist-57EISMJZ.js} +2 -2
- package/dist/{doctor-MXX7AHXT.js → doctor-GVRY22DC.js} +9 -9
- package/dist/dotEnv-AECLXQSO.js +14 -0
- package/dist/{events-R5N3EVAF.js → events-P3XLY3QN.js} +7 -7
- package/dist/{events-LLCZN2LK.js → events-XHIAV6Q6.js} +8 -8
- package/dist/{feedback-MIZ3HJT4.js → feedback-I2IJMVE6.js} +9 -9
- package/dist/{figma-4ESVBLHH.js → figma-KXZD5OXU.js} +3 -3
- package/dist/fontLocalizeCli.js +7 -7
- package/dist/{get-OF3I77OW.js → get-3TF6CQRJ.js} +2 -2
- package/dist/{gpuPolicy-KDI7HVOA.js → gpuPolicy-GUILWNQI.js} +5 -5
- package/dist/{grade-compare-QXE4ZEZU.js → grade-compare-6A4MPRDT.js} +24 -24
- package/dist/{help-NFHZFSQN.js → help-P2LXSWPH.js} +2 -2
- package/dist/{history-DTRCFREW.js → history-TIEBO3TQ.js} +14 -14
- package/dist/hyperframe-runtime.js +45 -45
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +45 -45
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/{info-KRDLMYKB.js → info-RDYN6M4J.js} +10 -10
- package/dist/{init-XTXSP6IU.js → init-FWKYWNED.js} +21 -21
- package/dist/{inspect-KH3CTX62.js → inspect-4X3GCH7D.js} +25 -25
- package/dist/{installer-M5OHZ3QU.js → installer-HBBKRFDP.js} +4 -4
- package/dist/{keyframes-K5UWQDSW.js → keyframes-7D4TUZZ2.js} +11 -11
- package/dist/{lambda-PXGK25LH.js → lambda-AYYSPAYH.js} +4 -4
- package/dist/{layout-SYWCNF2S.js → layout-J2IBMYTZ.js} +25 -25
- package/dist/{lint-A5W6BCKC.js → lint-H7QFZNTA.js} +11 -11
- package/dist/{list-CXWE53HJ.js → list-SPHCGWNR.js} +2 -2
- package/dist/{login-WUPTUIG2.js → login-A4GMDPEZ.js} +4 -4
- package/dist/{media-treatment-INJWEP6H.js → media-treatment-QOA3QGWO.js} +11 -11
- package/dist/{models-D5CMY6VB.js → models-ZDGTC4SZ.js} +6 -6
- package/dist/{motionShot-HS4M4WOQ.js → motionShot-QS5SVOHF.js} +11 -11
- package/dist/{normalize-audio-ILF3IDZC.js → normalize-audio-OPQAYTZV.js} +10 -10
- package/dist/{open-4V3RXCR6.js → open-UKGA7TPU.js} +18 -18
- package/dist/{pipeline-CPGRA375.js → pipeline-G5NLBVNJ.js} +5 -5
- package/dist/{play-IFATKPFL.js → play-C7GBF6WB.js} +19 -19
- package/dist/{preflight-IQEYFD33.js → preflight-DIJQBGM4.js} +6 -6
- package/dist/{present-A3EXMPEB.js → present-DWKHRNIC.js} +15 -15
- package/dist/{preview-6OFPNSRQ.js → preview-FGLYZD5S.js} +17 -17
- package/dist/{producer-T4HGO327.js → producer-NP2763FP.js} +1 -1
- package/dist/{projectConfig-VKUAJTKN.js → projectConfig-MVB3R3H4.js} +6 -6
- package/dist/{publication-EYW5DW5Q.js → publication-UBT6VC5K.js} +2 -2
- package/dist/{publish-7N3KAN23.js → publish-EP4CNDPL.js} +7 -7
- package/dist/{remove-background-76NDLWX2.js → remove-background-BSWFZHW3.js} +6 -6
- package/dist/{render-FVVTP6IC.js → render-4BL4C55X.js} +11 -11
- package/dist/{render-WWSM5VDX.js → render-4Q23SIOZ.js} +3 -3
- package/dist/{render-SGKRP4OI.js → render-I3S3XTXQ.js} +22 -22
- package/dist/{render-batch-UHVLIDQ6.js → render-batch-6MCTZTJR.js} +3 -3
- package/dist/{renderCancellation-TZ2YQXLI.js → renderCancellation-N3E4RU7B.js} +5 -5
- package/dist/{resolver-BERTN5TY.js → resolver-2D5RWIQP.js} +4 -4
- package/dist/{sherpa-WAI3BU35.js → sherpa-XLMKWU7U.js} +6 -6
- package/dist/skills/hyperframes/SKILL.md +9 -0
- package/dist/skills/hyperframes/references/brief-contract.md +1 -1
- package/dist/skills/hyperframes/references/review-loop.md +1 -1
- package/dist/skills/hyperframes-cli/SKILL.md +2 -1
- package/dist/skills/media-use/audio/references/tts.md +24 -7
- package/dist/skills/media-use/audio/scripts/heygen-tts.mjs +3 -2
- package/dist/skills/media-use/audio/scripts/heygen-tts.test.mjs +38 -0
- package/dist/skills/media-use/audio/scripts/heygen-voice.mjs +98 -0
- package/dist/skills/media-use/audio/scripts/heygen-voice.test.mjs +233 -0
- package/dist/skills/media-use/audio/scripts/lib/heygen.mjs +19 -5
- package/dist/skills/media-use/audio/scripts/lib/heygen.test.mjs +17 -0
- package/dist/skills/media-use/audio/scripts/lib/tts.mjs +2 -2
- package/dist/{skills-4J56N4BF.js → skills-HIHYTIAV.js} +10 -10
- package/dist/{skillsUpdateCheck-GPLLGZTN.js → skillsUpdateCheck-5YHBTQ6C.js} +3 -3
- package/dist/{snapshot-XPPNHMIG.js → snapshot-OHAYOW4C.js} +25 -25
- package/dist/{src-K6L2URKG.js → src-ESCXJW7I.js} +4 -4
- package/dist/{src-6ZDBAHYH.js → src-IXQPVJNK.js} +6 -6
- package/dist/{staticProjectServer-ETIXS3GJ.js → staticProjectServer-BP5PM77J.js} +13 -13
- package/dist/{status-P2I66DU7.js → status-BB22DSC3.js} +5 -5
- package/dist/studio/assets/{hyperframes-player-yABdb6yk.js → hyperframes-player-CmIh-wq9.js} +1 -1
- package/dist/studio/assets/{index-D77MIjSJ.js → index-4LRR6o2F.js} +1 -1
- package/dist/studio/assets/{index-Dt7lWtY7.js → index-CrYoEZ5p.js} +139 -139
- package/dist/studio/assets/{index-LrNlT5Tg.css → index-D11atkBt.css} +1 -1
- package/dist/studio/assets/{index-DWjF2Kxw.js → index-yCK8osBg.js} +1 -1
- package/dist/studio/index.d.ts +43 -35
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +283 -143
- package/dist/studio/index.js.map +1 -1
- package/dist/studio/styles.css +1 -1
- package/dist/{studio-api-PTVN2GZ5.js → studio-api-MPH3F7Y5.js} +7 -7
- package/dist/{studioServer-55366NG4.js → studioServer-JD5KIYR6.js} +49 -42
- package/dist/{system-M44QRAAZ.js → system-JPG4ILMN.js} +5 -5
- package/dist/{telemetry-6GQL3BIP.js → telemetry-VP5MPNOI.js} +8 -8
- package/dist/{timeline-NMG3JG3V.js → timeline-TKJJ7RHM.js} +14 -14
- package/dist/{tokens-5LYIBBEF.js → tokens-DRCIONI6.js} +2 -2
- package/dist/{transcribe-4DGPFZTU.js → transcribe-7TASY37D.js} +11 -11
- package/dist/{transcribe-3SONDYLT.js → transcribe-ZOGMUKWL.js} +6 -6
- package/dist/{updateCheck-CXNND3CL.js → updateCheck-G5JNP5U5.js} +2 -2
- package/dist/{upgrade-RFTKDIVZ.js → upgrade-B2IT4JO4.js} +2 -2
- package/dist/{urlDownloader-VRZX26OK.js → urlDownloader-VQNIYP7Y.js} +4 -4
- package/dist/{validate-3BFHVVZH.js → validate-ENFIOU6R.js} +15 -15
- package/dist/{video-ECPRKRRP.js → video-MJBFMRFI.js} +5 -5
- package/package.json +1 -1
- 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 —
|
|
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
|
-
|
|
148
|
-
|
|
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:
|
|
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-
|
|
13
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
31
|
-
import "./chunk-
|
|
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-
|
|
35
|
-
import "./chunk-
|
|
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-
|
|
54
|
+
} from "./chunk-OJ3NJ54J.js";
|
|
55
55
|
import {
|
|
56
56
|
withMeta
|
|
57
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
13
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
18
|
+
import "./chunk-AZP4Q3HX.js";
|
|
19
19
|
import {
|
|
20
20
|
resolveProject
|
|
21
|
-
} from "./chunk-
|
|
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-
|
|
30
|
+
} from "./chunk-JD6UVTTT.js";
|
|
31
31
|
import "./chunk-5Z63TBTX.js";
|
|
32
|
-
import "./chunk-
|
|
33
|
-
import "./chunk-
|
|
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-
|
|
37
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-MKTOQKW4.js";
|
|
37
|
+
import "./chunk-BVC2TTOR.js";
|
|
38
38
|
import "./chunk-EOVYQ3IG.js";
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
39
|
+
import "./chunk-CML2M4A5.js";
|
|
40
|
+
import "./chunk-QV4PJ5EE.js";
|
|
41
41
|
import {
|
|
42
42
|
resolveLocalBrowserGpuMode
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-CYILDWZD.js";
|
|
44
44
|
import "./chunk-PFCFR3KZ.js";
|
|
45
|
-
import "./chunk-
|
|
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-
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-
|
|
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-
|
|
62
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
78
|
+
import "./chunk-T7KM6AG5.js";
|
|
79
79
|
import {
|
|
80
80
|
isClipVisibleAt,
|
|
81
81
|
isInClipWindow
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-ZGGEWKPA.js";
|
|
83
83
|
import "./chunk-F7MXHGU3.js";
|
|
84
84
|
import "./chunk-DPVXBVLL.js";
|
|
85
|
-
import "./chunk-
|
|
85
|
+
import "./chunk-QM7YQ35N.js";
|
|
86
86
|
import {
|
|
87
87
|
readElementRateSpec,
|
|
88
88
|
sourceTimeAt,
|
|
89
89
|
timeAtSourceTime
|
|
90
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
215
|
+
} from "./chunk-T7KM6AG5.js";
|
|
216
216
|
import {
|
|
217
217
|
MEDIA_VISUAL_STYLE_PROPERTIES,
|
|
218
218
|
quantizeTimeToFrame
|
|
219
|
-
} from "./chunk-
|
|
219
|
+
} from "./chunk-ZGGEWKPA.js";
|
|
220
220
|
import "./chunk-F7MXHGU3.js";
|
|
221
221
|
import "./chunk-DPVXBVLL.js";
|
|
222
|
-
import "./chunk-
|
|
223
|
-
import "./chunk-
|
|
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 {
|