hyperframes 0.7.93 → 0.7.96
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/cli.js +720 -66
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/studio/assets/{hyperframes-player-NSdcoOcK.js → hyperframes-player-CogOkBTX.js} +1 -1
- package/dist/studio/assets/{index-CCGnc_0M.js → index-DfZlc9RM.js} +1 -1
- package/dist/studio/assets/{index-wS6f7F5q.js → index-OMTw4iIl.js} +1 -1
- package/dist/studio/assets/{index-Dp1zVb9X.js → index-YO-rhwSW.js} +195 -195
- package/dist/studio/assets/index-tBPidglp.css +1 -0
- package/dist/studio/index.d.ts +27 -7
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +2648 -1838
- package/dist/studio/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/studio/assets/index-D78KEjgB.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ var VERSION;
|
|
|
50
50
|
var init_version = __esm({
|
|
51
51
|
"src/version.ts"() {
|
|
52
52
|
"use strict";
|
|
53
|
-
VERSION = true ? "0.7.
|
|
53
|
+
VERSION = true ? "0.7.96" : "0.0.0-dev";
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -479,6 +479,7 @@ var init_dist = __esm({
|
|
|
479
479
|
});
|
|
480
480
|
|
|
481
481
|
// src/telemetry/runId.ts
|
|
482
|
+
import { randomUUID } from "crypto";
|
|
482
483
|
function getRunId() {
|
|
483
484
|
if (!resolved) {
|
|
484
485
|
const value = process.env["HYPERFRAMES_RUN_ID"]?.trim().slice(0, 128);
|
|
@@ -487,7 +488,11 @@ function getRunId() {
|
|
|
487
488
|
}
|
|
488
489
|
return runId;
|
|
489
490
|
}
|
|
490
|
-
|
|
491
|
+
function getInvocationId() {
|
|
492
|
+
invocationId ??= randomUUID();
|
|
493
|
+
return invocationId;
|
|
494
|
+
}
|
|
495
|
+
var resolved, runId, invocationId;
|
|
491
496
|
var init_runId = __esm({
|
|
492
497
|
"src/telemetry/runId.ts"() {
|
|
493
498
|
"use strict";
|
|
@@ -62374,10 +62379,15 @@ function parseCanaryOverride(raw) {
|
|
|
62374
62379
|
function canaryFeatureKey(name) {
|
|
62375
62380
|
return `${CANARY_FEATURE_PREFIX}${name}`;
|
|
62376
62381
|
}
|
|
62382
|
+
function canaryReasonKey(name) {
|
|
62383
|
+
return `canary_reason_${name.replace(/[^A-Za-z0-9]+/g, "_")}`;
|
|
62384
|
+
}
|
|
62377
62385
|
function canaryFeatureProperties(entries2) {
|
|
62378
62386
|
const props = {};
|
|
62379
62387
|
for (const entry of entries2) {
|
|
62380
62388
|
props[canaryFeatureKey(entry.name)] = entry.enabled ? "true" : "false";
|
|
62389
|
+
if (entry.reason !== void 0)
|
|
62390
|
+
props[canaryReasonKey(entry.name)] = entry.reason;
|
|
62381
62391
|
}
|
|
62382
62392
|
return props;
|
|
62383
62393
|
}
|
|
@@ -62735,7 +62745,7 @@ var init_policy = __esm({
|
|
|
62735
62745
|
import { existsSync as existsSync2, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
62736
62746
|
import { join as join3 } from "path";
|
|
62737
62747
|
import { homedir } from "os";
|
|
62738
|
-
import { randomUUID } from "crypto";
|
|
62748
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
62739
62749
|
function salvageInstallState(parsed) {
|
|
62740
62750
|
const markerAt = typeof parsed.markerAt === "string" ? parsed.markerAt : void 0;
|
|
62741
62751
|
const bucketSeed = parseNonEmptyString(parsed.bucketSeed);
|
|
@@ -62765,9 +62775,10 @@ function warnSeedBackfillFailed(error) {
|
|
|
62765
62775
|
}
|
|
62766
62776
|
function backfillBucketSeed(config) {
|
|
62767
62777
|
const recorded = readInstallState();
|
|
62768
|
-
config.bucketSeed = (isInstallState(recorded) ? recorded.bucketSeed : void 0) ??
|
|
62778
|
+
config.bucketSeed = (isInstallState(recorded) ? recorded.bucketSeed : void 0) ?? randomUUID2();
|
|
62769
62779
|
const write = writeConfigWithResult(config);
|
|
62770
62780
|
if (!write.ok) warnSeedBackfillFailed(write.error);
|
|
62781
|
+
return write;
|
|
62771
62782
|
}
|
|
62772
62783
|
function installStateLatchedFired() {
|
|
62773
62784
|
if (latchedFiredSeen) return true;
|
|
@@ -62856,6 +62867,7 @@ function mintAndCacheConfig() {
|
|
|
62856
62867
|
const config = mintConfig();
|
|
62857
62868
|
const write = writeConfigWithResult(config);
|
|
62858
62869
|
if (!write.ok) warnSeedBackfillFailed(write.error);
|
|
62870
|
+
classifyIdentity(write.ok ? "unknown" : "process_only", writeOutcomeOf(write));
|
|
62859
62871
|
cachedConfig = { ...config };
|
|
62860
62872
|
return { ...config };
|
|
62861
62873
|
}
|
|
@@ -62864,7 +62876,7 @@ function mintConfig() {
|
|
|
62864
62876
|
const state = isInstallState(read) ? read : null;
|
|
62865
62877
|
return {
|
|
62866
62878
|
...DEFAULT_CONFIG,
|
|
62867
|
-
anonymousId:
|
|
62879
|
+
anonymousId: randomUUID2(),
|
|
62868
62880
|
// A corrupt record still means this machine had an install — reporting it
|
|
62869
62881
|
// as `false` would count a partial disk write as a brand-new machine and
|
|
62870
62882
|
// understate recoverable churn, which is the one thing this field exists
|
|
@@ -62875,7 +62887,7 @@ function mintConfig() {
|
|
|
62875
62887
|
// machine stays tripped for the new one, and the canary bucketing seed is
|
|
62876
62888
|
// inherited so cohorts hold across a config.json re-mint.
|
|
62877
62889
|
deParallelRouterTrialFired: state?.deParallelRouterTrialFired === true ? true : void 0,
|
|
62878
|
-
bucketSeed: state?.bucketSeed ??
|
|
62890
|
+
bucketSeed: state?.bucketSeed ?? randomUUID2()
|
|
62879
62891
|
};
|
|
62880
62892
|
}
|
|
62881
62893
|
function recordRecentRender(id, ok) {
|
|
@@ -62884,6 +62896,23 @@ function recordRecentRender(id, ok) {
|
|
|
62884
62896
|
config.recentRenders = ring.slice(-MAX_RECENT_RENDERS);
|
|
62885
62897
|
writeConfig(config);
|
|
62886
62898
|
}
|
|
62899
|
+
function classifyIdentity(persistence, outcome) {
|
|
62900
|
+
if (identityPersistence !== void 0) return;
|
|
62901
|
+
identityPersistence = persistence;
|
|
62902
|
+
identityWriteOutcome = outcome;
|
|
62903
|
+
}
|
|
62904
|
+
function writeOutcomeOf(write) {
|
|
62905
|
+
if (!write.ok) return "failed";
|
|
62906
|
+
return write.mirrored === false ? "ok_unmirrored" : "ok";
|
|
62907
|
+
}
|
|
62908
|
+
function getIdentityPersistence() {
|
|
62909
|
+
readConfig();
|
|
62910
|
+
return identityPersistence ?? "unknown";
|
|
62911
|
+
}
|
|
62912
|
+
function getIdentityWriteOutcome() {
|
|
62913
|
+
readConfig();
|
|
62914
|
+
return identityWriteOutcome;
|
|
62915
|
+
}
|
|
62887
62916
|
function parseNonEmptyString(value) {
|
|
62888
62917
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
62889
62918
|
}
|
|
@@ -62933,7 +62962,7 @@ function materializeConfig(parsed) {
|
|
|
62933
62962
|
return {
|
|
62934
62963
|
...passthroughFields(parsed),
|
|
62935
62964
|
telemetryEnabled: parsed.telemetryEnabled ?? DEFAULT_CONFIG.telemetryEnabled,
|
|
62936
|
-
anonymousId: parsed.anonymousId ||
|
|
62965
|
+
anonymousId: parsed.anonymousId || randomUUID2(),
|
|
62937
62966
|
telemetryNoticeShown: parsed.telemetryNoticeShown ?? DEFAULT_CONFIG.telemetryNoticeShown,
|
|
62938
62967
|
commandCount: parsed.commandCount ?? DEFAULT_CONFIG.commandCount,
|
|
62939
62968
|
renderSuccessCount: parsed.renderSuccessCount ?? DEFAULT_CONFIG.renderSuccessCount,
|
|
@@ -62949,16 +62978,21 @@ function readConfig() {
|
|
|
62949
62978
|
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
62950
62979
|
const parsed = JSON.parse(raw);
|
|
62951
62980
|
const config = materializeConfig(parsed);
|
|
62981
|
+
const idFromDisk = parseNonEmptyString(parsed.anonymousId) !== void 0;
|
|
62952
62982
|
if (config.bucketSeed === void 0) {
|
|
62953
|
-
backfillBucketSeed(config);
|
|
62983
|
+
const write = backfillBucketSeed(config);
|
|
62984
|
+
if (idFromDisk) classifyIdentity("durable");
|
|
62985
|
+
else classifyIdentity(write.ok ? "unknown" : "process_only", writeOutcomeOf(write));
|
|
62954
62986
|
cachedConfig = config;
|
|
62955
62987
|
return { ...config };
|
|
62956
62988
|
}
|
|
62989
|
+
classifyIdentity(idFromDisk ? "durable" : "process_only");
|
|
62957
62990
|
cachedConfig = config;
|
|
62958
62991
|
return { ...config };
|
|
62959
62992
|
} catch {
|
|
62960
62993
|
const config = { ...mintConfig(), telemetryEnabled: false };
|
|
62961
|
-
|
|
62994
|
+
const write = writeConfigWithResult(config);
|
|
62995
|
+
classifyIdentity(write.ok ? "unknown" : "process_only", writeOutcomeOf(write));
|
|
62962
62996
|
return config;
|
|
62963
62997
|
}
|
|
62964
62998
|
}
|
|
@@ -62988,7 +63022,7 @@ function incrementCommandCount() {
|
|
|
62988
63022
|
writeConfig(config);
|
|
62989
63023
|
return config.commandCount;
|
|
62990
63024
|
}
|
|
62991
|
-
var CONFIG_DIR, CONFIG_FILE, STATE_FILE, LEGACY_STATE_FILE, seedBackfillWarned, latchedFiredSeen, stateMarkerSynced, stateFiredSynced, MAX_RECENT_RENDERS, DEFAULT_CONFIG, cachedConfig, CONFIG_PATH, STATE_PATH;
|
|
63025
|
+
var CONFIG_DIR, CONFIG_FILE, STATE_FILE, LEGACY_STATE_FILE, seedBackfillWarned, latchedFiredSeen, stateMarkerSynced, stateFiredSynced, MAX_RECENT_RENDERS, DEFAULT_CONFIG, cachedConfig, identityPersistence, identityWriteOutcome, CONFIG_PATH, STATE_PATH;
|
|
62992
63026
|
var init_config = __esm({
|
|
62993
63027
|
"src/telemetry/config.ts"() {
|
|
62994
63028
|
"use strict";
|
|
@@ -70836,7 +70870,7 @@ import {
|
|
|
70836
70870
|
statSync as statSync4,
|
|
70837
70871
|
unlinkSync
|
|
70838
70872
|
} from "fs";
|
|
70839
|
-
import { createHash, randomUUID as
|
|
70873
|
+
import { createHash, randomUUID as randomUUID3 } from "crypto";
|
|
70840
70874
|
import { BlockList, isIP } from "net";
|
|
70841
70875
|
import { dirname as dirname6, extname as extname2, join as join9 } from "path";
|
|
70842
70876
|
import { Readable, Transform } from "stream";
|
|
@@ -71004,7 +71038,7 @@ async function acquireCachePathLock(localPath, timeoutMs, signal) {
|
|
|
71004
71038
|
if (error.code !== "EEXIST") throw error;
|
|
71005
71039
|
}
|
|
71006
71040
|
if (createdLock) {
|
|
71007
|
-
const owner = `${CACHE_LOCK_OWNER_PREFIX}${
|
|
71041
|
+
const owner = `${CACHE_LOCK_OWNER_PREFIX}${randomUUID3()}`;
|
|
71008
71042
|
try {
|
|
71009
71043
|
mkdirSync5(join9(lockPath, owner));
|
|
71010
71044
|
const entries2 = readdirSync3(lockPath);
|
|
@@ -84955,7 +84989,7 @@ var init_htmlTemplate = __esm({
|
|
|
84955
84989
|
});
|
|
84956
84990
|
|
|
84957
84991
|
// ../engine/src/services/extractionCache.ts
|
|
84958
|
-
import { createHash as createHash2, randomUUID as
|
|
84992
|
+
import { createHash as createHash2, randomUUID as randomUUID4 } from "crypto";
|
|
84959
84993
|
import {
|
|
84960
84994
|
existsSync as existsSync13,
|
|
84961
84995
|
lstatSync as lstatSync2,
|
|
@@ -85003,7 +85037,7 @@ function lookupCacheEntry(rootDir, input2) {
|
|
|
85003
85037
|
return { entry: { dir, keyHash }, hit: complete };
|
|
85004
85038
|
}
|
|
85005
85039
|
function partialCacheEntryDir(entry) {
|
|
85006
|
-
return `${entry.dir}.partial-${process.pid}-${
|
|
85040
|
+
return `${entry.dir}.partial-${process.pid}-${randomUUID4().slice(0, 8)}`;
|
|
85007
85041
|
}
|
|
85008
85042
|
function isTargetExistsRenameError(err) {
|
|
85009
85043
|
const code = err.code;
|
|
@@ -90728,7 +90762,10 @@ function canaryDecisionsForStudio() {
|
|
|
90728
90762
|
}
|
|
90729
90763
|
function canaryEventProperties() {
|
|
90730
90764
|
return canaryFeatureProperties(
|
|
90731
|
-
CANARIES.map((c3) =>
|
|
90765
|
+
CANARIES.map((c3) => {
|
|
90766
|
+
const { enabled, reason } = resolveCanary(c3.name);
|
|
90767
|
+
return { name: c3.name, enabled, reason };
|
|
90768
|
+
})
|
|
90732
90769
|
);
|
|
90733
90770
|
}
|
|
90734
90771
|
var decisions, decisionsTelemetryPosture;
|
|
@@ -90746,10 +90783,10 @@ var init_canary2 = __esm({
|
|
|
90746
90783
|
|
|
90747
90784
|
// src/telemetry/transport.ts
|
|
90748
90785
|
import { spawn as spawn5 } from "child_process";
|
|
90749
|
-
import { randomUUID as
|
|
90786
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
90750
90787
|
function enqueue(event, properties, distinctId) {
|
|
90751
90788
|
eventQueue.push({
|
|
90752
|
-
uuid:
|
|
90789
|
+
uuid: randomUUID5(),
|
|
90753
90790
|
event,
|
|
90754
90791
|
distinctId,
|
|
90755
90792
|
properties,
|
|
@@ -90867,6 +90904,19 @@ function trackEvent(event, properties = {}, distinctId) {
|
|
|
90867
90904
|
// could not read. Without it a partial disk write is indistinguishable
|
|
90868
90905
|
// from a genuinely fresh install. Absent in the normal case.
|
|
90869
90906
|
install_state_file_corrupt: readConfig().stateFileCorrupt,
|
|
90907
|
+
// Whether this process's anonymousId can be trusted to survive to the
|
|
90908
|
+
// next run: `durable` (loaded from a preexisting config), `unknown`
|
|
90909
|
+
// (minted+persisted this run — an ephemeral HOME is indistinguishable
|
|
90910
|
+
// from a genuine first run), `process_only` (persist failed). Install-
|
|
90911
|
+
// grain metrics should count only durable identities; the identity-
|
|
90912
|
+
// churn workloads (fresh id per run) are never durable.
|
|
90913
|
+
identity_persistence: getIdentityPersistence(),
|
|
90914
|
+
// Outcome of the identity-establishing config write; absent when the
|
|
90915
|
+
// identity came from disk and nothing needed writing.
|
|
90916
|
+
config_write_outcome: getIdentityWriteOutcome(),
|
|
90917
|
+
// Groups one invocation's events even when the install identity is
|
|
90918
|
+
// untrustworthy. Always present, unlike the orchestrator-set run_id.
|
|
90919
|
+
invocation_id: getInvocationId(),
|
|
90870
90920
|
// Canary assignments as `$feature/canary-<name>` — PostHog's native flag
|
|
90871
90921
|
// property shape, so breakdowns and experiment analysis work on a canary
|
|
90872
90922
|
// with nothing configured server-side. On EVERY event, not just renders:
|
|
@@ -90901,6 +90951,7 @@ var init_client = __esm({
|
|
|
90901
90951
|
"src/telemetry/client.ts"() {
|
|
90902
90952
|
"use strict";
|
|
90903
90953
|
init_config();
|
|
90954
|
+
init_runId();
|
|
90904
90955
|
init_version();
|
|
90905
90956
|
init_colors();
|
|
90906
90957
|
init_diagnostics2();
|
|
@@ -94501,7 +94552,7 @@ import { execFileSync as execFileSync5 } from "child_process";
|
|
|
94501
94552
|
import { existsSync as existsSync25, readFileSync as readFileSync14, mkdirSync as mkdirSync12, unlinkSync as unlinkSync3 } from "fs";
|
|
94502
94553
|
import { join as join21, extname as extname5 } from "path";
|
|
94503
94554
|
import { tmpdir as tmpdir3 } from "os";
|
|
94504
|
-
import { randomUUID as
|
|
94555
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
94505
94556
|
function detectLanguage(whisperPath, modelPath2, wavPath) {
|
|
94506
94557
|
try {
|
|
94507
94558
|
const output = execFileSync5(whisperPath, ["--model", modelPath2, "--detect-language", wavPath], {
|
|
@@ -94643,7 +94694,7 @@ function isVideoFile(filePath) {
|
|
|
94643
94694
|
return VIDEO_EXTENSIONS.has(extname5(filePath).toLowerCase());
|
|
94644
94695
|
}
|
|
94645
94696
|
function tempWavPath() {
|
|
94646
|
-
return join21(tmpdir3(), `hyperframes-audio-${process.pid}-${
|
|
94697
|
+
return join21(tmpdir3(), `hyperframes-audio-${process.pid}-${randomUUID6()}.wav`);
|
|
94647
94698
|
}
|
|
94648
94699
|
function extractAudio(videoPath) {
|
|
94649
94700
|
const ffmpegPath = findFFmpeg();
|
|
@@ -99246,7 +99297,7 @@ var init_chunk_6H3V3WGJ = __esm({
|
|
|
99246
99297
|
|
|
99247
99298
|
// ../studio-server/dist/chunk-ZPI6QXJH.js
|
|
99248
99299
|
import { spawn as spawn8 } from "child_process";
|
|
99249
|
-
import { createHash as createHash6, randomUUID as
|
|
99300
|
+
import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
|
|
99250
99301
|
import {
|
|
99251
99302
|
existsSync as existsSync210,
|
|
99252
99303
|
mkdirSync as mkdirSync15,
|
|
@@ -99570,7 +99621,7 @@ async function transcodeToCache(absoluteSourcePath, cachePath2, variant) {
|
|
|
99570
99621
|
if (existsSync210(cachePath2)) return cachePath2;
|
|
99571
99622
|
const cacheDir = dirname14(cachePath2);
|
|
99572
99623
|
mkdirSync15(cacheDir, { recursive: true });
|
|
99573
|
-
const tempPath = join29(cacheDir, `.tmp-${
|
|
99624
|
+
const tempPath = join29(cacheDir, `.tmp-${randomUUID7()}-${basename4(cachePath2)}`);
|
|
99574
99625
|
try {
|
|
99575
99626
|
await runFfmpeg2(absoluteSourcePath, tempPath, variant);
|
|
99576
99627
|
renameSync6(tempPath, cachePath2);
|
|
@@ -106487,7 +106538,7 @@ import { basename as basename5, join as join42 } from "path";
|
|
|
106487
106538
|
import { mkdirSync as mkdirSync22, readdirSync as readdirSync32, readFileSync as readFileSync32, unlinkSync as unlinkSync5, writeFileSync as writeFileSync32 } from "fs";
|
|
106488
106539
|
import { Buffer as Buffer2 } from "buffer";
|
|
106489
106540
|
import { join as join52, relative as relative22 } from "path";
|
|
106490
|
-
import { createHash as createHash22, randomUUID as
|
|
106541
|
+
import { createHash as createHash22, randomUUID as randomUUID8 } from "crypto";
|
|
106491
106542
|
import { existsSync as existsSync37, readFileSync as readFileSync42, realpathSync as realpathSync6 } from "fs";
|
|
106492
106543
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
106493
106544
|
import { dirname as dirname15, relative as relative32, resolve as resolve24, sep as sep7 } from "path";
|
|
@@ -106511,9 +106562,19 @@ import { join as join92 } from "path";
|
|
|
106511
106562
|
import { streamSSE } from "hono/streaming";
|
|
106512
106563
|
import { existsSync as existsSync72, readFileSync as readFileSync102, mkdirSync as mkdirSync42, unlinkSync as unlinkSync32, readdirSync as readdirSync52, statSync as statSync32 } from "fs";
|
|
106513
106564
|
import { join as join102 } from "path";
|
|
106514
|
-
import {
|
|
106565
|
+
import {
|
|
106566
|
+
existsSync as existsSync82,
|
|
106567
|
+
mkdirSync as mkdirSync52,
|
|
106568
|
+
readFileSync as readFileSync112,
|
|
106569
|
+
readdirSync as readdirSync62,
|
|
106570
|
+
renameSync as renameSync22,
|
|
106571
|
+
rmSync as rmSync32,
|
|
106572
|
+
statSync as statSync42,
|
|
106573
|
+
unlinkSync as unlinkSync42,
|
|
106574
|
+
writeFileSync as writeFileSync62
|
|
106575
|
+
} from "fs";
|
|
106515
106576
|
import { join as join112 } from "path";
|
|
106516
|
-
import { createHash as createHash42 } from "crypto";
|
|
106577
|
+
import { createHash as createHash42, randomUUID as randomUUID32 } from "crypto";
|
|
106517
106578
|
import { existsSync as existsSync92, readFileSync as readFileSync122, writeFileSync as writeFileSync72, mkdirSync as mkdirSync62 } from "fs";
|
|
106518
106579
|
import { join as join122 } from "path";
|
|
106519
106580
|
import { closeSync as closeSync32, constants as constants22, fstatSync as fstatSync2, openSync as openSync32, readSync } from "fs";
|
|
@@ -106940,7 +107001,7 @@ function fileContentVersion(content) {
|
|
|
106940
107001
|
}
|
|
106941
107002
|
function createWriteToken(requestToken) {
|
|
106942
107003
|
const token = requestToken?.trim();
|
|
106943
|
-
return token && token.length <= 200 ? token :
|
|
107004
|
+
return token && token.length <= 200 ? token : randomUUID8();
|
|
106944
107005
|
}
|
|
106945
107006
|
function recordFileWriteReceipt(absPath, receipt) {
|
|
106946
107007
|
const now = Date.now();
|
|
@@ -110026,6 +110087,46 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
110026
110087
|
return c3.json({ renders: files });
|
|
110027
110088
|
});
|
|
110028
110089
|
}
|
|
110090
|
+
function pruneThumbnailCache(cacheDir, protectedPaths, now = Date.now()) {
|
|
110091
|
+
if (!existsSync82(cacheDir)) return;
|
|
110092
|
+
const files = readdirSync62(cacheDir, { withFileTypes: true }).flatMap((entry) => {
|
|
110093
|
+
if (!entry.isFile()) return [];
|
|
110094
|
+
const path2 = join112(cacheDir, entry.name);
|
|
110095
|
+
try {
|
|
110096
|
+
const stats = statSync42(path2);
|
|
110097
|
+
return [{ path: path2, bytes: stats.size, mtimeMs: stats.mtimeMs }];
|
|
110098
|
+
} catch {
|
|
110099
|
+
return [];
|
|
110100
|
+
}
|
|
110101
|
+
});
|
|
110102
|
+
const retained = [];
|
|
110103
|
+
for (const file of files) {
|
|
110104
|
+
if (!protectedPaths.has(file.path) && now - file.mtimeMs > THUMBNAIL_CACHE_MAX_AGE_MS) {
|
|
110105
|
+
rmSync32(file.path, { force: true });
|
|
110106
|
+
} else {
|
|
110107
|
+
retained.push(file);
|
|
110108
|
+
}
|
|
110109
|
+
}
|
|
110110
|
+
let bytes = retained.reduce((total, file) => total + file.bytes, 0);
|
|
110111
|
+
for (const file of retained.sort((left, right) => left.mtimeMs - right.mtimeMs)) {
|
|
110112
|
+
if (bytes <= THUMBNAIL_CACHE_MAX_BYTES) break;
|
|
110113
|
+
if (protectedPaths.has(file.path)) continue;
|
|
110114
|
+
try {
|
|
110115
|
+
unlinkSync42(file.path);
|
|
110116
|
+
bytes -= file.bytes;
|
|
110117
|
+
} catch {
|
|
110118
|
+
}
|
|
110119
|
+
}
|
|
110120
|
+
}
|
|
110121
|
+
function writeThumbnailAtomically(path2, buffer) {
|
|
110122
|
+
const temporaryPath = `${path2}.${process.pid}.${randomUUID32()}.tmp`;
|
|
110123
|
+
try {
|
|
110124
|
+
writeFileSync62(temporaryPath, buffer, { flag: "wx" });
|
|
110125
|
+
renameSync22(temporaryPath, path2);
|
|
110126
|
+
} finally {
|
|
110127
|
+
rmSync32(temporaryPath, { force: true });
|
|
110128
|
+
}
|
|
110129
|
+
}
|
|
110029
110130
|
function registerThumbnailRoutes(api, adapter2) {
|
|
110030
110131
|
api.get("/projects/:id/thumbnail/*", async (c3) => {
|
|
110031
110132
|
if (!adapter2.generateThumbnail) {
|
|
@@ -110046,6 +110147,8 @@ function registerThumbnailRoutes(api, adapter2) {
|
|
|
110046
110147
|
const selector = url.searchParams.get("selector") || void 0;
|
|
110047
110148
|
const format = url.searchParams.get("format") === "png" ? "png" : "jpeg";
|
|
110048
110149
|
const contentType = format === "png" ? "image/png" : "image/jpeg";
|
|
110150
|
+
const requestedOutput = url.searchParams.get("output");
|
|
110151
|
+
const outputMode = requestedOutput === "source" || requestedOutput !== "preview" && format === "png" ? "source" : "preview";
|
|
110049
110152
|
const rawSelectorIndex = Number.parseInt(url.searchParams.get("selectorIndex") || "0", 10);
|
|
110050
110153
|
const selectorIndex = Number.isFinite(rawSelectorIndex) && rawSelectorIndex > 0 ? rawSelectorIndex : void 0;
|
|
110051
110154
|
const urlVersion = url.searchParams.get("v") || "";
|
|
@@ -110083,37 +110186,62 @@ function registerThumbnailRoutes(api, adapter2) {
|
|
|
110083
110186
|
const cacheDir = join112(project.dir, ".thumbnails");
|
|
110084
110187
|
const selectorKey = selector ? `_${selector.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 80)}_${selectorIndex ?? 0}` : "";
|
|
110085
110188
|
const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
|
|
110086
|
-
const
|
|
110189
|
+
const outputScale = outputMode === "source" ? 1 : Math.min(1, THUMBNAIL_MAX_OUTPUT_WIDTH / compW, THUMBNAIL_MAX_OUTPUT_HEIGHT / compH);
|
|
110190
|
+
const outputWidth = Math.max(1, Math.round(compW * outputScale));
|
|
110191
|
+
const outputHeight = Math.max(1, Math.round(compH * outputScale));
|
|
110192
|
+
const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}${manualEditsKey}${motionKey}${sourceKey}_${format}_${outputMode}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${outputWidth}x${outputHeight}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.${format === "png" ? "png" : "jpg"}`;
|
|
110087
110193
|
const cachePath2 = join112(cacheDir, cacheKey);
|
|
110194
|
+
if (!prunedCacheDirs.has(cacheDir)) {
|
|
110195
|
+
prunedCacheDirs.add(cacheDir);
|
|
110196
|
+
pruneThumbnailCache(
|
|
110197
|
+
cacheDir,
|
|
110198
|
+
/* @__PURE__ */ new Set([...thumbnailGenerationCoordinator.protectedKeys(), cachePath2])
|
|
110199
|
+
);
|
|
110200
|
+
}
|
|
110088
110201
|
if (existsSync82(cachePath2)) {
|
|
110089
110202
|
return new Response(new Uint8Array(readFileSync112(cachePath2)), {
|
|
110090
110203
|
headers: { "Content-Type": contentType, "Cache-Control": "no-cache" }
|
|
110091
110204
|
});
|
|
110092
110205
|
}
|
|
110093
110206
|
try {
|
|
110094
|
-
const buffer = await
|
|
110095
|
-
|
|
110096
|
-
|
|
110097
|
-
|
|
110098
|
-
|
|
110099
|
-
|
|
110100
|
-
|
|
110101
|
-
|
|
110102
|
-
|
|
110103
|
-
|
|
110104
|
-
|
|
110207
|
+
const buffer = await thumbnailGenerationCoordinator.acquire(
|
|
110208
|
+
cachePath2,
|
|
110209
|
+
c3.req.raw.signal,
|
|
110210
|
+
async (signal) => {
|
|
110211
|
+
const generated = await adapter2.generateThumbnail({
|
|
110212
|
+
project,
|
|
110213
|
+
compPath,
|
|
110214
|
+
seekTime,
|
|
110215
|
+
width: compW,
|
|
110216
|
+
height: compH,
|
|
110217
|
+
outputWidth,
|
|
110218
|
+
outputHeight,
|
|
110219
|
+
previewUrl,
|
|
110220
|
+
selector,
|
|
110221
|
+
format,
|
|
110222
|
+
selectorIndex,
|
|
110223
|
+
signal
|
|
110224
|
+
});
|
|
110225
|
+
if (!generated) return null;
|
|
110226
|
+
if (!existsSync82(cacheDir)) mkdirSync52(cacheDir, { recursive: true });
|
|
110227
|
+
writeThumbnailAtomically(cachePath2, generated);
|
|
110228
|
+
return generated;
|
|
110229
|
+
}
|
|
110230
|
+
);
|
|
110105
110231
|
if (!buffer) {
|
|
110106
110232
|
return c3.json(
|
|
110107
110233
|
{ error: "Thumbnail generation failed \u2014 Chrome browser may not be available" },
|
|
110108
110234
|
500
|
|
110109
110235
|
);
|
|
110110
110236
|
}
|
|
110111
|
-
|
|
110112
|
-
writeFileSync62(cachePath2, buffer);
|
|
110237
|
+
pruneThumbnailCache(cacheDir, thumbnailGenerationCoordinator.protectedKeys());
|
|
110113
110238
|
return new Response(new Uint8Array(buffer), {
|
|
110114
110239
|
headers: { "Content-Type": contentType, "Cache-Control": "no-cache" }
|
|
110115
110240
|
});
|
|
110116
110241
|
} catch (err) {
|
|
110242
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
110243
|
+
return new Response(null, { status: 499 });
|
|
110244
|
+
}
|
|
110117
110245
|
const msg = err instanceof Error ? err.message : String(err);
|
|
110118
110246
|
return c3.json({ error: `Thumbnail generation failed: ${msg}` }, 500);
|
|
110119
110247
|
}
|
|
@@ -110592,6 +110720,18 @@ function createStudioApi(adapter2) {
|
|
|
110592
110720
|
registerGlobalAssetRoutes(api);
|
|
110593
110721
|
return api;
|
|
110594
110722
|
}
|
|
110723
|
+
function thumbnailDeviceScaleFactor({
|
|
110724
|
+
width,
|
|
110725
|
+
height,
|
|
110726
|
+
outputWidth,
|
|
110727
|
+
outputHeight
|
|
110728
|
+
}) {
|
|
110729
|
+
const dimensions = [width, height, outputWidth, outputHeight];
|
|
110730
|
+
if (dimensions.some((value) => !Number.isFinite(value) || value <= 0)) {
|
|
110731
|
+
throw new RangeError("Thumbnail dimensions must be positive finite numbers");
|
|
110732
|
+
}
|
|
110733
|
+
return Math.min(1, outputWidth / width, outputHeight / height);
|
|
110734
|
+
}
|
|
110595
110735
|
function createBackgroundRemovalJob(opts, render3) {
|
|
110596
110736
|
const state = {
|
|
110597
110737
|
id: opts.jobId,
|
|
@@ -110644,7 +110784,7 @@ function updateBackgroundRemovalProgress(state, event) {
|
|
|
110644
110784
|
state.framesProcessed = event.index;
|
|
110645
110785
|
state.avgMsPerFrame = event.avgMsPerFrame;
|
|
110646
110786
|
}
|
|
110647
|
-
var IGNORE_DIRS, SIGNATURE_TEXT_EXTENSIONS, SIGNATURE_EXCLUDED_DIRS, MAX_SIGNATURE_TEXT_BYTES, STUDIO_SIGNATURE_MANIFEST_PATHS, projectSignatureCache, COMPOSITION_ID_RE, MIME_TYPES2, SAMPLE_RATE, PEAK_COUNT, WAVEFORM_CACHE_VERSION, VIDEO_EXT2, AUDIO_EXT2, DEFAULT_KEEP_PER_FILE, RECEIPT_TTL_MS, receipts, CompositionInsertionError, differential, behavioral, GSAP_MUTATION_CAPABILITIES, GSAP_WRITER_MIGRATION, atomicCutTail, HOLD_SYNC_MUTATION_TYPES, REGEXP_SPECIALS, NON_RENDERED_TAGS, VARIABLES_PAYLOAD_ERROR, PROJECT_SIGNATURE_META, GSAP_CDN_VERSION, GSAP_CDN_SCRIPT, GSAP_CUSTOM_EASE_CDN_SCRIPT, GSAP_MOTION_PATH_CDN_SCRIPT, GSAP_CDN_FALLBACK_SCRIPT, VALID_RESOLUTIONS, THUMBNAIL_CACHE_VERSION, MAX_FONT_RESULTS, GOOGLE_FONTS_METADATA_URL, GOOGLE_FONTS_FETCH_TIMEOUT_MS, cachedFonts, cachedGoogleFonts, GOOGLE_FONT_FALLBACKS, VIDEO_EXTENSIONS2, IMAGE_EXTENSIONS, VIDEO_OUTPUT_EXTENSIONS, QUALITIES, DEVICES;
|
|
110787
|
+
var IGNORE_DIRS, SIGNATURE_TEXT_EXTENSIONS, SIGNATURE_EXCLUDED_DIRS, MAX_SIGNATURE_TEXT_BYTES, STUDIO_SIGNATURE_MANIFEST_PATHS, projectSignatureCache, COMPOSITION_ID_RE, MIME_TYPES2, SAMPLE_RATE, PEAK_COUNT, WAVEFORM_CACHE_VERSION, VIDEO_EXT2, AUDIO_EXT2, DEFAULT_KEEP_PER_FILE, RECEIPT_TTL_MS, receipts, CompositionInsertionError, differential, behavioral, GSAP_MUTATION_CAPABILITIES, GSAP_WRITER_MIGRATION, atomicCutTail, HOLD_SYNC_MUTATION_TYPES, REGEXP_SPECIALS, NON_RENDERED_TAGS, VARIABLES_PAYLOAD_ERROR, PROJECT_SIGNATURE_META, GSAP_CDN_VERSION, GSAP_CDN_SCRIPT, GSAP_CUSTOM_EASE_CDN_SCRIPT, GSAP_MOTION_PATH_CDN_SCRIPT, GSAP_CDN_FALLBACK_SCRIPT, VALID_RESOLUTIONS, ThumbnailGenerationCoordinator, thumbnailGenerationCoordinator, THUMBNAIL_CACHE_VERSION, THUMBNAIL_MAX_OUTPUT_WIDTH, THUMBNAIL_MAX_OUTPUT_HEIGHT, THUMBNAIL_CACHE_MAX_BYTES, THUMBNAIL_CACHE_MAX_AGE_MS, prunedCacheDirs, MAX_FONT_RESULTS, GOOGLE_FONTS_METADATA_URL, GOOGLE_FONTS_FETCH_TIMEOUT_MS, cachedFonts, cachedGoogleFonts, GOOGLE_FONT_FALLBACKS, VIDEO_EXTENSIONS2, IMAGE_EXTENSIONS, VIDEO_OUTPUT_EXTENSIONS, QUALITIES, DEVICES;
|
|
110648
110788
|
var init_dist9 = __esm({
|
|
110649
110789
|
"../studio-server/dist/index.js"() {
|
|
110650
110790
|
"use strict";
|
|
@@ -110885,7 +111025,113 @@ var init_dist9 = __esm({
|
|
|
110885
111025
|
})();
|
|
110886
111026
|
</script>`;
|
|
110887
111027
|
VALID_RESOLUTIONS = new Set(VALID_CANVAS_RESOLUTIONS);
|
|
111028
|
+
ThumbnailGenerationCoordinator = class {
|
|
111029
|
+
constructor(concurrency = 1) {
|
|
111030
|
+
this.concurrency = concurrency;
|
|
111031
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
111032
|
+
throw new RangeError("Thumbnail concurrency must be a positive integer");
|
|
111033
|
+
}
|
|
111034
|
+
}
|
|
111035
|
+
concurrency;
|
|
111036
|
+
entries = /* @__PURE__ */ new Map();
|
|
111037
|
+
queue = [];
|
|
111038
|
+
activeEntries = /* @__PURE__ */ new Set();
|
|
111039
|
+
active = 0;
|
|
111040
|
+
acquire(key2, signal, work) {
|
|
111041
|
+
if (signal.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
111042
|
+
let entry = this.entries.get(key2);
|
|
111043
|
+
if (!entry) {
|
|
111044
|
+
let resolve510;
|
|
111045
|
+
let reject;
|
|
111046
|
+
const promise = new Promise((resolvePromise, rejectPromise) => {
|
|
111047
|
+
resolve510 = resolvePromise;
|
|
111048
|
+
reject = rejectPromise;
|
|
111049
|
+
});
|
|
111050
|
+
entry = {
|
|
111051
|
+
key: key2,
|
|
111052
|
+
controller: new AbortController(),
|
|
111053
|
+
leases: 0,
|
|
111054
|
+
state: "queued",
|
|
111055
|
+
work,
|
|
111056
|
+
promise,
|
|
111057
|
+
resolve: resolve510,
|
|
111058
|
+
reject
|
|
111059
|
+
};
|
|
111060
|
+
this.entries.set(key2, entry);
|
|
111061
|
+
this.queue.push(entry);
|
|
111062
|
+
}
|
|
111063
|
+
entry.leases++;
|
|
111064
|
+
this.pump();
|
|
111065
|
+
return this.lease(entry, signal);
|
|
111066
|
+
}
|
|
111067
|
+
protectedKeys() {
|
|
111068
|
+
return /* @__PURE__ */ new Set([...this.entries.keys(), ...[...this.activeEntries].map((entry) => entry.key)]);
|
|
111069
|
+
}
|
|
111070
|
+
lease(entry, signal) {
|
|
111071
|
+
return new Promise((resolve510, reject) => {
|
|
111072
|
+
let released = false;
|
|
111073
|
+
const release4 = () => {
|
|
111074
|
+
if (released) return;
|
|
111075
|
+
released = true;
|
|
111076
|
+
signal.removeEventListener("abort", onAbort);
|
|
111077
|
+
entry.leases--;
|
|
111078
|
+
if (entry.leases > 0 || !this.entries.has(entry.key)) return;
|
|
111079
|
+
entry.controller.abort();
|
|
111080
|
+
if (this.entries.get(entry.key) === entry) this.entries.delete(entry.key);
|
|
111081
|
+
if (entry.state === "queued") {
|
|
111082
|
+
const index = this.queue.indexOf(entry);
|
|
111083
|
+
if (index >= 0) this.queue.splice(index, 1);
|
|
111084
|
+
entry.reject(new DOMException("Aborted", "AbortError"));
|
|
111085
|
+
}
|
|
111086
|
+
};
|
|
111087
|
+
const onAbort = () => {
|
|
111088
|
+
release4();
|
|
111089
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
111090
|
+
};
|
|
111091
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
111092
|
+
entry.promise.then(
|
|
111093
|
+
(value) => {
|
|
111094
|
+
release4();
|
|
111095
|
+
resolve510(value);
|
|
111096
|
+
},
|
|
111097
|
+
(reason) => {
|
|
111098
|
+
release4();
|
|
111099
|
+
reject(reason);
|
|
111100
|
+
}
|
|
111101
|
+
);
|
|
111102
|
+
});
|
|
111103
|
+
}
|
|
111104
|
+
pump() {
|
|
111105
|
+
while (this.active < this.concurrency) {
|
|
111106
|
+
const entry = this.queue.shift();
|
|
111107
|
+
if (!entry) return;
|
|
111108
|
+
if (entry.leases === 0) continue;
|
|
111109
|
+
entry.state = "active";
|
|
111110
|
+
this.activeEntries.add(entry);
|
|
111111
|
+
this.active++;
|
|
111112
|
+
void this.run(entry);
|
|
111113
|
+
}
|
|
111114
|
+
}
|
|
111115
|
+
async run(entry) {
|
|
111116
|
+
try {
|
|
111117
|
+
entry.resolve(await entry.work(entry.controller.signal));
|
|
111118
|
+
} catch (error) {
|
|
111119
|
+
entry.reject(error);
|
|
111120
|
+
} finally {
|
|
111121
|
+
this.active--;
|
|
111122
|
+
this.activeEntries.delete(entry);
|
|
111123
|
+
if (this.entries.get(entry.key) === entry) this.entries.delete(entry.key);
|
|
111124
|
+
this.pump();
|
|
111125
|
+
}
|
|
111126
|
+
}
|
|
111127
|
+
};
|
|
111128
|
+
thumbnailGenerationCoordinator = new ThumbnailGenerationCoordinator(1);
|
|
110888
111129
|
THUMBNAIL_CACHE_VERSION = "v4";
|
|
111130
|
+
THUMBNAIL_MAX_OUTPUT_WIDTH = 240;
|
|
111131
|
+
THUMBNAIL_MAX_OUTPUT_HEIGHT = 135;
|
|
111132
|
+
THUMBNAIL_CACHE_MAX_BYTES = 512 * 1024 * 1024;
|
|
111133
|
+
THUMBNAIL_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
111134
|
+
prunedCacheDirs = /* @__PURE__ */ new Set();
|
|
110889
111135
|
MAX_FONT_RESULTS = 2e3;
|
|
110890
111136
|
GOOGLE_FONTS_METADATA_URL = "https://fonts.google.com/metadata/fonts";
|
|
110891
111137
|
GOOGLE_FONTS_FETCH_TIMEOUT_MS = 3e3;
|
|
@@ -124868,7 +125114,7 @@ import {
|
|
|
124868
125114
|
import { tmpdir as tmpdir8 } from "os";
|
|
124869
125115
|
import { join as join60, dirname as dirname25, resolve as resolve33 } from "path";
|
|
124870
125116
|
import { totalmem as totalmem2 } from "os";
|
|
124871
|
-
import { randomUUID as
|
|
125117
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
124872
125118
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
124873
125119
|
function sampleDirectoryBytes(dir) {
|
|
124874
125120
|
let total = 0;
|
|
@@ -125227,7 +125473,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
|
|
|
125227
125473
|
}
|
|
125228
125474
|
function createRenderJob(config) {
|
|
125229
125475
|
return {
|
|
125230
|
-
id:
|
|
125476
|
+
id: randomUUID9(),
|
|
125231
125477
|
config: {
|
|
125232
125478
|
...config,
|
|
125233
125479
|
fps: toFps(config.fps),
|
|
@@ -132359,9 +132605,19 @@ function createStudioServer(options) {
|
|
|
132359
132605
|
);
|
|
132360
132606
|
}
|
|
132361
132607
|
let page = null;
|
|
132608
|
+
const closePage = () => void page?.close().catch(() => {
|
|
132609
|
+
});
|
|
132610
|
+
opts.signal.addEventListener("abort", closePage, { once: true });
|
|
132362
132611
|
try {
|
|
132363
132612
|
page = await session.browser.newPage();
|
|
132364
|
-
|
|
132613
|
+
if (opts.signal.aborted) return null;
|
|
132614
|
+
const width = opts.width || 1920;
|
|
132615
|
+
const height = opts.height || 1080;
|
|
132616
|
+
await page.setViewport({
|
|
132617
|
+
width,
|
|
132618
|
+
height,
|
|
132619
|
+
deviceScaleFactor: thumbnailDeviceScaleFactor(opts)
|
|
132620
|
+
});
|
|
132365
132621
|
await page.goto(opts.previewUrl, { waitUntil: "domcontentloaded", timeout: 1e4 });
|
|
132366
132622
|
await page.waitForFunction(
|
|
132367
132623
|
() => {
|
|
@@ -132404,12 +132660,15 @@ function createStudioServer(options) {
|
|
|
132404
132660
|
);
|
|
132405
132661
|
return screenshot;
|
|
132406
132662
|
} catch (err) {
|
|
132407
|
-
|
|
132408
|
-
|
|
132409
|
-
|
|
132410
|
-
|
|
132663
|
+
if (!opts.signal.aborted) {
|
|
132664
|
+
console.warn(
|
|
132665
|
+
"[Studio] Thumbnail generation failed:",
|
|
132666
|
+
err instanceof Error ? err.message : err
|
|
132667
|
+
);
|
|
132668
|
+
}
|
|
132411
132669
|
return null;
|
|
132412
132670
|
} finally {
|
|
132671
|
+
opts.signal.removeEventListener("abort", closePage);
|
|
132413
132672
|
await page?.close().catch(() => {
|
|
132414
132673
|
});
|
|
132415
132674
|
}
|
|
@@ -135057,6 +135316,7 @@ __export(studio_api_exports, {
|
|
|
135057
135316
|
getElementScreenshotClip: () => getElementScreenshotClip,
|
|
135058
135317
|
getMimeType: () => getMimeType,
|
|
135059
135318
|
isSafePath: () => isSafePath,
|
|
135319
|
+
thumbnailDeviceScaleFactor: () => thumbnailDeviceScaleFactor,
|
|
135060
135320
|
walkDir: () => walkDir
|
|
135061
135321
|
});
|
|
135062
135322
|
var init_studio_api = __esm({
|
|
@@ -135598,7 +135858,7 @@ var init_present = __esm({
|
|
|
135598
135858
|
function isAuthError(err) {
|
|
135599
135859
|
return err instanceof AuthError;
|
|
135600
135860
|
}
|
|
135601
|
-
var AuthError, ErrNotConfigured, ErrInvalidStore, ErrUnauthenticated, ErrApi, ErrOAuthNotConfigured, ErrRefreshFailed;
|
|
135861
|
+
var AuthError, ErrNotConfigured, ErrInvalidStore, ErrUnauthenticated, ErrApi, ErrOAuthNotConfigured, ErrRefreshFailed, ErrDeviceAuthFailed;
|
|
135602
135862
|
var init_errors = __esm({
|
|
135603
135863
|
"src/auth/errors.ts"() {
|
|
135604
135864
|
"use strict";
|
|
@@ -135638,6 +135898,11 @@ var init_errors = __esm({
|
|
|
135638
135898
|
detail ? `Failed to refresh OAuth tokens: ${detail}` : "Failed to refresh OAuth tokens",
|
|
135639
135899
|
"Run `hyperframes auth login` to re-authenticate."
|
|
135640
135900
|
);
|
|
135901
|
+
ErrDeviceAuthFailed = (detail) => new AuthError(
|
|
135902
|
+
"DEVICE_AUTH_FAILED",
|
|
135903
|
+
`Device authorization failed: ${detail}`,
|
|
135904
|
+
"Run `hyperframes auth login --device` to start a new code."
|
|
135905
|
+
);
|
|
135641
135906
|
}
|
|
135642
135907
|
});
|
|
135643
135908
|
|
|
@@ -136347,6 +136612,9 @@ function tokenEndpoint() {
|
|
|
136347
136612
|
function revokeEndpoint() {
|
|
136348
136613
|
return process.env["HYPERFRAMES_OAUTH_REVOKE_URL"] || DEFAULT_REVOKE_URL;
|
|
136349
136614
|
}
|
|
136615
|
+
function deviceAuthorizationEndpoint() {
|
|
136616
|
+
return process.env["HYPERFRAMES_OAUTH_DEVICE_URL"] || DEFAULT_DEVICE_AUTHORIZATION_URL;
|
|
136617
|
+
}
|
|
136350
136618
|
function resolveClientId() {
|
|
136351
136619
|
const override = process.env["HYPERFRAMES_OAUTH_CLIENT_ID"];
|
|
136352
136620
|
const id = override && override.length > 0 ? override : DEFAULT_CLIENT_ID;
|
|
@@ -136402,6 +136670,127 @@ async function startAuthorizationCodeFlow(opts = {}) {
|
|
|
136402
136670
|
await persistOAuth(tokens, { preserveMissing: false });
|
|
136403
136671
|
return { tokens };
|
|
136404
136672
|
}
|
|
136673
|
+
async function startDeviceAuthorizationFlow(opts = {}) {
|
|
136674
|
+
const runtime = {
|
|
136675
|
+
clientId: resolveClientId(),
|
|
136676
|
+
fetchImpl: opts.fetchImpl ?? fetch,
|
|
136677
|
+
sleepImpl: opts.sleepImpl ?? ((ms) => new Promise((resolve77) => setTimeout(resolve77, ms))),
|
|
136678
|
+
now: opts.now ?? Date.now,
|
|
136679
|
+
requestTimeoutMs: opts.requestTimeoutMs ?? DEVICE_REQUEST_TIMEOUT_MS
|
|
136680
|
+
};
|
|
136681
|
+
const issuance = await requestDeviceAuthorization(runtime, opts.scope ?? DEFAULT_SCOPES);
|
|
136682
|
+
await opts.onChallenge?.({
|
|
136683
|
+
userCode: issuance.userCode,
|
|
136684
|
+
verificationUri: issuance.verificationUri,
|
|
136685
|
+
...issuance.verificationUriComplete ? { verificationUriComplete: issuance.verificationUriComplete } : {}
|
|
136686
|
+
});
|
|
136687
|
+
return await pollDeviceToken(runtime, issuance);
|
|
136688
|
+
}
|
|
136689
|
+
async function requestDeviceAuthorization(runtime, scope) {
|
|
136690
|
+
return await withDeviceRequestTimeout(
|
|
136691
|
+
runtime,
|
|
136692
|
+
"could not reach the authorization server",
|
|
136693
|
+
async (signal) => {
|
|
136694
|
+
const response = await runtime.fetchImpl(deviceAuthorizationEndpoint(), {
|
|
136695
|
+
method: "POST",
|
|
136696
|
+
headers: {
|
|
136697
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
136698
|
+
accept: "application/json"
|
|
136699
|
+
},
|
|
136700
|
+
body: new URLSearchParams({ client_id: runtime.clientId, scope }).toString(),
|
|
136701
|
+
signal
|
|
136702
|
+
});
|
|
136703
|
+
if (!response.ok) {
|
|
136704
|
+
throw ErrDeviceAuthFailed(`authorization server returned HTTP ${response.status}`);
|
|
136705
|
+
}
|
|
136706
|
+
return parseDeviceAuthorizationResponse(await readJsonOrDeviceError(response));
|
|
136707
|
+
}
|
|
136708
|
+
);
|
|
136709
|
+
}
|
|
136710
|
+
async function pollDeviceToken(runtime, issuance) {
|
|
136711
|
+
const deadline = runtime.now() + Math.min(issuance.expiresIn, MAX_DEVICE_FLOW_SECONDS) * 1e3;
|
|
136712
|
+
let intervalSeconds = issuance.interval;
|
|
136713
|
+
while (runtime.now() < deadline) {
|
|
136714
|
+
const remainingMs = deadline - runtime.now();
|
|
136715
|
+
if (remainingMs <= 0) break;
|
|
136716
|
+
await runtime.sleepImpl(Math.min(intervalSeconds * 1e3, remainingMs));
|
|
136717
|
+
const result = await requestDeviceToken(runtime, issuance.deviceCode);
|
|
136718
|
+
if (result.tokens) return result.tokens;
|
|
136719
|
+
if (result.slowDown) {
|
|
136720
|
+
intervalSeconds = Math.min(
|
|
136721
|
+
Math.max(intervalSeconds + 5, result.retryAfterSeconds ?? 0),
|
|
136722
|
+
MAX_DEVICE_POLL_SECONDS
|
|
136723
|
+
);
|
|
136724
|
+
}
|
|
136725
|
+
}
|
|
136726
|
+
throw ErrDeviceAuthFailed("the code expired");
|
|
136727
|
+
}
|
|
136728
|
+
async function requestDeviceToken(runtime, deviceCode) {
|
|
136729
|
+
return await withDeviceRequestTimeout(
|
|
136730
|
+
runtime,
|
|
136731
|
+
"lost contact with the authorization server",
|
|
136732
|
+
async (signal) => {
|
|
136733
|
+
const response = await runtime.fetchImpl(tokenEndpoint(), {
|
|
136734
|
+
method: "POST",
|
|
136735
|
+
headers: {
|
|
136736
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
136737
|
+
accept: "application/json"
|
|
136738
|
+
},
|
|
136739
|
+
body: new URLSearchParams({
|
|
136740
|
+
grant_type: DEVICE_CODE_GRANT_TYPE,
|
|
136741
|
+
device_code: deviceCode,
|
|
136742
|
+
client_id: runtime.clientId
|
|
136743
|
+
}).toString(),
|
|
136744
|
+
signal
|
|
136745
|
+
});
|
|
136746
|
+
return await evaluateDevicePollResponse(response, runtime.now());
|
|
136747
|
+
}
|
|
136748
|
+
);
|
|
136749
|
+
}
|
|
136750
|
+
async function evaluateDevicePollResponse(response, nowMs) {
|
|
136751
|
+
if (response.ok) {
|
|
136752
|
+
return { tokens: parseTokenResponse(await readJsonOrDeviceError(response)) };
|
|
136753
|
+
}
|
|
136754
|
+
const error = await readDeviceOAuthError(response);
|
|
136755
|
+
switch (error) {
|
|
136756
|
+
case "authorization_pending":
|
|
136757
|
+
return {};
|
|
136758
|
+
case "slow_down":
|
|
136759
|
+
return { slowDown: true, retryAfterSeconds: retryAfterSeconds(response, nowMs) };
|
|
136760
|
+
case "access_denied":
|
|
136761
|
+
throw ErrDeviceAuthFailed("access was denied");
|
|
136762
|
+
case "expired_token":
|
|
136763
|
+
throw ErrDeviceAuthFailed("the code expired");
|
|
136764
|
+
default:
|
|
136765
|
+
if (response.status === 429) {
|
|
136766
|
+
return { slowDown: true, retryAfterSeconds: retryAfterSeconds(response, nowMs) };
|
|
136767
|
+
}
|
|
136768
|
+
throw ErrDeviceAuthFailed(`authorization server returned HTTP ${response.status}`);
|
|
136769
|
+
}
|
|
136770
|
+
}
|
|
136771
|
+
async function withDeviceRequestTimeout(runtime, networkError, operation) {
|
|
136772
|
+
const controller = new AbortController();
|
|
136773
|
+
const timer = setTimeout(() => controller.abort(), runtime.requestTimeoutMs);
|
|
136774
|
+
try {
|
|
136775
|
+
return await operation(controller.signal);
|
|
136776
|
+
} catch (err) {
|
|
136777
|
+
if (controller.signal.aborted) {
|
|
136778
|
+
throw ErrDeviceAuthFailed("authorization server request timed out");
|
|
136779
|
+
}
|
|
136780
|
+
if (isAuthError(err)) throw err;
|
|
136781
|
+
throw ErrDeviceAuthFailed(networkError);
|
|
136782
|
+
} finally {
|
|
136783
|
+
clearTimeout(timer);
|
|
136784
|
+
}
|
|
136785
|
+
}
|
|
136786
|
+
function retryAfterSeconds(response, nowMs) {
|
|
136787
|
+
const value = response.headers.get("retry-after")?.trim();
|
|
136788
|
+
if (!value) return void 0;
|
|
136789
|
+
if (/^\d+$/.test(value)) return Math.min(Number(value), MAX_DEVICE_POLL_SECONDS);
|
|
136790
|
+
const retryAt = Date.parse(value);
|
|
136791
|
+
if (!Number.isFinite(retryAt)) return void 0;
|
|
136792
|
+
return Math.min(Math.max(Math.ceil((retryAt - nowMs) / 1e3), 0), MAX_DEVICE_POLL_SECONDS);
|
|
136793
|
+
}
|
|
136405
136794
|
async function refreshTokens(refresh_token, opts = {}) {
|
|
136406
136795
|
const clientId = resolveClientId();
|
|
136407
136796
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
@@ -136562,6 +136951,146 @@ async function persistOAuth(tokens, opts) {
|
|
|
136562
136951
|
const oauth = opts.preserveMissing ? { ...existing.oauth, ...tokens } : { ...tokens };
|
|
136563
136952
|
await writeStore({ ...existing, oauth });
|
|
136564
136953
|
}
|
|
136954
|
+
async function persistVerifiedOAuthSession(tokens, user) {
|
|
136955
|
+
let credentials = {};
|
|
136956
|
+
try {
|
|
136957
|
+
({ credentials } = await readStore());
|
|
136958
|
+
} catch {
|
|
136959
|
+
credentials = {};
|
|
136960
|
+
}
|
|
136961
|
+
const next = {
|
|
136962
|
+
...credentials,
|
|
136963
|
+
oauth: { ...tokens }
|
|
136964
|
+
};
|
|
136965
|
+
if (user.email || user.first_name || user.last_name || user.username) {
|
|
136966
|
+
next.user = {
|
|
136967
|
+
...credentials.user,
|
|
136968
|
+
email: user.email,
|
|
136969
|
+
first_name: user.first_name,
|
|
136970
|
+
last_name: user.last_name,
|
|
136971
|
+
username: user.username
|
|
136972
|
+
};
|
|
136973
|
+
} else {
|
|
136974
|
+
delete next.user;
|
|
136975
|
+
}
|
|
136976
|
+
await writeStore(next);
|
|
136977
|
+
}
|
|
136978
|
+
function parseDeviceAuthorizationResponse(payload) {
|
|
136979
|
+
const data2 = requireDeviceAuthorizationRecord(payload);
|
|
136980
|
+
const deviceCode = stringField(data2, "device_code");
|
|
136981
|
+
const userCode = stringField(data2, "user_code");
|
|
136982
|
+
const verificationUri = requiredSafeVerificationUri(data2, "verification_uri");
|
|
136983
|
+
const verificationUriComplete = optionalSafeVerificationUri(data2, "verification_uri_complete");
|
|
136984
|
+
const expiresIn = strictNumericField(data2, "expires_in");
|
|
136985
|
+
const interval = strictNumericField(data2, "interval");
|
|
136986
|
+
requireSafeDeviceCode(deviceCode);
|
|
136987
|
+
requireSafeDeviceCode(userCode);
|
|
136988
|
+
const timing2 = normalizeDeviceAuthorizationTiming(data2, expiresIn, interval);
|
|
136989
|
+
return {
|
|
136990
|
+
deviceCode,
|
|
136991
|
+
userCode,
|
|
136992
|
+
verificationUri,
|
|
136993
|
+
...verificationUriComplete ? { verificationUriComplete } : {},
|
|
136994
|
+
...timing2
|
|
136995
|
+
};
|
|
136996
|
+
}
|
|
136997
|
+
function requireSafeDeviceCode(value) {
|
|
136998
|
+
if (!value || !isHeaderSafe(value)) {
|
|
136999
|
+
throw ErrDeviceAuthFailed("authorization server returned an invalid response");
|
|
137000
|
+
}
|
|
137001
|
+
}
|
|
137002
|
+
function normalizeDeviceAuthorizationTiming(data2, expiresIn, interval) {
|
|
137003
|
+
if (!isPositiveNumber(expiresIn) || data2["interval"] !== void 0 && !isPositiveNumber(interval)) {
|
|
137004
|
+
throw ErrDeviceAuthFailed("authorization server returned invalid timing values");
|
|
137005
|
+
}
|
|
137006
|
+
return {
|
|
137007
|
+
expiresIn,
|
|
137008
|
+
interval: Math.min(
|
|
137009
|
+
Math.max(Math.ceil(interval ?? MIN_DEVICE_POLL_SECONDS), MIN_DEVICE_POLL_SECONDS),
|
|
137010
|
+
MAX_DEVICE_POLL_SECONDS
|
|
137011
|
+
)
|
|
137012
|
+
};
|
|
137013
|
+
}
|
|
137014
|
+
function requiredSafeVerificationUri(data2, key2) {
|
|
137015
|
+
const value = normalizeSafeVerificationUri(stringField(data2, key2));
|
|
137016
|
+
if (!value) throw ErrDeviceAuthFailed("authorization server returned an unsafe verification URL");
|
|
137017
|
+
return value;
|
|
137018
|
+
}
|
|
137019
|
+
function optionalSafeVerificationUri(data2, key2) {
|
|
137020
|
+
if (data2[key2] === void 0) return void 0;
|
|
137021
|
+
return requiredSafeVerificationUri(data2, key2);
|
|
137022
|
+
}
|
|
137023
|
+
function requireDeviceAuthorizationRecord(payload) {
|
|
137024
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
137025
|
+
throw ErrDeviceAuthFailed("authorization server returned an invalid response");
|
|
137026
|
+
}
|
|
137027
|
+
return payload;
|
|
137028
|
+
}
|
|
137029
|
+
function isPositiveNumber(value) {
|
|
137030
|
+
return value !== void 0 && value > 0;
|
|
137031
|
+
}
|
|
137032
|
+
function normalizeSafeVerificationUri(value) {
|
|
137033
|
+
if (!value || !isHeaderSafe(value)) return void 0;
|
|
137034
|
+
try {
|
|
137035
|
+
const url = new URL(value);
|
|
137036
|
+
if (url.username || url.password) return void 0;
|
|
137037
|
+
const allowed = url.protocol === "https:" || url.protocol === "http:" && ["127.0.0.1", "localhost"].includes(url.hostname);
|
|
137038
|
+
return allowed ? url.href : void 0;
|
|
137039
|
+
} catch {
|
|
137040
|
+
return void 0;
|
|
137041
|
+
}
|
|
137042
|
+
}
|
|
137043
|
+
async function readJsonOrDeviceError(res) {
|
|
137044
|
+
return await readBoundedDeviceJson(res);
|
|
137045
|
+
}
|
|
137046
|
+
async function readDeviceOAuthError(res) {
|
|
137047
|
+
try {
|
|
137048
|
+
const payload = await readBoundedDeviceJson(res);
|
|
137049
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return void 0;
|
|
137050
|
+
const error = payload["error"];
|
|
137051
|
+
return typeof error === "string" ? error : void 0;
|
|
137052
|
+
} catch {
|
|
137053
|
+
return void 0;
|
|
137054
|
+
}
|
|
137055
|
+
}
|
|
137056
|
+
function strictNumericField(obj, key2) {
|
|
137057
|
+
const value = obj[key2];
|
|
137058
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
137059
|
+
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
137060
|
+
const parsed = Number(value);
|
|
137061
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
137062
|
+
}
|
|
137063
|
+
async function readBoundedDeviceJson(res) {
|
|
137064
|
+
if (!res.body) throw ErrDeviceAuthFailed("authorization server returned no data");
|
|
137065
|
+
const reader = res.body.getReader();
|
|
137066
|
+
const chunks = [];
|
|
137067
|
+
let total = 0;
|
|
137068
|
+
try {
|
|
137069
|
+
while (true) {
|
|
137070
|
+
const { done, value } = await reader.read();
|
|
137071
|
+
if (done) break;
|
|
137072
|
+
if (!value) continue;
|
|
137073
|
+
total += value.byteLength;
|
|
137074
|
+
if (total > MAX_DEVICE_RESPONSE_BYTES) {
|
|
137075
|
+
await reader.cancel();
|
|
137076
|
+
throw ErrDeviceAuthFailed("authorization server response was too large");
|
|
137077
|
+
}
|
|
137078
|
+
chunks.push(value);
|
|
137079
|
+
}
|
|
137080
|
+
const body = new Uint8Array(total);
|
|
137081
|
+
let offset2 = 0;
|
|
137082
|
+
for (const chunk of chunks) {
|
|
137083
|
+
body.set(chunk, offset2);
|
|
137084
|
+
offset2 += chunk.byteLength;
|
|
137085
|
+
}
|
|
137086
|
+
return JSON.parse(new TextDecoder().decode(body));
|
|
137087
|
+
} catch (err) {
|
|
137088
|
+
if (isAuthError(err)) throw err;
|
|
137089
|
+
throw ErrDeviceAuthFailed("authorization server returned non-JSON data");
|
|
137090
|
+
} finally {
|
|
137091
|
+
reader.releaseLock();
|
|
137092
|
+
}
|
|
137093
|
+
}
|
|
136565
137094
|
async function readJsonOrThrow(res) {
|
|
136566
137095
|
try {
|
|
136567
137096
|
return await res.json();
|
|
@@ -136576,7 +137105,7 @@ async function safeText2(res) {
|
|
|
136576
137105
|
return "";
|
|
136577
137106
|
}
|
|
136578
137107
|
}
|
|
136579
|
-
var REVOKE_TIMEOUT_MS, MIN_EXPIRES_IN_SECONDS, DEFAULT_CLIENT_ID, DEFAULT_SCOPES, DEFAULT_AUTHORIZE_URL, DEFAULT_TOKEN_URL, DEFAULT_REVOKE_URL;
|
|
137108
|
+
var REVOKE_TIMEOUT_MS, MIN_EXPIRES_IN_SECONDS, DEFAULT_CLIENT_ID, DEFAULT_SCOPES, DEFAULT_AUTHORIZE_URL, DEFAULT_TOKEN_URL, DEFAULT_REVOKE_URL, DEFAULT_DEVICE_AUTHORIZATION_URL, DEVICE_CODE_GRANT_TYPE, MAX_DEVICE_FLOW_SECONDS, MIN_DEVICE_POLL_SECONDS, MAX_DEVICE_POLL_SECONDS, MAX_DEVICE_RESPONSE_BYTES, DEVICE_REQUEST_TIMEOUT_MS;
|
|
136580
137109
|
var init_oauth = __esm({
|
|
136581
137110
|
"src/auth/oauth.ts"() {
|
|
136582
137111
|
"use strict";
|
|
@@ -136595,6 +137124,13 @@ var init_oauth = __esm({
|
|
|
136595
137124
|
DEFAULT_AUTHORIZE_URL = "https://app.heygen.com/oauth/authorize";
|
|
136596
137125
|
DEFAULT_TOKEN_URL = "https://api2.heygen.com/v1/oauth/token";
|
|
136597
137126
|
DEFAULT_REVOKE_URL = "https://api2.heygen.com/v1/oauth/revoke";
|
|
137127
|
+
DEFAULT_DEVICE_AUTHORIZATION_URL = "https://api2.heygen.com/v1/oauth/device_authorization";
|
|
137128
|
+
DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
137129
|
+
MAX_DEVICE_FLOW_SECONDS = 30 * 60;
|
|
137130
|
+
MIN_DEVICE_POLL_SECONDS = 5;
|
|
137131
|
+
MAX_DEVICE_POLL_SECONDS = 60;
|
|
137132
|
+
MAX_DEVICE_RESPONSE_BYTES = 64 * 1024;
|
|
137133
|
+
DEVICE_REQUEST_TIMEOUT_MS = 15e3;
|
|
136598
137134
|
}
|
|
136599
137135
|
});
|
|
136600
137136
|
|
|
@@ -136613,7 +137149,7 @@ var init_auth = __esm({
|
|
|
136613
137149
|
});
|
|
136614
137150
|
|
|
136615
137151
|
// src/utils/projectLink.ts
|
|
136616
|
-
import { randomUUID as
|
|
137152
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
136617
137153
|
import { existsSync as existsSync75, mkdirSync as mkdirSync39, readFileSync as readFileSync46, writeFileSync as writeFileSync28 } from "fs";
|
|
136618
137154
|
import { homedir as homedir16 } from "os";
|
|
136619
137155
|
import { join as join83, resolve as resolve47 } from "path";
|
|
@@ -136664,7 +137200,7 @@ function ensureProjectId(absDir) {
|
|
|
136664
137200
|
const path2 = resolve47(absDir);
|
|
136665
137201
|
const existing = links[path2];
|
|
136666
137202
|
if (existing) return existing.projectId;
|
|
136667
|
-
const projectId =
|
|
137203
|
+
const projectId = randomUUID10();
|
|
136668
137204
|
links[path2] = { projectId, url: "" };
|
|
136669
137205
|
writeProjectLinks(links);
|
|
136670
137206
|
return projectId;
|
|
@@ -150344,7 +150880,7 @@ __export(feedback_exports, {
|
|
|
150344
150880
|
default: () => feedback_default,
|
|
150345
150881
|
examples: () => examples26
|
|
150346
150882
|
});
|
|
150347
|
-
import { randomUUID as
|
|
150883
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
150348
150884
|
import { resolve as resolve66 } from "path";
|
|
150349
150885
|
import open from "open";
|
|
150350
150886
|
function normalizeComment(raw) {
|
|
@@ -150497,7 +151033,7 @@ var init_feedback2 = __esm({
|
|
|
150497
151033
|
}
|
|
150498
151034
|
const comment = normalizeComment(args.comment);
|
|
150499
151035
|
const doctorSummary = await getDoctorSummary();
|
|
150500
|
-
const feedbackId =
|
|
151036
|
+
const feedbackId = randomUUID11();
|
|
150501
151037
|
const config = readConfig();
|
|
150502
151038
|
const joinKeys = buildTelemetryJoinKeys({
|
|
150503
151039
|
feedbackId,
|
|
@@ -158802,7 +159338,7 @@ var require_gaxios = __commonJS({
|
|
|
158802
159338
|
var retry_js_1 = require_retry3();
|
|
158803
159339
|
var stream_1 = __require("stream");
|
|
158804
159340
|
var interceptor_js_1 = require_interceptor();
|
|
158805
|
-
var
|
|
159341
|
+
var randomUUID12 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
158806
159342
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
158807
159343
|
var Gaxios = class {
|
|
158808
159344
|
agentCache = /* @__PURE__ */ new Map();
|
|
@@ -159075,7 +159611,7 @@ var require_gaxios = __commonJS({
|
|
|
159075
159611
|
*/
|
|
159076
159612
|
["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
159077
159613
|
if (opts.multipart?.length) {
|
|
159078
|
-
const boundary = await
|
|
159614
|
+
const boundary = await randomUUID12();
|
|
159079
159615
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
159080
159616
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
159081
159617
|
} else if (shouldDirectlyPassData) {
|
|
@@ -192744,7 +193280,7 @@ __export(compare_exports, {
|
|
|
192744
193280
|
parseCompareArgs: () => parseCompareArgs,
|
|
192745
193281
|
prepareCompareVariantProjects: () => prepareCompareVariantProjects
|
|
192746
193282
|
});
|
|
192747
|
-
import { cpSync as cpSync6, existsSync as existsSync105, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync17, renameSync as renameSync15, rmSync as
|
|
193283
|
+
import { cpSync as cpSync6, existsSync as existsSync105, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync17, renameSync as renameSync15, rmSync as rmSync33, statSync as statSync36 } from "fs";
|
|
192748
193284
|
import { tmpdir as tmpdir17 } from "os";
|
|
192749
193285
|
import { basename as basename28, dirname as dirname55, extname as extname23, join as join110 } from "path";
|
|
192750
193286
|
function defaultLabelForPath(input2) {
|
|
@@ -192864,7 +193400,7 @@ function stageHtmlVariant(variant) {
|
|
|
192864
193400
|
stagedDir
|
|
192865
193401
|
};
|
|
192866
193402
|
} catch (err) {
|
|
192867
|
-
|
|
193403
|
+
rmSync33(stagedDir, { recursive: true, force: true });
|
|
192868
193404
|
throw err;
|
|
192869
193405
|
}
|
|
192870
193406
|
}
|
|
@@ -192893,7 +193429,7 @@ function prepareCompareVariantProjects(variants) {
|
|
|
192893
193429
|
} catch (err) {
|
|
192894
193430
|
for (const variant of prepared) {
|
|
192895
193431
|
if (variant.stagedDir) {
|
|
192896
|
-
|
|
193432
|
+
rmSync33(variant.stagedDir, { recursive: true, force: true });
|
|
192897
193433
|
}
|
|
192898
193434
|
}
|
|
192899
193435
|
throw err;
|
|
@@ -192902,7 +193438,7 @@ function prepareCompareVariantProjects(variants) {
|
|
|
192902
193438
|
function cleanupPreparedCompareVariants(variants) {
|
|
192903
193439
|
for (const variant of variants) {
|
|
192904
193440
|
if (variant.stagedDir) {
|
|
192905
|
-
|
|
193441
|
+
rmSync33(variant.stagedDir, { recursive: true, force: true });
|
|
192906
193442
|
}
|
|
192907
193443
|
}
|
|
192908
193444
|
}
|
|
@@ -192974,7 +193510,7 @@ async function renderCompareSheet(parsed) {
|
|
|
192974
193510
|
return buildCompareSuccessPayload(parsed.outPath, variants, capResult);
|
|
192975
193511
|
} finally {
|
|
192976
193512
|
cleanupPreparedCompareVariants(prepared);
|
|
192977
|
-
|
|
193513
|
+
rmSync33(frameDir, { recursive: true, force: true });
|
|
192978
193514
|
}
|
|
192979
193515
|
}
|
|
192980
193516
|
function printJson2(payload) {
|
|
@@ -197690,7 +198226,7 @@ __export(state_exports, {
|
|
|
197690
198226
|
stateFilePath: () => stateFilePath,
|
|
197691
198227
|
writeStackOutputs: () => writeStackOutputs
|
|
197692
198228
|
});
|
|
197693
|
-
import { existsSync as existsSync113, mkdirSync as mkdirSync58, readdirSync as readdirSync38, readFileSync as readFileSync77, rmSync as
|
|
198229
|
+
import { existsSync as existsSync113, mkdirSync as mkdirSync58, readdirSync as readdirSync38, readFileSync as readFileSync77, rmSync as rmSync34, writeFileSync as writeFileSync53 } from "fs";
|
|
197694
198230
|
import { dirname as dirname56, join as join121 } from "path";
|
|
197695
198231
|
function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
|
|
197696
198232
|
return join121(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
|
|
@@ -197712,7 +198248,7 @@ function readStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
|
|
|
197712
198248
|
}
|
|
197713
198249
|
function deleteStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
|
|
197714
198250
|
const path2 = stateFilePath(stackName, cwd);
|
|
197715
|
-
if (existsSync113(path2))
|
|
198251
|
+
if (existsSync113(path2)) rmSync34(path2);
|
|
197716
198252
|
}
|
|
197717
198253
|
function listStackNames(cwd = process.cwd()) {
|
|
197718
198254
|
const dir = join121(cwd, STATE_DIR_NAME);
|
|
@@ -201752,6 +202288,98 @@ __export(login_exports, {
|
|
|
201752
202288
|
default: () => login_default
|
|
201753
202289
|
});
|
|
201754
202290
|
import { stdin as input } from "process";
|
|
202291
|
+
function isRemoteOrHeadless() {
|
|
202292
|
+
const remoteEnvironment = [
|
|
202293
|
+
"CODESPACES",
|
|
202294
|
+
"GITHUB_CODESPACES",
|
|
202295
|
+
"REMOTE_CONTAINERS",
|
|
202296
|
+
"GITPOD_WORKSPACE_ID",
|
|
202297
|
+
"container"
|
|
202298
|
+
].some(envFlagEnabled);
|
|
202299
|
+
return Boolean(
|
|
202300
|
+
process.env["SSH_CONNECTION"] || process.env["SSH_CLIENT"] || process.env["SSH_TTY"] || process.env["BROWSER"] === "none" || process.env["HF_NO_BROWSER"] === "1" || remoteEnvironment || process.stdout.isTTY !== true
|
|
202301
|
+
);
|
|
202302
|
+
}
|
|
202303
|
+
function envFlagEnabled(name) {
|
|
202304
|
+
const value = process.env[name]?.trim().toLowerCase();
|
|
202305
|
+
return Boolean(value && value !== "0" && value !== "false" && value !== "no");
|
|
202306
|
+
}
|
|
202307
|
+
function assertAttendedDeviceFlow() {
|
|
202308
|
+
if (envFlagEnabled("CI") || process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
202309
|
+
console.error(
|
|
202310
|
+
c.error(
|
|
202311
|
+
"`--device` requires an attended terminal and is disabled in CI. Use an API key or workload credential for automation."
|
|
202312
|
+
)
|
|
202313
|
+
);
|
|
202314
|
+
failUsage();
|
|
202315
|
+
}
|
|
202316
|
+
}
|
|
202317
|
+
async function runDeviceLogin() {
|
|
202318
|
+
assertAttendedDeviceFlow();
|
|
202319
|
+
assertOAuthConfiguredOrExit();
|
|
202320
|
+
const { trackAuthLoginStarted: trackAuthLoginStarted2, trackAuthLoginCompleted: trackAuthLoginCompleted2, trackAuthLoginFailed: trackAuthLoginFailed2, identifyUser: identifyUser2 } = await Promise.resolve().then(() => (init_telemetry2(), telemetry_exports2));
|
|
202321
|
+
trackAuthLoginStarted2("device");
|
|
202322
|
+
let tokens;
|
|
202323
|
+
try {
|
|
202324
|
+
tokens = await startDeviceAuthorizationFlow({
|
|
202325
|
+
onChallenge: ({ verificationUri, verificationUriComplete, userCode }) => {
|
|
202326
|
+
console.log(`Open ${c.accent(verificationUriComplete ?? verificationUri)} in a browser.`);
|
|
202327
|
+
if (!verificationUriComplete) console.log(`Enter code ${c.bold(userCode)}.`);
|
|
202328
|
+
console.log(c.dim("Waiting for approval\u2026"));
|
|
202329
|
+
}
|
|
202330
|
+
});
|
|
202331
|
+
} catch (err) {
|
|
202332
|
+
const message = err.message || "Device authorization failed.";
|
|
202333
|
+
trackAuthLoginFailed2("device", /expired/i.test(message) ? "flow_timeout" : "flow_error");
|
|
202334
|
+
console.error(c.error(message));
|
|
202335
|
+
failCommand();
|
|
202336
|
+
}
|
|
202337
|
+
const credential = {
|
|
202338
|
+
type: "oauth",
|
|
202339
|
+
access_token: tokens.access_token,
|
|
202340
|
+
...tokens.refresh_token ? { refresh_token: tokens.refresh_token } : {},
|
|
202341
|
+
source: "file_json",
|
|
202342
|
+
refreshable: false
|
|
202343
|
+
};
|
|
202344
|
+
let user;
|
|
202345
|
+
try {
|
|
202346
|
+
user = await new AuthClient().getCurrentUser(credential);
|
|
202347
|
+
} catch (err) {
|
|
202348
|
+
await revokeDeviceTokens(tokens);
|
|
202349
|
+
trackAuthLoginFailed2("device", "rejected");
|
|
202350
|
+
console.error(
|
|
202351
|
+
c.error(
|
|
202352
|
+
`HeyGen could not verify the approved device session; no credential was saved. ${err.message}`
|
|
202353
|
+
)
|
|
202354
|
+
);
|
|
202355
|
+
failCommand();
|
|
202356
|
+
}
|
|
202357
|
+
try {
|
|
202358
|
+
await persistVerifiedOAuthSession(tokens, toStoredUserInfo(user));
|
|
202359
|
+
} catch (err) {
|
|
202360
|
+
await revokeDeviceTokens(tokens);
|
|
202361
|
+
trackAuthLoginFailed2("device", "flow_error");
|
|
202362
|
+
console.error(
|
|
202363
|
+
c.error(
|
|
202364
|
+
`Could not save the verified device session; it was revoked. ${err.message}`
|
|
202365
|
+
)
|
|
202366
|
+
);
|
|
202367
|
+
failCommand();
|
|
202368
|
+
}
|
|
202369
|
+
const id = identityKey(user);
|
|
202370
|
+
if (id) identifyUser2(id);
|
|
202371
|
+
trackAuthLoginCompleted2("device", id);
|
|
202372
|
+
const identity = userDisplayName(toStoredUserInfo(user)) ?? "(unknown user)";
|
|
202373
|
+
console.log(c.success(`\u2713 Signed in as ${identity}.`));
|
|
202374
|
+
}
|
|
202375
|
+
async function revokeDeviceTokens(tokens) {
|
|
202376
|
+
await revokeTokens(tokens.access_token, { token_type_hint: "access_token" });
|
|
202377
|
+
if (tokens.refresh_token) {
|
|
202378
|
+
await revokeTokens(tokens.refresh_token, {
|
|
202379
|
+
token_type_hint: "refresh_token"
|
|
202380
|
+
});
|
|
202381
|
+
}
|
|
202382
|
+
}
|
|
201755
202383
|
async function runOAuthLogin() {
|
|
201756
202384
|
assertOAuthConfiguredOrExit();
|
|
201757
202385
|
const { trackAuthLoginStarted: trackAuthLoginStarted2, trackAuthLoginFailed: trackAuthLoginFailed2 } = await Promise.resolve().then(() => (init_telemetry2(), telemetry_exports2));
|
|
@@ -201886,7 +202514,11 @@ async function rollback(previous) {
|
|
|
201886
202514
|
async function verifyAndReport(key2) {
|
|
201887
202515
|
const client = new AuthClient();
|
|
201888
202516
|
try {
|
|
201889
|
-
const user = await client.getCurrentUser({
|
|
202517
|
+
const user = await client.getCurrentUser({
|
|
202518
|
+
type: "api_key",
|
|
202519
|
+
key: key2,
|
|
202520
|
+
source: "file_json"
|
|
202521
|
+
});
|
|
201890
202522
|
await persistUserInfo(user);
|
|
201891
202523
|
const identity = userDisplayName(toStoredUserInfo(user)) ?? "(unknown user)";
|
|
201892
202524
|
console.log(c.success(`\u2713 API key saved. Authenticated as ${identity}.`));
|
|
@@ -201963,15 +202595,35 @@ var init_login = __esm({
|
|
|
201963
202595
|
"api-key": {
|
|
201964
202596
|
type: "string",
|
|
201965
202597
|
description: "API key value, or pass `--api-key` with no value to read from stdin / prompt."
|
|
202598
|
+
},
|
|
202599
|
+
device: {
|
|
202600
|
+
type: "boolean",
|
|
202601
|
+
description: "Use an attended device code (for SSH/headless terminals; never for CI)."
|
|
201966
202602
|
}
|
|
201967
202603
|
},
|
|
201968
202604
|
// fallow-ignore-next-line complexity
|
|
201969
202605
|
async run({ args }) {
|
|
201970
202606
|
const inlineKey = args["api-key"];
|
|
202607
|
+
if (inlineKey !== void 0 && args.device) {
|
|
202608
|
+
console.error(c.error("Choose either --device or --api-key, not both."));
|
|
202609
|
+
failUsage();
|
|
202610
|
+
}
|
|
201971
202611
|
if (inlineKey !== void 0) {
|
|
201972
202612
|
await runApiKeyLogin(inlineKey);
|
|
201973
202613
|
return;
|
|
201974
202614
|
}
|
|
202615
|
+
if (args.device) {
|
|
202616
|
+
await runDeviceLogin();
|
|
202617
|
+
return;
|
|
202618
|
+
}
|
|
202619
|
+
if (isRemoteOrHeadless()) {
|
|
202620
|
+
console.error(
|
|
202621
|
+
c.error(
|
|
202622
|
+
"Browser callback login is unavailable in this remote/headless terminal. Run `hyperframes auth login --device`."
|
|
202623
|
+
)
|
|
202624
|
+
);
|
|
202625
|
+
failUsage();
|
|
202626
|
+
}
|
|
201975
202627
|
await runOAuthLogin();
|
|
201976
202628
|
}
|
|
201977
202629
|
});
|
|
@@ -202394,6 +203046,7 @@ var init_auth3 = __esm({
|
|
|
202394
203046
|
init_colors();
|
|
202395
203047
|
examples37 = [
|
|
202396
203048
|
["Sign in via browser (OAuth)", "hyperframes auth login"],
|
|
203049
|
+
["Sign in from SSH/headless terminal", "hyperframes auth login --device"],
|
|
202397
203050
|
["Save an API key (interactive)", "hyperframes auth login --api-key"],
|
|
202398
203051
|
["Save an API key from stdin", "echo $HEYGEN_API_KEY | hyperframes auth login --api-key"],
|
|
202399
203052
|
["Check who you're signed in as", "hyperframes auth status"],
|
|
@@ -202407,7 +203060,7 @@ Manage HeyGen credentials. Credentials live in
|
|
|
202407
203060
|
${c.accent("~/.heygen/credentials")} and are shared with heygen-cli.
|
|
202408
203061
|
|
|
202409
203062
|
${c.bold("SUBCOMMANDS:")}
|
|
202410
|
-
${c.accent("login")} ${c.dim("Sign in via browser
|
|
203063
|
+
${c.accent("login")} ${c.dim("Sign in via browser, --device for SSH, or --api-key for a long-lived key.")}
|
|
202411
203064
|
${c.accent("status")} ${c.dim("Show the active credential's source, type, and identity.")}
|
|
202412
203065
|
${c.accent("refresh")} ${c.dim("Force-refresh the OAuth access token.")}
|
|
202413
203066
|
${c.accent("logout")} ${c.dim("Remove the stored credential (--keep-api-key for OAuth-only).")}
|
|
@@ -202418,6 +203071,7 @@ ${c.bold("ENV VARS:")}
|
|
|
202418
203071
|
${c.accent("HEYGEN_API_URL")} Override the API base URL (default https://api.heygen.com).
|
|
202419
203072
|
${c.accent("HEYGEN_CONFIG_DIR")} Override the credentials directory (default ~/.heygen).
|
|
202420
203073
|
${c.accent("HYPERFRAMES_OAUTH_CLIENT_ID")} Override the OAuth client_id (for dev/test).
|
|
203074
|
+
${c.accent("HYPERFRAMES_OAUTH_DEVICE_URL")} Override the RFC 8628 device endpoint (for dev/test).
|
|
202421
203075
|
`;
|
|
202422
203076
|
auth_default = defineCommand({
|
|
202423
203077
|
meta: { name: "auth", description: "Sign in to HeyGen and manage credentials" },
|
|
@@ -202699,7 +203353,7 @@ var init_parseFigmaRef = __esm({
|
|
|
202699
203353
|
});
|
|
202700
203354
|
|
|
202701
203355
|
// ../core/dist/figma/freeze.js
|
|
202702
|
-
import { copyFileSync as copyFileSync11, mkdirSync as mkdirSync61, rmSync as
|
|
203356
|
+
import { copyFileSync as copyFileSync11, mkdirSync as mkdirSync61, rmSync as rmSync35, statSync as statSync39, writeFileSync as writeFileSync55 } from "fs";
|
|
202703
203357
|
import { dirname as dirname59 } from "path";
|
|
202704
203358
|
function exceedsFreezeCap(byteLength) {
|
|
202705
203359
|
return byteLength > MAX_FREEZE_BYTES;
|
|
@@ -202715,7 +203369,7 @@ function freezeBytes(bytes, destPath) {
|
|
|
202715
203369
|
} catch (err) {
|
|
202716
203370
|
if (err.code !== "EEXIST")
|
|
202717
203371
|
throw err;
|
|
202718
|
-
|
|
203372
|
+
rmSync35(destPath);
|
|
202719
203373
|
writeFileSync55(destPath, bytes, { flag: "wx" });
|
|
202720
203374
|
}
|
|
202721
203375
|
return bytes.length;
|