hyperframes 0.7.92 → 0.7.93

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 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.92" : "0.0.0-dev";
53
+ VERSION = true ? "0.7.93" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -52025,8 +52025,62 @@ function containsTimelineCall(node, timelineVar) {
52025
52025
  function rangeOf(node) {
52026
52026
  return typeof node.start === "number" && typeof node.end === "number" ? [node.start, node.end] : void 0;
52027
52027
  }
52028
+ function isSafeDefaultExpression(node, earlierParams) {
52029
+ let safe = true;
52030
+ const visit = (current2, parent, key2) => {
52031
+ if (!isNode2(current2) || !safe) return;
52032
+ if (!SAFE_DEFAULT_NODES.has(current2.type)) {
52033
+ safe = false;
52034
+ return;
52035
+ }
52036
+ if (current2.type === "UnaryExpression" && current2.operator === "delete") {
52037
+ safe = false;
52038
+ return;
52039
+ }
52040
+ if (current2.type === "Identifier") {
52041
+ const nonValue = parent && key2 ? isNonValueIdentifierSlot(parent, key2) : false;
52042
+ if (!nonValue && current2.name !== "undefined" && !earlierParams.has(current2.name)) {
52043
+ safe = false;
52044
+ }
52045
+ return;
52046
+ }
52047
+ for (const childKey of Object.keys(current2)) {
52048
+ if (SKIP_KEYS.has(childKey)) continue;
52049
+ const child = current2[childKey];
52050
+ if (Array.isArray(child)) {
52051
+ for (const item of child) visit(item, current2, childKey);
52052
+ } else {
52053
+ visit(child, current2, childKey);
52054
+ }
52055
+ }
52056
+ };
52057
+ visit(node);
52058
+ return safe;
52059
+ }
52060
+ function supportedParam(param, earlier) {
52061
+ if (param.type === "Identifier") return { name: param.name };
52062
+ if (param.type !== "AssignmentPattern" || param.left?.type !== "Identifier") return null;
52063
+ if (!isSafeDefaultExpression(param.right, earlier)) return null;
52064
+ return { name: param.left.name, defaultExpression: param.right };
52065
+ }
52066
+ function supportedParams(fn) {
52067
+ if (SUPPORTED_PARAMS_CACHE.has(fn)) return SUPPORTED_PARAMS_CACHE.get(fn) ?? null;
52068
+ const params = [];
52069
+ const earlier = /* @__PURE__ */ new Set();
52070
+ for (const param of fn.params ?? []) {
52071
+ const parsed = supportedParam(param, earlier);
52072
+ if (!parsed) {
52073
+ SUPPORTED_PARAMS_CACHE.set(fn, null);
52074
+ return null;
52075
+ }
52076
+ params.push(parsed);
52077
+ earlier.add(parsed.name);
52078
+ }
52079
+ SUPPORTED_PARAMS_CACHE.set(fn, params);
52080
+ return params;
52081
+ }
52028
52082
  function isShapeEligible(fn) {
52029
- return isFunctionNode(fn) && fn.body?.type === "BlockStatement" && !(fn.params ?? []).some((p2) => p2.type !== "Identifier");
52083
+ return isFunctionNode(fn) && fn.body?.type === "BlockStatement" && supportedParams(fn) !== null;
52030
52084
  }
52031
52085
  function callsAny(node, names) {
52032
52086
  let hit = false;
@@ -52076,20 +52130,55 @@ function timelineBuildingNames(candidates, timelineVar) {
52076
52130
  function bump(counts, key2) {
52077
52131
  counts.set(key2, (counts.get(key2) ?? 0) + 1);
52078
52132
  }
52133
+ function undefinedIdentifier() {
52134
+ return { type: "Identifier", name: "undefined" };
52135
+ }
52136
+ function isExplicitUndefined(node) {
52137
+ return node?.type === "Identifier" && node.name === "undefined" || node?.type === "UnaryExpression" && node.operator === "void" && node.argument?.type === "Literal" && node.argument.value === 0;
52138
+ }
52139
+ function resolveHelperBindings(call, params) {
52140
+ if (call.arguments?.some((arg) => arg?.type === "SpreadElement")) return null;
52141
+ const bindings = /* @__PURE__ */ new Map();
52142
+ for (let i2 = 0; i2 < params.length; i2++) {
52143
+ const param = params[i2];
52144
+ const arg = call.arguments?.[i2];
52145
+ if (arg && !isExplicitUndefined(arg)) {
52146
+ bindings.set(param.name, arg);
52147
+ } else if (param.defaultExpression) {
52148
+ bindings.set(param.name, substituteParams(cloneNode2(param.defaultExpression), bindings));
52149
+ } else {
52150
+ bindings.set(param.name, undefinedIdentifier());
52151
+ }
52152
+ }
52153
+ return bindings;
52154
+ }
52155
+ function statementHelperCall(node, names) {
52156
+ if (node.type !== "ExpressionStatement") return void 0;
52157
+ const expression = node.expression;
52158
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier") {
52159
+ return void 0;
52160
+ }
52161
+ return names.has(expression.callee.name) ? expression : void 0;
52162
+ }
52079
52163
  function safelyDroppable(program, candidates) {
52080
52164
  const names = new Set(candidates.keys());
52081
52165
  const totalIds = /* @__PURE__ */ new Map();
52082
52166
  const stmtCalls = /* @__PURE__ */ new Map();
52167
+ const unbindable = /* @__PURE__ */ new Set();
52083
52168
  walkNodes(program, (n2) => {
52084
52169
  if (n2.type === "Identifier" && names.has(n2.name)) bump(totalIds, n2.name);
52085
- const e3 = n2.type === "ExpressionStatement" ? n2.expression : void 0;
52086
- if (e3?.type === "CallExpression" && e3.callee?.type === "Identifier" && names.has(e3.callee.name)) {
52087
- bump(stmtCalls, e3.callee.name);
52088
- }
52170
+ const call = statementHelperCall(n2, names);
52171
+ if (!call) return;
52172
+ bump(stmtCalls, call.callee.name);
52173
+ const fn = candidates.get(call.callee.name);
52174
+ const params = fn && supportedParams(fn);
52175
+ if (!params || !resolveHelperBindings(call, params)) unbindable.add(call.callee.name);
52089
52176
  });
52090
52177
  const safe = /* @__PURE__ */ new Map();
52091
52178
  for (const [name, fn] of candidates) {
52092
- if ((totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) safe.set(name, fn);
52179
+ if (!unbindable.has(name) && (totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) {
52180
+ safe.set(name, fn);
52181
+ }
52093
52182
  }
52094
52183
  return safe;
52095
52184
  }
@@ -52132,11 +52221,11 @@ function expandBody(bodyStmts, bindings, prov, ctx) {
52132
52221
  }
52133
52222
  function inlineHelper(call, ctx) {
52134
52223
  const fn = ctx.helpers.get(call.callee.name);
52135
- const bindings = /* @__PURE__ */ new Map();
52136
- (fn.params ?? []).forEach((p2, i2) => {
52137
- const arg = call.arguments?.[i2];
52138
- if (arg) bindings.set(p2.name, arg);
52139
- });
52224
+ if (!fn) return null;
52225
+ const params = supportedParams(fn);
52226
+ if (!params) return null;
52227
+ const bindings = resolveHelperBindings(call, params);
52228
+ if (!bindings) return null;
52140
52229
  const prov = {
52141
52230
  kind: "helper",
52142
52231
  fn: call.callee.name,
@@ -54683,7 +54772,7 @@ function decodeUrlPathVariants(path2) {
54683
54772
  }
54684
54773
  return variants;
54685
54774
  }
54686
- var recast, import_parser2, CANVAS_DIMENSIONS, VALID_CANVAS_RESOLUTIONS, RESOLUTION_ALIASES, ASPECT_AGNOSTIC_RESOLUTION_ALIASES, COMPOSITION_VARIABLE_TYPES, TIMELINE_COLORS, DEFAULT_DURATIONS, PROPERTY_GROUPS, PROP_TO_GROUP, FORBIDDEN_GSAP_PATTERNS, roundPercentage, SKIP_KEYS, FUNCTION_TYPES, GSAP_METHODS, MAX_DEPTH, MAX_ITERS, GSAP_METHODS2, QUERY_METHODS, ITERATION_METHODS, SCOPE_NODE_TYPES, CONST_NODES, MATH_FNS, MATH_CONSTS, BUILTIN_VAR_KEYS, DROPPED_VAR_KEYS, EXTRAS_KEYS, PERCENTAGE_KEY_RE, GSAP_DEFAULT_DURATION, DEFAULT_TYPEOF, EXCLUDED_TAGS, COMPOSITION_ATTRIBUTES, CANONICAL_AUTHORED_TIMING_ATTRIBUTES, DERIVED_TIMING_ATTRIBUTES, LEGACY_TIMING_ATTRIBUTES, ClipTimingWriteError, REFERENCE_ID_PATTERN, DERIVED_END_EQUALITY_EPSILON_SECONDS, MEDIA_TYPES, CompositionHtmlParseError, UHD_SQUARE_MIN, UHD_RECT_MIN, OK, FONT_ALIAS_MAP, FONT_ALIAS_KEYS;
54775
+ var recast, import_parser2, CANVAS_DIMENSIONS, VALID_CANVAS_RESOLUTIONS, RESOLUTION_ALIASES, ASPECT_AGNOSTIC_RESOLUTION_ALIASES, COMPOSITION_VARIABLE_TYPES, TIMELINE_COLORS, DEFAULT_DURATIONS, PROPERTY_GROUPS, PROP_TO_GROUP, FORBIDDEN_GSAP_PATTERNS, roundPercentage, SKIP_KEYS, FUNCTION_TYPES, GSAP_METHODS, MAX_DEPTH, MAX_ITERS, SAFE_DEFAULT_NODES, SUPPORTED_PARAMS_CACHE, GSAP_METHODS2, QUERY_METHODS, ITERATION_METHODS, SCOPE_NODE_TYPES, CONST_NODES, MATH_FNS, MATH_CONSTS, BUILTIN_VAR_KEYS, DROPPED_VAR_KEYS, EXTRAS_KEYS, PERCENTAGE_KEY_RE, GSAP_DEFAULT_DURATION, DEFAULT_TYPEOF, EXCLUDED_TAGS, COMPOSITION_ATTRIBUTES, CANONICAL_AUTHORED_TIMING_ATTRIBUTES, DERIVED_TIMING_ATTRIBUTES, LEGACY_TIMING_ATTRIBUTES, ClipTimingWriteError, REFERENCE_ID_PATTERN, DERIVED_END_EQUALITY_EPSILON_SECONDS, MEDIA_TYPES, CompositionHtmlParseError, UHD_SQUARE_MIN, UHD_RECT_MIN, OK, FONT_ALIAS_MAP, FONT_ALIAS_KEYS;
54687
54776
  var init_dist2 = __esm({
54688
54777
  "../parsers/dist/index.js"() {
54689
54778
  "use strict";
@@ -54791,6 +54880,23 @@ var init_dist2 = __esm({
54791
54880
  GSAP_METHODS = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
54792
54881
  MAX_DEPTH = 8;
54793
54882
  MAX_ITERS = 512;
54883
+ SAFE_DEFAULT_NODES = /* @__PURE__ */ new Set([
54884
+ "ArrayExpression",
54885
+ "BinaryExpression",
54886
+ "ChainExpression",
54887
+ "ConditionalExpression",
54888
+ "Identifier",
54889
+ "Literal",
54890
+ "LogicalExpression",
54891
+ "MemberExpression",
54892
+ "ObjectExpression",
54893
+ "Property",
54894
+ "SpreadElement",
54895
+ "TemplateElement",
54896
+ "TemplateLiteral",
54897
+ "UnaryExpression"
54898
+ ]);
54899
+ SUPPORTED_PARAMS_CACHE = /* @__PURE__ */ new WeakMap();
54794
54900
  GSAP_METHODS2 = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
54795
54901
  QUERY_METHODS = /* @__PURE__ */ new Set(["querySelector", "querySelectorAll"]);
54796
54902
  ITERATION_METHODS = /* @__PURE__ */ new Set(["forEach", "map"]);
@@ -58530,17 +58636,46 @@ function truncateTelemetryString(value, maxLength) {
58530
58636
  function redactUrlQueryStrings(value) {
58531
58637
  return value.replace(/\b(https?:\/\/[^\s?]+)\?[^\s]*/g, "$1?\u2026");
58532
58638
  }
58639
+ function redactKnownPaths(value, paths) {
58640
+ if (typeof value !== "string")
58641
+ return "";
58642
+ let out = value;
58643
+ for (const path2 of paths) {
58644
+ if (typeof path2 !== "string" || path2.length === 0)
58645
+ continue;
58646
+ const basename31 = path2.split(/[\\/]/).pop() ?? "";
58647
+ for (const literal2 of [path2, basename31].filter((v2) => v2.length > 2)) {
58648
+ out = out.split(literal2).join("[path]");
58649
+ }
58650
+ }
58651
+ return out;
58652
+ }
58533
58653
  function redactFilePaths(value) {
58534
- return value.replace(/file:\/\/[^\s'")]+/g, "[file-url]").replace(/\/Users\/[^\s'")]+/g, "[path]").replace(/\/(?:home|root|opt|app|workspace|srv|mnt)\/[^\s'")]+/g, "[path]").replace(/\/(?:private\/)?(?:var|tmp)\/[^\s'")]+/g, "[path]").replace(/[A-Za-z]:\\[^\s'")]+/g, "[path]");
58654
+ return value.replace(/file:\/\/[^\s'")]+/g, "[file-url]").replace(RELATIVE_PATH, "[path]").replace(BARE_RELATIVE_PATH, "[path]").replace(ABSOLUTE_PATH, "[path]").replace(ASSET_BASENAME, "[file]");
58535
58655
  }
58536
58656
  function redactTelemetryString(value, maxLength = MAX_TELEMETRY_STRING_LENGTH) {
58537
58657
  return truncateTelemetryString(redactFilePaths(redactUrlQueryStrings(value)), maxLength);
58538
58658
  }
58539
- var MAX_TELEMETRY_STRING_LENGTH;
58659
+ var MAX_TELEMETRY_STRING_LENGTH, SEGMENT, SEGMENT_NODOT, TOKEN_TAIL, ABSOLUTE_PATH, RELATIVE_PATH, ASSET_BASENAME, BARE_RELATIVE_PATH;
58540
58660
  var init_telemetryRedaction = __esm({
58541
58661
  "../core/dist/telemetryRedaction.js"() {
58542
58662
  "use strict";
58543
58663
  MAX_TELEMETRY_STRING_LENGTH = 240;
58664
+ SEGMENT = String.raw`[^\s/\\'"]+`;
58665
+ SEGMENT_NODOT = String.raw`[^\s/\\'".]+`;
58666
+ TOKEN_TAIL = String.raw`[^\s'")]*`;
58667
+ ABSOLUTE_PATH = new RegExp(String.raw`(?<![:\w/\\])(?:[A-Za-z]:)?(?:[\\/]${SEGMENT}){2,}${TOKEN_TAIL}`, "g");
58668
+ RELATIVE_PATH = new RegExp(String.raw`(?<![\w/\\.])\.{1,2}(?:[\\/]${SEGMENT})+${TOKEN_TAIL}`, "g");
58669
+ ASSET_BASENAME = /(?<![\w/\\])[^\s/\\'"]+\.(?:mp4|mov|mkv|webm|avi|m4v|mpe?g|ts|mp3|wav|aac|m4a|flac|ogg|opus|png|jpe?g|gif|webp|svg|html?|json|srt|vtt|ass)\b/gi;
58670
+ BARE_RELATIVE_PATH = new RegExp([
58671
+ // Two or more separators: `customer/acme/video.mp4`. No extension needed —
58672
+ // that much structure is already a path.
58673
+ String.raw`(?<![^\s'\"(=,\[])(?:${SEGMENT}[\\/]){2,}${SEGMENT}${TOKEN_TAIL}`,
58674
+ // One separator, but the last segment carries a file extension:
58675
+ // `assets/bgm.mp3`. That segment is dot-free on purpose — SEGMENT includes
58676
+ // `.`, so a greedy one swallows the extension this rule needs.
58677
+ String.raw`(?<![^\s'\"(=,\[])${SEGMENT}[\\/]${SEGMENT_NODOT}\.\w{1,8}\b${TOKEN_TAIL}`
58678
+ ].join("|"), "g");
58544
58679
  }
58545
58680
  });
58546
58681
 
@@ -62432,6 +62567,7 @@ __export(dist_exports, {
62432
62567
  quantizeTimeToFrame: () => quantizeTimeToFrame,
62433
62568
  queryByAttr: () => queryByAttr2,
62434
62569
  readClipTiming: () => readClipTiming2,
62570
+ redactKnownPaths: () => redactKnownPaths,
62435
62571
  redactTelemetryString: () => redactTelemetryString,
62436
62572
  removeElementFromHtml: () => removeElementFromHtml,
62437
62573
  resolveHfColorGradingVariables: () => resolveHfColorGradingVariables,
@@ -64060,7 +64196,7 @@ async function probeAutoBrowserGpuMode(options) {
64060
64196
  const ppt = await getPuppeteerOrNull();
64061
64197
  if (ppt === null) {
64062
64198
  logResolvedBrowserGpuMode("software", "puppeteer unavailable");
64063
- return "software";
64199
+ return { mode: "software", cause: "probe-error" };
64064
64200
  }
64065
64201
  try {
64066
64202
  const info = await probeHardwareWebGlInfo(ppt, {
@@ -64070,20 +64206,37 @@ async function probeAutoBrowserGpuMode(options) {
64070
64206
  });
64071
64207
  const resolved2 = resolveWebGlProbeMode(info);
64072
64208
  logResolvedBrowserGpuMode(resolved2, describeWebGlProbe(info));
64073
- return resolved2;
64209
+ return resolved2 === "hardware" ? { mode: "hardware" } : { mode: "software", cause: "no-gpu" };
64074
64210
  } catch (err) {
64075
64211
  logResolvedBrowserGpuMode("software", formatProbeFailure(err));
64076
- return "software";
64212
+ return { mode: "software", cause: "probe-error" };
64077
64213
  }
64078
64214
  }
64079
64215
  function resolveBrowserGpuMode(mode, options = {}) {
64080
- if (mode !== "auto") return Promise.resolve(mode);
64081
- if (_autoBrowserGpuModeCache) return _autoBrowserGpuModeCache;
64082
- _autoBrowserGpuModeCache = probeAutoBrowserGpuMode(options);
64083
- return _autoBrowserGpuModeCache;
64216
+ if (mode === "software") return Promise.resolve(mode);
64217
+ _autoBrowserGpuModeCache ??= probeAutoBrowserGpuMode(options);
64218
+ if (mode === "auto") return _autoBrowserGpuModeCache.then((probed) => probed.mode);
64219
+ return _autoBrowserGpuModeCache.then((probed) => {
64220
+ if (probed.mode === "software" && !_unverifiedHardwareGpuWarned) {
64221
+ _unverifiedHardwareGpuWarned = true;
64222
+ console.warn(
64223
+ buildUnverifiedHardwareGpuWarning(options.platform ?? process.platform, probed.cause)
64224
+ );
64225
+ }
64226
+ return "hardware";
64227
+ });
64228
+ }
64229
+ function buildUnverifiedHardwareGpuWarning(platform10, cause) {
64230
+ if (cause === "probe-error") {
64231
+ return "[hyperframes] browserGpuMode=hardware was requested, but the GPU probe could not run, so hardware acceleration is UNVERIFIED \u2014 if Chrome falls back to software WebGL the capture will run at CPU speed. Honouring the explicit request anyway.\n This is a probe failure, not evidence of a missing GPU: see the `browserGpuMode probe \u2192 software (probe failed ...)` line above for the underlying error, which usually means Chrome could not launch (bad HYPERFRAMES_BROWSER_PATH, missing shared libraries, or a denied sandbox) rather than a GPU problem.\n Run `hyperframes doctor` to check the Chrome install.";
64232
+ }
64233
+ const remediation = platform10 === "linux" ? "Inside Docker, the container needs GPU passthrough: `--gpus all` with the NVIDIA Container Toolkit installed, or `--device /dev/dri` for Mesa/AMD/Intel. The image also needs the matching userspace driver + libEGL. Verify with `hyperframes render --browser-gpu` and watch for this warning disappearing." : "Check that the host exposes a GPU to this process and that the graphics drivers are installed.";
64234
+ return `[hyperframes] browserGpuMode=hardware was requested, but the WebGL probe found no hardware GPU \u2014 Chrome will silently fall back to software WebGL and the capture will run at CPU speed. Honouring the explicit request anyway.
64235
+ ${remediation}
64236
+ Pass --no-browser-gpu to select deterministic SwiftShader instead of waiting on a hardware path that is not there.`;
64084
64237
  }
64085
64238
  function logResolvedBrowserGpuMode(resolved2, reason) {
64086
- console.error(`[hyperframes] browserGpuMode auto \u2192 ${resolved2} (${reason})`);
64239
+ console.error(`[hyperframes] browserGpuMode probe \u2192 ${resolved2} (${reason})`);
64087
64240
  }
64088
64241
  function createBrowserLaunchFingerprint(chromeArgs, config) {
64089
64242
  const launchConfig = {
@@ -64306,7 +64459,7 @@ function getBrowserGpuArgs(mode, platform10) {
64306
64459
  return ["--enable-gpu-rasterization"];
64307
64460
  }
64308
64461
  }
64309
- var _puppeteer, CACHED_HEADLESS_SHELL_EXECUTABLES, ENABLE_BROWSER_POOL, BEGINFRAME_ONLY_FLAGS, BEGINFRAME_SCREENSHOT_PROBE_ATTEMPTS, BEGINFRAME_PROBE_TIMEOUT_MS, BEGINFRAME_PROBE_CLEANUP_TIMEOUT_MS, _autoBrowserGpuModeCache, browserLeasePool, _cachedVramMb, CANVAS_DRAW_ELEMENT_FEATURE_FLAG, WEBGPU_FLAG;
64462
+ var _puppeteer, CACHED_HEADLESS_SHELL_EXECUTABLES, ENABLE_BROWSER_POOL, BEGINFRAME_ONLY_FLAGS, BEGINFRAME_SCREENSHOT_PROBE_ATTEMPTS, BEGINFRAME_PROBE_TIMEOUT_MS, BEGINFRAME_PROBE_CLEANUP_TIMEOUT_MS, _autoBrowserGpuModeCache, _unverifiedHardwareGpuWarned, browserLeasePool, _cachedVramMb, CANVAS_DRAW_ELEMENT_FEATURE_FLAG, WEBGPU_FLAG;
64310
64463
  var init_browserManager = __esm({
64311
64464
  "../engine/src/services/browserManager.ts"() {
64312
64465
  "use strict";
@@ -64336,6 +64489,7 @@ var init_browserManager = __esm({
64336
64489
  BEGINFRAME_SCREENSHOT_PROBE_ATTEMPTS = 10;
64337
64490
  BEGINFRAME_PROBE_TIMEOUT_MS = 2e3;
64338
64491
  BEGINFRAME_PROBE_CLEANUP_TIMEOUT_MS = 250;
64492
+ _unverifiedHardwareGpuWarned = false;
64339
64493
  browserLeasePool = new BrowserLeasePool({
64340
64494
  launch: launchBrowser,
64341
64495
  close: async (browser) => browser.close(),
@@ -66612,6 +66766,50 @@ function formatHttpErrorDiagnostic(input2) {
66612
66766
  const statusText = input2.statusText ? ` ${input2.statusText}` : "";
66613
66767
  return `[Browser:HTTP${input2.status}] ${input2.method} ${sanitizeDiagnosticUrl(input2.url)} resource=${input2.resourceType}${statusText}`;
66614
66768
  }
66769
+ function warmupFrameTimeTicks(state, intervalMs) {
66770
+ return state.ticks * intervalMs;
66771
+ }
66772
+ function deriveBeginFrameTimeTicks(state, warmupIntervalMs, captureIntervalMs) {
66773
+ const legacyCaptureTimeTicks = (state.ticks + BEGIN_FRAME_CAPTURE_HEADROOM_INTERVALS) * captureIntervalMs;
66774
+ const legacyCommitTimeTicks = deriveBeginFrameCommitTimeTicks(
66775
+ legacyCaptureTimeTicks,
66776
+ captureIntervalMs
66777
+ );
66778
+ const lastWarmupTimeTicks = Math.max(0, state.ticks - 1) * warmupIntervalMs;
66779
+ if (legacyCommitTimeTicks > lastWarmupTimeTicks) return legacyCaptureTimeTicks;
66780
+ const monotonicCaptureTimeTicks = warmupFrameTimeTicks(state, warmupIntervalMs) + BEGIN_FRAME_CAPTURE_HEADROOM_INTERVALS * captureIntervalMs;
66781
+ return monotonicCaptureTimeTicks;
66782
+ }
66783
+ function deriveBeginFrameCommitTimeTicks(captureTimeTicks, captureIntervalMs) {
66784
+ return captureTimeTicks - BEGIN_FRAME_COMMIT_LEAD_INTERVALS * captureIntervalMs;
66785
+ }
66786
+ function deriveBeginFrameProbeTimeTicks(captureTimeTicks, captureIntervalMs) {
66787
+ return Math.max(0, captureTimeTicks - BEGIN_FRAME_PROBE_LEAD_INTERVALS * captureIntervalMs);
66788
+ }
66789
+ function deriveBeginFrameTimelineTicks(state, warmupIntervalMs, captureIntervalMs) {
66790
+ const capture2 = deriveBeginFrameTimeTicks(state, warmupIntervalMs, captureIntervalMs);
66791
+ return {
66792
+ capture: capture2,
66793
+ commit: deriveBeginFrameCommitTimeTicks(capture2, captureIntervalMs),
66794
+ probe: deriveBeginFrameProbeTimeTicks(capture2, captureIntervalMs)
66795
+ };
66796
+ }
66797
+ function prepareBeginFrameTimeline(session, state, warmupIntervalMs) {
66798
+ const timeline = deriveBeginFrameTimelineTicks(
66799
+ state,
66800
+ warmupIntervalMs,
66801
+ session.beginFrameIntervalMs
66802
+ );
66803
+ session.beginFrameTimeTicks = timeline.capture;
66804
+ return {
66805
+ timeline,
66806
+ commitParams: {
66807
+ frameTimeTicks: timeline.commit,
66808
+ interval: session.beginFrameIntervalMs,
66809
+ noDisplayUpdates: false
66810
+ }
66811
+ };
66812
+ }
66615
66813
  async function driveWarmupTicks(options, state) {
66616
66814
  const sleep5 = options.sleep ?? realSleep;
66617
66815
  while (true) {
@@ -67557,17 +67755,16 @@ async function initializeSession(session) {
67557
67755
  warmupState.running = false;
67558
67756
  await warmupLoopPromise.catch(() => {
67559
67757
  });
67560
- const baseTickCount = lockWarmupTicks ? LOCKED_WARMUP_TICKS : warmupState.ticks;
67561
- session.beginFrameTimeTicks = (baseTickCount + 10) * session.beginFrameIntervalMs;
67758
+ const preparedBeginFrameTimeline = prepareBeginFrameTimeline(
67759
+ session,
67760
+ warmupState,
67761
+ warmupIntervalMs
67762
+ );
67562
67763
  await initDrawElementOrTransparentBackground(session, page, logInitPhase);
67563
67764
  await armStaticDedup(session, session.page, logInitPhase);
67564
67765
  await ensureRenderFrameSiblings(page);
67565
67766
  const commitCdp = await getCdpSession(page);
67566
- await commitCdp.send("HeadlessExperimental.beginFrame", {
67567
- frameTimeTicks: session.beginFrameTimeTicks - 6 * session.beginFrameIntervalMs,
67568
- interval: session.beginFrameIntervalMs,
67569
- noDisplayUpdates: false
67570
- });
67767
+ await commitCdp.send("HeadlessExperimental.beginFrame", preparedBeginFrameTimeline.commitParams);
67571
67768
  session.isInitialized = true;
67572
67769
  }
67573
67770
  async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
@@ -68406,7 +68603,7 @@ function getCapturePerfSummary(session) {
68406
68603
  deNcprFallbacks: session.deNcprFallbacks ?? 0
68407
68604
  };
68408
68605
  }
68409
- var DrawElementVerificationError, BROWSER_CONSOLE_BUFFER_SIZE, CAPTURE_SESSION_CLOSE_TIMEOUT_MS, LOCKED_WARMUP_TICKS, realSleep, HF_READY_DIAGNOSTIC_EXPR, LIVE_MAP_MARKERS, MAX_STATIC_DEDUP_ANALYSIS_FRAMES, STATIC_VERIFY_REFERENCE_STRIDE, STATIC_VERIFY_MAX_MS;
68606
+ var DrawElementVerificationError, BROWSER_CONSOLE_BUFFER_SIZE, CAPTURE_SESSION_CLOSE_TIMEOUT_MS, LOCKED_WARMUP_TICKS, realSleep, BEGIN_FRAME_CAPTURE_HEADROOM_INTERVALS, BEGIN_FRAME_COMMIT_LEAD_INTERVALS, BEGIN_FRAME_PROBE_LEAD_INTERVALS, HF_READY_DIAGNOSTIC_EXPR, LIVE_MAP_MARKERS, MAX_STATIC_DEDUP_ANALYSIS_FRAMES, STATIC_VERIFY_REFERENCE_STRIDE, STATIC_VERIFY_MAX_MS;
68410
68607
  var init_frameCapture = __esm({
68411
68608
  "../engine/src/services/frameCapture.ts"() {
68412
68609
  "use strict";
@@ -68437,6 +68634,9 @@ var init_frameCapture = __esm({
68437
68634
  CAPTURE_SESSION_CLOSE_TIMEOUT_MS = 5e3;
68438
68635
  LOCKED_WARMUP_TICKS = 60;
68439
68636
  realSleep = (ms) => new Promise((resolve77) => setTimeout(resolve77, ms));
68637
+ BEGIN_FRAME_CAPTURE_HEADROOM_INTERVALS = 10;
68638
+ BEGIN_FRAME_COMMIT_LEAD_INTERVALS = 6;
68639
+ BEGIN_FRAME_PROBE_LEAD_INTERVALS = 5;
68440
68640
  HF_READY_DIAGNOSTIC_EXPR = `(function() {
68441
68641
  var hf = window.__hf;
68442
68642
  var player = window.__player;
@@ -70621,21 +70821,25 @@ var init_referenceResolver = __esm({
70621
70821
  // ../engine/src/utils/urlDownloader.ts
70622
70822
  import {
70623
70823
  closeSync,
70824
+ createReadStream as createReadStream2,
70624
70825
  createWriteStream,
70625
70826
  existsSync as existsSync9,
70626
70827
  fsyncSync,
70828
+ linkSync,
70627
70829
  mkdtempSync,
70628
70830
  mkdirSync as mkdirSync5,
70629
70831
  lstatSync,
70630
70832
  openSync,
70631
- renameSync as renameSync2,
70833
+ readdirSync as readdirSync3,
70834
+ rmdirSync,
70632
70835
  rmSync as rmSync2,
70633
- statSync as statSync4
70836
+ statSync as statSync4,
70837
+ unlinkSync
70634
70838
  } from "fs";
70635
- import { createHash } from "crypto";
70839
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
70636
70840
  import { BlockList, isIP } from "net";
70637
70841
  import { dirname as dirname6, extname as extname2, join as join9 } from "path";
70638
- import { Readable } from "stream";
70842
+ import { Readable, Transform } from "stream";
70639
70843
  import { pipeline } from "stream/promises";
70640
70844
  function signalScopeKey(signal) {
70641
70845
  if (!signal) return "none";
@@ -70647,8 +70851,29 @@ function signalScopeKey(signal) {
70647
70851
  }
70648
70852
  return String(scope);
70649
70853
  }
70650
- function classifyHttpFailure(status, statusText) {
70651
- const message = `HTTP ${status}: ${statusText}`;
70854
+ function safeDownloadUrlIdentity(url) {
70855
+ let canonical = url;
70856
+ let host;
70857
+ try {
70858
+ const parsed = new URL(url);
70859
+ canonical = `${parsed.origin}${parsed.pathname}`;
70860
+ host = parsed.hostname.toLowerCase();
70861
+ } catch {
70862
+ }
70863
+ return {
70864
+ urlFingerprint: createHash("sha256").update(canonical).digest("hex"),
70865
+ host
70866
+ };
70867
+ }
70868
+ function writeUrlDownloadTelemetry(event) {
70869
+ try {
70870
+ process.stderr.write(`[hyperframes:download] ${JSON.stringify(event)}
70871
+ `);
70872
+ } catch {
70873
+ }
70874
+ }
70875
+ function classifyHttpFailure(status) {
70876
+ const message = `HTTP ${status}`;
70652
70877
  if (status === 404 || status === 410) {
70653
70878
  return new UrlDownloadError("http_not_found", false, message, status);
70654
70879
  }
@@ -70659,15 +70884,22 @@ function classifyHttpFailure(status, statusText) {
70659
70884
  }
70660
70885
  function classifyDownloadFailure(error) {
70661
70886
  if (error instanceof UrlDownloadError) return error;
70662
- const message = error instanceof Error ? error.message : String(error);
70663
70887
  let current2 = error;
70664
70888
  for (let depth = 0; current2 && depth < 4; depth += 1) {
70665
70889
  if (isRetryableNetworkCause(current2)) {
70666
- return new UrlDownloadError("network", true, `Download failed: ${message}`);
70890
+ return new UrlDownloadError(
70891
+ "network",
70892
+ true,
70893
+ "Download failed due to a transient network error"
70894
+ );
70667
70895
  }
70668
70896
  current2 = typeof current2 === "object" && current2 !== null && "cause" in current2 ? current2.cause : void 0;
70669
70897
  }
70670
- return new UrlDownloadError("filesystem", false, `Download failed: ${message}`);
70898
+ return new UrlDownloadError(
70899
+ "filesystem",
70900
+ false,
70901
+ "Download failed while writing the local artifact"
70902
+ );
70671
70903
  }
70672
70904
  function isRetryableNetworkCause(error) {
70673
70905
  const message = error instanceof Error ? error.message : String(error);
@@ -70686,31 +70918,155 @@ function assertPublicHttpsUrl(url) {
70686
70918
  try {
70687
70919
  parsed = new URL(url);
70688
70920
  } catch {
70689
- throw new Error(`[URLDownloader] Invalid URL: ${url}`);
70921
+ throw new Error("[URLDownloader] Invalid URL");
70690
70922
  }
70691
70923
  if (parsed.protocol !== "https:") {
70692
- throw new Error(
70693
- `[URLDownloader] Only HTTPS URLs are permitted in compositions (got ${parsed.protocol}): ${url}`
70694
- );
70924
+ throw new Error(`[URLDownloader] Only HTTPS URLs are permitted in compositions`);
70695
70925
  }
70696
70926
  if (isBlockedHost(parsed.hostname)) {
70697
- throw new Error(
70698
- `[URLDownloader] URL targets a private/reserved address and is not permitted: ${url}`
70699
- );
70927
+ throw new Error("[URLDownloader] URL targets a private/reserved address and is not permitted");
70700
70928
  }
70701
70929
  }
70702
- function getFilenameFromUrl(url) {
70703
- const hash2 = createHash("md5").update(url).digest("hex").slice(0, 12);
70930
+ function getFilenameFromUrl(url, validationScope) {
70931
+ const physicalIdentity = validationScope === "" ? url : `${url}\0${validationScope}`;
70932
+ const hash2 = createHash("md5").update(physicalIdentity).digest("hex").slice(0, 12);
70704
70933
  const urlObj = new URL(url);
70705
70934
  const ext = extname2(urlObj.pathname) || ".mp4";
70706
70935
  return `download_${hash2}${ext}`;
70707
70936
  }
70708
- function hasCompleteFile(path2) {
70709
- if (!existsSync9(path2)) return false;
70710
- const entry = lstatSync(path2);
70711
- if (entry.isFile() && entry.size > 0) return true;
70712
- rmSync2(path2, { recursive: entry.isDirectory(), force: true });
70713
- return false;
70937
+ function sameFileIdentity(left, right) {
70938
+ return left.dev === right.dev && left.ino === right.ino;
70939
+ }
70940
+ function sameCacheLockStatGeneration(left, right) {
70941
+ return sameFileIdentity(left, right) && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.birthtimeMs === right.birthtimeMs;
70942
+ }
70943
+ function observeCachePathLock(lockPath) {
70944
+ for (let pass = 0; pass < 3; pass += 1) {
70945
+ const before3 = lstatSync(lockPath);
70946
+ const owner = readdirSync3(lockPath).find((name) => name.startsWith(CACHE_LOCK_OWNER_PREFIX));
70947
+ const after2 = lstatSync(lockPath);
70948
+ if (sameCacheLockStatGeneration(before3, after2)) return { stats: after2, owner };
70949
+ }
70950
+ throw new UrlDownloadError("filesystem", true, "Cache lock changed repeatedly during inspection");
70951
+ }
70952
+ function sameCachePathLock(left, right) {
70953
+ if (left.owner !== void 0 || right.owner !== void 0) {
70954
+ return left.owner !== void 0 && left.owner === right.owner;
70955
+ }
70956
+ return sameFileIdentity(left.stats, right.stats);
70957
+ }
70958
+ function removeCacheLockDirectoryIfEmpty(lockPath) {
70959
+ try {
70960
+ rmdirSync(lockPath);
70961
+ } catch (error) {
70962
+ const code = error.code;
70963
+ if (code !== "ENOENT" && code !== "ENOTEMPTY" && code !== "EEXIST") throw error;
70964
+ }
70965
+ }
70966
+ function releaseOwnedCachePathLock(lockPath, owner) {
70967
+ try {
70968
+ rmdirSync(join9(lockPath, owner));
70969
+ } catch (error) {
70970
+ if (error.code === "ENOENT") return;
70971
+ throw error;
70972
+ }
70973
+ removeCacheLockDirectoryIfEmpty(lockPath);
70974
+ }
70975
+ async function waitForCacheLock(signal) {
70976
+ if (signal?.aborted) {
70977
+ throw new UrlDownloadError("cancelled", false, "Download cancelled");
70978
+ }
70979
+ await new Promise((resolve77, reject) => {
70980
+ const timeout = setTimeout(() => {
70981
+ signal?.removeEventListener("abort", onAbort);
70982
+ resolve77();
70983
+ }, CACHE_LOCK_POLL_MS);
70984
+ const onAbort = () => {
70985
+ clearTimeout(timeout);
70986
+ signal?.removeEventListener("abort", onAbort);
70987
+ reject(new UrlDownloadError("cancelled", false, "Download cancelled"));
70988
+ };
70989
+ signal?.addEventListener("abort", onAbort, { once: true });
70990
+ });
70991
+ }
70992
+ async function acquireCachePathLock(localPath, timeoutMs, signal) {
70993
+ const lockPath = `${localPath}.hf-lock`;
70994
+ const startedAt = Date.now();
70995
+ for (; ; ) {
70996
+ if (signal?.aborted) {
70997
+ throw new UrlDownloadError("cancelled", false, "Download cancelled");
70998
+ }
70999
+ let createdLock = false;
71000
+ try {
71001
+ mkdirSync5(lockPath);
71002
+ createdLock = true;
71003
+ } catch (error) {
71004
+ if (error.code !== "EEXIST") throw error;
71005
+ }
71006
+ if (createdLock) {
71007
+ const owner = `${CACHE_LOCK_OWNER_PREFIX}${randomUUID2()}`;
71008
+ try {
71009
+ mkdirSync5(join9(lockPath, owner));
71010
+ const entries2 = readdirSync3(lockPath);
71011
+ if (entries2.length === 1 && entries2[0] === owner) {
71012
+ return () => releaseOwnedCachePathLock(lockPath, owner);
71013
+ }
71014
+ rmdirSync(join9(lockPath, owner));
71015
+ removeCacheLockDirectoryIfEmpty(lockPath);
71016
+ continue;
71017
+ } catch (error) {
71018
+ if (error.code === "ENOENT") continue;
71019
+ throw error;
71020
+ }
71021
+ }
71022
+ let observedLock;
71023
+ try {
71024
+ observedLock = observeCachePathLock(lockPath);
71025
+ } catch (error) {
71026
+ if (error.code === "ENOENT") continue;
71027
+ throw error;
71028
+ }
71029
+ if (Date.now() - observedLock.stats.mtimeMs > CACHE_LOCK_STALE_MS) {
71030
+ if (observedLock.owner) {
71031
+ try {
71032
+ rmdirSync(join9(lockPath, observedLock.owner));
71033
+ } catch (error) {
71034
+ if (error.code === "ENOENT") continue;
71035
+ throw error;
71036
+ }
71037
+ removeCacheLockDirectoryIfEmpty(lockPath);
71038
+ continue;
71039
+ }
71040
+ const reclaimPath = join9(lockPath, CACHE_LOCK_RECLAIM_NAME);
71041
+ try {
71042
+ mkdirSync5(reclaimPath);
71043
+ } catch (error) {
71044
+ const code = error.code;
71045
+ if (code === "EEXIST" || code === "ENOENT") continue;
71046
+ throw error;
71047
+ }
71048
+ try {
71049
+ const currentLock = observeCachePathLock(lockPath);
71050
+ if (sameCachePathLock(currentLock, observedLock)) {
71051
+ rmdirSync(reclaimPath);
71052
+ removeCacheLockDirectoryIfEmpty(lockPath);
71053
+ } else {
71054
+ rmdirSync(reclaimPath);
71055
+ }
71056
+ } catch (error) {
71057
+ if (error.code !== "ENOENT") throw error;
71058
+ }
71059
+ continue;
71060
+ }
71061
+ if (Date.now() - startedAt >= timeoutMs) {
71062
+ throw new UrlDownloadError(
71063
+ "timeout",
71064
+ true,
71065
+ `Download cache lock timeout after ${timeoutMs / 1e3}s`
71066
+ );
71067
+ }
71068
+ await waitForCacheLock(signal);
71069
+ }
70714
71070
  }
70715
71071
  function assertAllowedDownloadUrl(url, redirect) {
70716
71072
  try {
@@ -70753,31 +71109,335 @@ async function fetchWithValidatedRedirects(initialUrl, controller) {
70753
71109
  assertAllowedDownloadUrl(currentUrl, redirects > 0);
70754
71110
  const response = await fetch(currentUrl, {
70755
71111
  signal: controller.signal,
70756
- redirect: "manual"
71112
+ redirect: "manual",
71113
+ headers: { "accept-encoding": "identity" }
70757
71114
  });
70758
- if (!REDIRECT_STATUSES.has(response.status)) return response;
71115
+ if (!REDIRECT_STATUSES.has(response.status)) return { response, finalUrl: currentUrl };
70759
71116
  await cancelResponseBody(response);
70760
71117
  currentUrl = resolveRedirectUrl(response, currentUrl, redirects);
70761
71118
  }
70762
71119
  }
70763
- async function fetchToPartial(url, partialPath, controller) {
70764
- const response = await fetchWithValidatedRedirects(url, controller);
71120
+ async function fetchPublicHttpsText(url, options) {
71121
+ const timeoutMs = options.timeoutMs ?? 15e3;
71122
+ if (!Number.isSafeInteger(options.maxBytes) || options.maxBytes <= 0) {
71123
+ throw new RangeError("maxBytes must be a positive safe integer");
71124
+ }
71125
+ assertPublicHttpsUrl(url);
71126
+ const controller = new AbortController();
71127
+ let timedOut = false;
71128
+ let callerAborted = options.signal?.aborted ?? false;
71129
+ const onCallerAbort = () => {
71130
+ callerAborted = true;
71131
+ controller.abort();
71132
+ };
71133
+ options.signal?.addEventListener("abort", onCallerAbort, { once: true });
71134
+ const timeoutId = setTimeout(() => {
71135
+ timedOut = true;
71136
+ controller.abort();
71137
+ }, timeoutMs);
71138
+ try {
71139
+ if (callerAborted) {
71140
+ throw new UrlDownloadError("cancelled", false, "Text fetch cancelled");
71141
+ }
71142
+ const { response } = await fetchWithValidatedRedirects(url, controller);
71143
+ if (!response.ok) {
71144
+ await cancelResponseBody(response);
71145
+ throw classifyHttpFailure(response.status);
71146
+ }
71147
+ if (!response.body) return "";
71148
+ let declaredLength;
71149
+ try {
71150
+ declaredLength = parseDeclaredLength(response);
71151
+ } catch (error) {
71152
+ await cancelResponseBody(response);
71153
+ throw error;
71154
+ }
71155
+ const contentEncoding = response.headers.get("content-encoding")?.trim().toLowerCase();
71156
+ const expectedBytes = !contentEncoding || contentEncoding === "identity" ? declaredLength : void 0;
71157
+ if (declaredLength !== void 0 && declaredLength > options.maxBytes) {
71158
+ await cancelResponseBody(response);
71159
+ throw new UrlDownloadError(
71160
+ "length_mismatch",
71161
+ false,
71162
+ "Text response exceeded the configured byte limit",
71163
+ response.status
71164
+ );
71165
+ }
71166
+ const reader = response.body.getReader();
71167
+ const chunks = [];
71168
+ let receivedBytes = 0;
71169
+ for (; ; ) {
71170
+ const { done, value } = await reader.read();
71171
+ if (done) break;
71172
+ receivedBytes += value.byteLength;
71173
+ if (receivedBytes > options.maxBytes) {
71174
+ await reader.cancel();
71175
+ throw new UrlDownloadError(
71176
+ "length_mismatch",
71177
+ false,
71178
+ "Text response exceeded the configured byte limit",
71179
+ response.status,
71180
+ { receivedBytes }
71181
+ );
71182
+ }
71183
+ chunks.push(value);
71184
+ }
71185
+ if (expectedBytes !== void 0 && receivedBytes !== expectedBytes) {
71186
+ throw new UrlDownloadError(
71187
+ "length_mismatch",
71188
+ true,
71189
+ "Text response byte count did not match its declared length",
71190
+ response.status,
71191
+ { expectedBytes, receivedBytes }
71192
+ );
71193
+ }
71194
+ return new TextDecoder().decode(Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))));
71195
+ } catch (error) {
71196
+ if (callerAborted) {
71197
+ throw new UrlDownloadError("cancelled", false, "Text fetch cancelled");
71198
+ }
71199
+ if (timedOut) {
71200
+ throw new UrlDownloadError("timeout", true, `Text fetch timeout after ${timeoutMs / 1e3}s`);
71201
+ }
71202
+ throw classifyDownloadFailure(error);
71203
+ } finally {
71204
+ clearTimeout(timeoutId);
71205
+ options.signal?.removeEventListener("abort", onCallerAbort);
71206
+ controller.abort();
71207
+ }
71208
+ }
71209
+ function parseDeclaredLength(response) {
71210
+ const raw = response.headers.get("content-length");
71211
+ if (raw === null) return void 0;
71212
+ if (!/^\d+$/.test(raw.trim())) {
71213
+ throw new UrlDownloadError(
71214
+ "length_mismatch",
71215
+ true,
71216
+ "Download response Content-Length is malformed",
71217
+ response.status,
71218
+ { status: response.status }
71219
+ );
71220
+ }
71221
+ const value = Number(raw);
71222
+ if (!Number.isSafeInteger(value) || value < 0) {
71223
+ throw new UrlDownloadError(
71224
+ "length_mismatch",
71225
+ true,
71226
+ "Download response Content-Length is out of range",
71227
+ response.status,
71228
+ { status: response.status }
71229
+ );
71230
+ }
71231
+ return value;
71232
+ }
71233
+ function classifyRangeDisposition(response) {
71234
+ const contentRange = response.headers.get("content-range");
71235
+ if (response.status === 206) {
71236
+ const match2 = contentRange?.match(/^bytes (\d+)-(\d+)\/(\d+|\*)$/i);
71237
+ if (!match2) return "malformed_206";
71238
+ const start2 = Number(match2[1]);
71239
+ const end2 = Number(match2[2]);
71240
+ const total2 = match2[3] === "*" ? void 0 : Number(match2[3]);
71241
+ if (!Number.isSafeInteger(start2) || !Number.isSafeInteger(end2) || start2 < 0 || end2 < start2 || total2 !== void 0 && (!Number.isSafeInteger(total2) || total2 <= end2)) {
71242
+ return "malformed_206";
71243
+ }
71244
+ return "unsolicited_206";
71245
+ }
71246
+ if (response.status !== 200 || contentRange === null) return "none";
71247
+ const match = contentRange.match(/^bytes (\d+)-(\d+)\/(\d+)$/i);
71248
+ const contentLength = response.headers.get("content-length")?.trim();
71249
+ const contentEncoding = response.headers.get("content-encoding")?.trim().toLowerCase();
71250
+ if (!match || !contentLength || !/^\d+$/.test(contentLength)) {
71251
+ return "content_range_on_200";
71252
+ }
71253
+ const start = Number(match[1]);
71254
+ const end = Number(match[2]);
71255
+ const total = Number(match[3]);
71256
+ const declaredLength = Number(contentLength);
71257
+ return Number.isSafeInteger(start) && Number.isSafeInteger(end) && Number.isSafeInteger(total) && Number.isSafeInteger(declaredLength) && start === 0 && total > 0 && end === total - 1 && declaredLength === total && (!contentEncoding || contentEncoding === "identity") ? "full_object_200" : "content_range_on_200";
71258
+ }
71259
+ function looksLikeRemoteErrorDocument(prefix) {
71260
+ const text2 = prefix.toString("utf8").replace(/^\uFEFF?\s*/, "").toLowerCase();
71261
+ return text2.startsWith("<!doctype html") || text2.startsWith("<html") || text2.startsWith("<head") || text2.startsWith("<body") || text2.startsWith("<error") || /^\{\s*"(?:error|message|detail|code|status)"\s*:/i.test(text2) || /^<\?xml\b/.test(text2) && /<(?:html|error)\b/.test(text2);
71262
+ }
71263
+ function normalizeCallerSha256(value) {
71264
+ if (value === void 0) return void 0;
71265
+ const normalized2 = value.trim().toLowerCase();
71266
+ if (!/^[a-f0-9]{64}$/.test(normalized2)) {
71267
+ throw new UrlDownloadError(
71268
+ "hash_mismatch",
71269
+ false,
71270
+ "Caller-provided SHA-256 checksum is malformed"
71271
+ );
71272
+ }
71273
+ return normalized2;
71274
+ }
71275
+ function expectedResponseSha256(response, callerSha256) {
71276
+ if (callerSha256) return { value: callerSha256, encoding: "hex", source: "caller" };
71277
+ const amazonChecksum = response.headers.get("x-amz-checksum-sha256")?.trim();
71278
+ const amazonChecksumType = response.headers.get("x-amz-checksum-type")?.trim().toUpperCase();
71279
+ if (amazonChecksum && amazonChecksumType !== "COMPOSITE") {
71280
+ return { value: amazonChecksum, encoding: "base64", source: "server" };
71281
+ }
71282
+ const digest = response.headers.get("digest");
71283
+ const sha256Digest = digest?.match(/(?:^|,)\s*sha-256=:?([^,:\s]+):?/i)?.[1];
71284
+ return sha256Digest ? { value: sha256Digest, encoding: "base64", source: "server" } : null;
71285
+ }
71286
+ function checksumMismatchError(source, status, telemetry) {
71287
+ return new UrlDownloadError(
71288
+ "hash_mismatch",
71289
+ source === "server",
71290
+ "Download payload checksum did not match",
71291
+ status,
71292
+ telemetry,
71293
+ true
71294
+ );
71295
+ }
71296
+ async function fetchToPartial(url, partialPath, controller, options) {
71297
+ const { response, finalUrl } = await fetchWithValidatedRedirects(url, controller);
71298
+ const finalIdentity = safeDownloadUrlIdentity(finalUrl);
71299
+ const rangeDisposition = classifyRangeDisposition(response);
71300
+ if (rangeDisposition !== "none" && rangeDisposition !== "full_object_200") {
71301
+ await cancelResponseBody(response);
71302
+ throw new UrlDownloadError(
71303
+ "range_protocol",
71304
+ true,
71305
+ rangeDisposition === "malformed_206" ? "Download received a malformed unsolicited partial response" : "Download received an unsolicited partial response",
71306
+ response.status,
71307
+ {
71308
+ finalHost: finalIdentity.host,
71309
+ status: response.status,
71310
+ rangeDisposition
71311
+ }
71312
+ );
71313
+ }
70765
71314
  if (!response.ok) {
70766
71315
  try {
70767
71316
  await response.body?.cancel();
70768
71317
  } catch {
70769
71318
  }
70770
- throw classifyHttpFailure(response.status, response.statusText);
71319
+ const classified = classifyHttpFailure(response.status);
71320
+ throw new UrlDownloadError(
71321
+ classified.kind,
71322
+ classified.retryable,
71323
+ classified.message,
71324
+ classified.status,
71325
+ { finalHost: finalIdentity.host, status: response.status, rangeDisposition }
71326
+ );
70771
71327
  }
70772
71328
  if (!response.body) {
70773
- throw new UrlDownloadError("empty_body", true, "Download response body is empty");
71329
+ throw new UrlDownloadError(
71330
+ "empty_body",
71331
+ true,
71332
+ "Download response body is empty",
71333
+ response.status,
71334
+ {
71335
+ finalHost: finalIdentity.host,
71336
+ status: response.status
71337
+ }
71338
+ );
70774
71339
  }
70775
- const fileStream = createWriteStream(partialPath, { flags: "wx" });
71340
+ let declaredLength;
71341
+ try {
71342
+ declaredLength = parseDeclaredLength(response);
71343
+ } catch (error) {
71344
+ await cancelResponseBody(response);
71345
+ if (error instanceof UrlDownloadError) {
71346
+ throw new UrlDownloadError(error.kind, error.retryable, error.message, error.status, {
71347
+ ...error.telemetry,
71348
+ finalHost: finalIdentity.host,
71349
+ rangeDisposition
71350
+ });
71351
+ }
71352
+ throw error;
71353
+ }
71354
+ const contentEncoding = response.headers.get("content-encoding")?.trim().toLowerCase();
71355
+ const expectedBytes = !contentEncoding || contentEncoding === "identity" ? declaredLength : void 0;
71356
+ let receivedBytes = 0;
71357
+ const sha256 = createHash("sha256");
71358
+ const md5 = createHash("md5");
71359
+ const prefixChunks = [];
71360
+ let prefixBytes = 0;
71361
+ const inspector = new Transform({
71362
+ transform(chunk, _encoding, callback) {
71363
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
71364
+ receivedBytes += bytes.length;
71365
+ sha256.update(bytes);
71366
+ md5.update(bytes);
71367
+ if (prefixBytes < 1024) {
71368
+ const remaining = 1024 - prefixBytes;
71369
+ const sample = bytes.subarray(0, remaining);
71370
+ prefixChunks.push(sample);
71371
+ prefixBytes += sample.length;
71372
+ }
71373
+ callback(null, bytes);
71374
+ }
71375
+ });
70776
71376
  const readableStream = Readable.fromWeb(response.body);
70777
- await pipeline(readableStream, fileStream);
70778
- if (statSync4(partialPath).size === 0) {
70779
- throw new UrlDownloadError("empty_body", true, "Download response body contained zero bytes");
71377
+ const fileStream = createWriteStream(partialPath, { flags: "wx" });
71378
+ await pipeline(readableStream, inspector, fileStream);
71379
+ const localSize = statSync4(partialPath).size;
71380
+ const sha256Bytes = sha256.digest();
71381
+ const localSha256 = sha256Bytes.toString("hex");
71382
+ const md5Base64 = md5.digest("base64");
71383
+ const telemetry = {
71384
+ finalHost: finalIdentity.host,
71385
+ status: response.status,
71386
+ expectedBytes,
71387
+ receivedBytes,
71388
+ rangeDisposition,
71389
+ localSize,
71390
+ localSha256
71391
+ };
71392
+ if (receivedBytes === 0 || localSize === 0) {
71393
+ throw new UrlDownloadError(
71394
+ "empty_body",
71395
+ true,
71396
+ "Download response body contained zero bytes",
71397
+ response.status,
71398
+ telemetry
71399
+ );
71400
+ }
71401
+ if (localSize !== receivedBytes || expectedBytes !== void 0 && receivedBytes !== expectedBytes) {
71402
+ throw new UrlDownloadError(
71403
+ "length_mismatch",
71404
+ true,
71405
+ "Download response byte count did not match its declared length",
71406
+ response.status,
71407
+ telemetry
71408
+ );
70780
71409
  }
71410
+ const prefix = Buffer.concat(prefixChunks);
71411
+ if (looksLikeRemoteErrorDocument(prefix)) {
71412
+ throw new UrlDownloadError(
71413
+ "invalid_payload",
71414
+ false,
71415
+ "Download returned an HTML or JSON error document",
71416
+ response.status,
71417
+ telemetry
71418
+ );
71419
+ }
71420
+ const expectedSha256 = expectedResponseSha256(response, options.expectedSha256);
71421
+ const checksumMatches = expectedSha256 === null || (expectedSha256.encoding === "base64" ? sha256Bytes.toString("base64") === expectedSha256.value : localSha256 === expectedSha256.value);
71422
+ const contentMd5 = response.headers.get("content-md5")?.trim();
71423
+ if (!checksumMatches) {
71424
+ throw checksumMismatchError(expectedSha256?.source ?? "server", response.status, telemetry);
71425
+ }
71426
+ if (expectedSha256 === null && contentMd5 && md5Base64 !== contentMd5) {
71427
+ throw checksumMismatchError("server", response.status, telemetry);
71428
+ }
71429
+ const etag = response.headers.get("etag")?.trim();
71430
+ return {
71431
+ finalHost: finalIdentity.host,
71432
+ status: response.status,
71433
+ expectedBytes,
71434
+ receivedBytes,
71435
+ rangeDisposition,
71436
+ etagFingerprint: etag ? createHash("sha256").update(etag).digest("hex") : void 0,
71437
+ etagWeak: etag ? /^W\//i.test(etag) : void 0,
71438
+ localSize,
71439
+ localSha256
71440
+ };
70781
71441
  }
70782
71442
  function syncAndPublishPartial(partialPath, localPath) {
70783
71443
  const fd = openSync(partialPath, "r+");
@@ -70786,14 +71446,35 @@ function syncAndPublishPartial(partialPath, localPath) {
70786
71446
  } finally {
70787
71447
  closeSync(fd);
70788
71448
  }
70789
- if (hasCompleteFile(localPath)) return;
70790
71449
  try {
70791
- renameSync2(partialPath, localPath);
71450
+ linkSync(partialPath, localPath);
71451
+ unlinkSync(partialPath);
71452
+ return "published";
70792
71453
  } catch (error) {
70793
- if (!hasCompleteFile(localPath)) throw error;
71454
+ const code = error.code;
71455
+ if (code !== "EEXIST") throw error;
71456
+ let winner;
71457
+ try {
71458
+ winner = lstatSync(localPath);
71459
+ } catch (inspectionError) {
71460
+ if (inspectionError.code !== "ENOENT") throw inspectionError;
71461
+ throw new UrlDownloadError(
71462
+ "filesystem",
71463
+ true,
71464
+ "Concurrent cache artifact disappeared before validation"
71465
+ );
71466
+ }
71467
+ if (!winner.isFile() || winner.size === 0) throw error;
71468
+ return "race_reused";
70794
71469
  }
70795
71470
  }
70796
- async function runDownloadAttempt(url, localPath, timeoutMs, signal) {
71471
+ function emitDownloadTelemetry(options, event) {
71472
+ try {
71473
+ options.onTelemetry?.(event);
71474
+ } catch {
71475
+ }
71476
+ }
71477
+ async function runDownloadAttempt(url, localPath, timeoutMs, attempt, options, signal) {
70797
71478
  const attemptDir = mkdtempSync(join9(dirname6(localPath), ".hf-download-"));
70798
71479
  const partialPath = join9(attemptDir, "payload");
70799
71480
  const controller = new AbortController();
@@ -70808,21 +71489,91 @@ async function runDownloadAttempt(url, localPath, timeoutMs, signal) {
70808
71489
  timedOut = true;
70809
71490
  controller.abort();
70810
71491
  }, timeoutMs);
71492
+ const identity = safeDownloadUrlIdentity(url);
70811
71493
  try {
70812
71494
  if (callerAborted) {
70813
71495
  throw new UrlDownloadError("cancelled", false, "Download cancelled");
70814
71496
  }
70815
- await fetchToPartial(url, partialPath, controller);
70816
- syncAndPublishPartial(partialPath, localPath);
71497
+ const integrity = await fetchToPartial(url, partialPath, controller, options);
71498
+ let outcome = syncAndPublishPartial(partialPath, localPath);
71499
+ let publishedIntegrity = integrity;
71500
+ if (outcome === "race_reused") {
71501
+ let inspection;
71502
+ try {
71503
+ inspection = await inspectExistingFile(localPath);
71504
+ } catch (error) {
71505
+ if (error.code !== "ENOENT") throw error;
71506
+ throw new UrlDownloadError(
71507
+ "filesystem",
71508
+ true,
71509
+ "Concurrent cache artifact disappeared before validation",
71510
+ integrity.status,
71511
+ integrity
71512
+ );
71513
+ }
71514
+ publishedIntegrity = {
71515
+ ...integrity,
71516
+ localSize: inspection.localSize,
71517
+ localSha256: inspection.localSha256
71518
+ };
71519
+ if (!localInspectionMatchesOptions(inspection, options)) {
71520
+ if (looksLikeRemoteErrorDocument(inspection.prefix)) {
71521
+ throw new UrlDownloadError(
71522
+ "invalid_payload",
71523
+ false,
71524
+ "Concurrent download published an HTML or JSON error document",
71525
+ integrity.status,
71526
+ publishedIntegrity
71527
+ );
71528
+ }
71529
+ throw checksumMismatchError("caller", integrity.status, publishedIntegrity);
71530
+ }
71531
+ }
71532
+ emitDownloadTelemetry(options, {
71533
+ urlFingerprint: identity.urlFingerprint,
71534
+ initialHost: identity.host,
71535
+ attempt,
71536
+ outcome,
71537
+ ...publishedIntegrity
71538
+ });
70817
71539
  return localPath;
70818
71540
  } catch (error) {
70819
71541
  if (callerAborted) {
70820
- throw new UrlDownloadError("cancelled", false, "Download cancelled");
71542
+ const classified2 = new UrlDownloadError("cancelled", false, "Download cancelled");
71543
+ emitDownloadTelemetry(options, {
71544
+ urlFingerprint: identity.urlFingerprint,
71545
+ initialHost: identity.host,
71546
+ attempt,
71547
+ outcome: "attempt_failed",
71548
+ failureKind: classified2.kind
71549
+ });
71550
+ throw classified2;
70821
71551
  }
70822
71552
  if (timedOut) {
70823
- throw new UrlDownloadError("timeout", true, `Download timeout after ${timeoutMs / 1e3}s`);
71553
+ const classified2 = new UrlDownloadError(
71554
+ "timeout",
71555
+ true,
71556
+ `Download timeout after ${timeoutMs / 1e3}s`
71557
+ );
71558
+ emitDownloadTelemetry(options, {
71559
+ urlFingerprint: identity.urlFingerprint,
71560
+ initialHost: identity.host,
71561
+ attempt,
71562
+ outcome: "attempt_failed",
71563
+ failureKind: classified2.kind
71564
+ });
71565
+ throw classified2;
70824
71566
  }
70825
- throw classifyDownloadFailure(error);
71567
+ const classified = classifyDownloadFailure(error);
71568
+ emitDownloadTelemetry(options, {
71569
+ urlFingerprint: identity.urlFingerprint,
71570
+ initialHost: identity.host,
71571
+ attempt,
71572
+ outcome: "attempt_failed",
71573
+ failureKind: classified.kind,
71574
+ ...classified.telemetry
71575
+ });
71576
+ throw classified;
70826
71577
  } finally {
70827
71578
  clearTimeout(timeoutId);
70828
71579
  signal?.removeEventListener("abort", onCallerAbort);
@@ -70830,22 +71581,114 @@ async function runDownloadAttempt(url, localPath, timeoutMs, signal) {
70830
71581
  rmSync2(attemptDir, { recursive: true, force: true });
70831
71582
  }
70832
71583
  }
70833
- async function downloadWithRetry(url, localPath, timeoutMs, signal, onTransientRetry) {
71584
+ async function downloadWithRetry(url, localPath, timeoutMs, signal, onTransientRetry, options = {}) {
70834
71585
  const maxTransientRetries = 1;
70835
71586
  for (let attempt = 0; ; attempt += 1) {
70836
71587
  try {
70837
- return await runDownloadAttempt(url, localPath, timeoutMs, signal);
71588
+ return await runDownloadAttempt(url, localPath, timeoutMs, attempt + 1, options, signal);
70838
71589
  } catch (error) {
70839
71590
  const classified = classifyDownloadFailure(error);
70840
- if (!classified.retryable || attempt >= maxTransientRetries) throw classified;
70841
- onTransientRetry?.(classified);
71591
+ if (!classified.locallyRetryable || attempt >= maxTransientRetries) throw classified;
71592
+ if (classified.retryable) onTransientRetry?.(classified);
71593
+ const identity = safeDownloadUrlIdentity(url);
71594
+ emitDownloadTelemetry(options, {
71595
+ urlFingerprint: identity.urlFingerprint,
71596
+ initialHost: identity.host,
71597
+ attempt: attempt + 1,
71598
+ outcome: "retrying",
71599
+ failureKind: classified.kind,
71600
+ ...classified.telemetry
71601
+ });
71602
+ }
71603
+ }
71604
+ }
71605
+ async function inspectExistingFile(path2) {
71606
+ const sha256 = createHash("sha256");
71607
+ const prefixChunks = [];
71608
+ let prefixBytes = 0;
71609
+ let localSize = 0;
71610
+ for await (const chunk of createReadStream2(path2)) {
71611
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
71612
+ localSize += bytes.length;
71613
+ sha256.update(bytes);
71614
+ if (prefixBytes < 1024) {
71615
+ const sample = bytes.subarray(0, 1024 - prefixBytes);
71616
+ prefixChunks.push(sample);
71617
+ prefixBytes += sample.length;
70842
71618
  }
70843
71619
  }
71620
+ return {
71621
+ localSize,
71622
+ localSha256: sha256.digest("hex"),
71623
+ prefix: Buffer.concat(prefixChunks)
71624
+ };
71625
+ }
71626
+ function localInspectionMatchesOptions(inspection, options) {
71627
+ const expectedSha256 = options.expectedSha256?.trim().toLowerCase();
71628
+ return inspection.localSize > 0 && !looksLikeRemoteErrorDocument(inspection.prefix) && (!expectedSha256 || inspection.localSha256 === expectedSha256);
70844
71629
  }
70845
- async function downloadToTemp(url, destDir, timeoutMs = 3e5, signal, onTransientRetry) {
71630
+ function sameCacheEntry(before3, after2) {
71631
+ return sameFileIdentity(before3, after2) && before3.size === after2.size && before3.mtimeMs === after2.mtimeMs;
71632
+ }
71633
+ async function reuseOrInvalidateCachedFile(url, localPath, timeoutMs, signal, options) {
71634
+ const releaseLock = await acquireCachePathLock(localPath, timeoutMs, signal);
71635
+ try {
71636
+ for (let pass = 0; pass < 3; pass += 1) {
71637
+ let before3;
71638
+ try {
71639
+ before3 = lstatSync(localPath);
71640
+ } catch (error) {
71641
+ if (error.code === "ENOENT") continue;
71642
+ throw error;
71643
+ }
71644
+ if (!before3.isFile() || before3.size === 0) {
71645
+ rmSync2(localPath, { recursive: before3.isDirectory(), force: true });
71646
+ return false;
71647
+ }
71648
+ let inspection;
71649
+ try {
71650
+ inspection = await inspectExistingFile(localPath);
71651
+ } catch (error) {
71652
+ if (error.code === "ENOENT") continue;
71653
+ throw error;
71654
+ }
71655
+ let after2;
71656
+ try {
71657
+ after2 = lstatSync(localPath);
71658
+ } catch (error) {
71659
+ if (error.code === "ENOENT") continue;
71660
+ throw error;
71661
+ }
71662
+ if (!sameCacheEntry(before3, after2)) continue;
71663
+ if (localInspectionMatchesOptions(inspection, options)) {
71664
+ const identity = safeDownloadUrlIdentity(url);
71665
+ emitDownloadTelemetry(options, {
71666
+ urlFingerprint: identity.urlFingerprint,
71667
+ initialHost: identity.host,
71668
+ attempt: 0,
71669
+ outcome: "cache_hit",
71670
+ receivedBytes: inspection.localSize,
71671
+ localSize: inspection.localSize,
71672
+ localSha256: inspection.localSha256,
71673
+ rangeDisposition: "none"
71674
+ });
71675
+ return true;
71676
+ }
71677
+ rmSync2(localPath, { force: true });
71678
+ return false;
71679
+ }
71680
+ return false;
71681
+ } finally {
71682
+ releaseLock();
71683
+ }
71684
+ }
71685
+ async function downloadToTemp(url, destDir, timeoutMs = 3e5, signal, onTransientRetry, options = {}) {
70846
71686
  assertPublicHttpsUrl(url);
71687
+ const expectedSha256 = normalizeCallerSha256(options.expectedSha256);
71688
+ const normalizedOptions = { ...options, expectedSha256 };
70847
71689
  const cacheKey = `${url}\0${destDir}`;
70848
- const inFlightKey = `${cacheKey}\0${timeoutMs}\0${signalScopeKey(signal)}`;
71690
+ const validationScope = expectedSha256 ?? "";
71691
+ const inFlightKey = `${cacheKey}\0${timeoutMs}\0${signalScopeKey(signal)}\0${validationScope}`;
70849
71692
  const inFlight2 = inFlightDownloads.get(inFlightKey);
70850
71693
  if (inFlight2) {
70851
71694
  return inFlight2;
@@ -70853,10 +71696,35 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5, signal, onTransient
70853
71696
  if (!existsSync9(destDir)) {
70854
71697
  mkdirSync5(destDir, { recursive: true });
70855
71698
  }
70856
- const filename = getFilenameFromUrl(url);
71699
+ const filename = getFilenameFromUrl(url, validationScope);
70857
71700
  const localPath = join9(destDir, filename);
70858
- if (hasCompleteFile(localPath)) return localPath;
70859
- const downloadPromise = downloadWithRetry(url, localPath, timeoutMs, signal, onTransientRetry);
71701
+ const downloadPromise = (async () => {
71702
+ const cacheStartedAt = Date.now();
71703
+ const reused = await reuseOrInvalidateCachedFile(
71704
+ url,
71705
+ localPath,
71706
+ timeoutMs,
71707
+ signal,
71708
+ normalizedOptions
71709
+ );
71710
+ const remainingTimeoutMs = timeoutMs - (Date.now() - cacheStartedAt);
71711
+ if (remainingTimeoutMs <= 0) {
71712
+ throw new UrlDownloadError(
71713
+ "timeout",
71714
+ true,
71715
+ `Download cache inspection timeout after ${timeoutMs / 1e3}s`
71716
+ );
71717
+ }
71718
+ if (reused) return localPath;
71719
+ return downloadWithRetry(
71720
+ url,
71721
+ localPath,
71722
+ remainingTimeoutMs,
71723
+ signal,
71724
+ onTransientRetry,
71725
+ normalizedOptions
71726
+ );
71727
+ })();
70860
71728
  const trackedDownload = downloadPromise.finally(() => {
70861
71729
  inFlightDownloads.delete(inFlightKey);
70862
71730
  });
@@ -70866,7 +71734,7 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5, signal, onTransient
70866
71734
  function isHttpUrl(path2) {
70867
71735
  return path2.startsWith("http://") || path2.startsWith("https://");
70868
71736
  }
70869
- var inFlightDownloads, signalScopes, nextSignalScope, UrlDownloadError, RETRYABLE_NETWORK_CODES, NON_PUBLIC_IPV4_ADDRESSES, NON_PUBLIC_IPV6_ADDRESSES, REDIRECT_STATUSES, MAX_REDIRECTS;
71737
+ var inFlightDownloads, signalScopes, nextSignalScope, UrlDownloadError, RETRYABLE_NETWORK_CODES, NON_PUBLIC_IPV4_ADDRESSES, NON_PUBLIC_IPV6_ADDRESSES, CACHE_LOCK_POLL_MS, CACHE_LOCK_STALE_MS, CACHE_LOCK_RECLAIM_NAME, CACHE_LOCK_OWNER_PREFIX, REDIRECT_STATUSES, MAX_REDIRECTS;
70870
71738
  var init_urlDownloader = __esm({
70871
71739
  "../engine/src/utils/urlDownloader.ts"() {
70872
71740
  "use strict";
@@ -70874,16 +71742,20 @@ var init_urlDownloader = __esm({
70874
71742
  signalScopes = /* @__PURE__ */ new WeakMap();
70875
71743
  nextSignalScope = 1;
70876
71744
  UrlDownloadError = class extends Error {
70877
- constructor(kind, retryable, message, status) {
71745
+ constructor(kind, retryable, message, status, telemetry, locallyRetryable = retryable) {
70878
71746
  super(message);
70879
71747
  this.kind = kind;
70880
71748
  this.retryable = retryable;
70881
71749
  this.status = status;
71750
+ this.telemetry = telemetry;
71751
+ this.locallyRetryable = locallyRetryable;
70882
71752
  this.name = "UrlDownloadError";
70883
71753
  }
70884
71754
  kind;
70885
71755
  retryable;
70886
71756
  status;
71757
+ telemetry;
71758
+ locallyRetryable;
70887
71759
  };
70888
71760
  RETRYABLE_NETWORK_CODES = /* @__PURE__ */ new Set(["ECONNRESET", "ECONNREFUSED", "ETIMEDOUT", "EAI_AGAIN"]);
70889
71761
  NON_PUBLIC_IPV4_ADDRESSES = new BlockList();
@@ -70919,6 +71791,10 @@ var init_urlDownloader = __esm({
70919
71791
  ]) {
70920
71792
  NON_PUBLIC_IPV6_ADDRESSES.addSubnet(network, prefix, "ipv6");
70921
71793
  }
71794
+ CACHE_LOCK_POLL_MS = 10;
71795
+ CACHE_LOCK_STALE_MS = 5 * 6e4;
71796
+ CACHE_LOCK_RECLAIM_NAME = ".hf-reclaim";
71797
+ CACHE_LOCK_OWNER_PREFIX = ".hf-owner-";
70922
71798
  REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
70923
71799
  MAX_REDIRECTS = 5;
70924
71800
  }
@@ -75531,8 +76407,62 @@ function containsTimelineCall2(node, timelineVar) {
75531
76407
  function rangeOf2(node) {
75532
76408
  return typeof node.start === "number" && typeof node.end === "number" ? [node.start, node.end] : void 0;
75533
76409
  }
76410
+ function isSafeDefaultExpression2(node, earlierParams) {
76411
+ let safe = true;
76412
+ const visit = (current2, parent, key2) => {
76413
+ if (!isNode3(current2) || !safe) return;
76414
+ if (!SAFE_DEFAULT_NODES2.has(current2.type)) {
76415
+ safe = false;
76416
+ return;
76417
+ }
76418
+ if (current2.type === "UnaryExpression" && current2.operator === "delete") {
76419
+ safe = false;
76420
+ return;
76421
+ }
76422
+ if (current2.type === "Identifier") {
76423
+ const nonValue = parent && key2 ? isNonValueIdentifierSlot2(parent, key2) : false;
76424
+ if (!nonValue && current2.name !== "undefined" && !earlierParams.has(current2.name)) {
76425
+ safe = false;
76426
+ }
76427
+ return;
76428
+ }
76429
+ for (const childKey of Object.keys(current2)) {
76430
+ if (SKIP_KEYS2.has(childKey)) continue;
76431
+ const child = current2[childKey];
76432
+ if (Array.isArray(child)) {
76433
+ for (const item of child) visit(item, current2, childKey);
76434
+ } else {
76435
+ visit(child, current2, childKey);
76436
+ }
76437
+ }
76438
+ };
76439
+ visit(node);
76440
+ return safe;
76441
+ }
76442
+ function supportedParam2(param, earlier) {
76443
+ if (param.type === "Identifier") return { name: param.name };
76444
+ if (param.type !== "AssignmentPattern" || param.left?.type !== "Identifier") return null;
76445
+ if (!isSafeDefaultExpression2(param.right, earlier)) return null;
76446
+ return { name: param.left.name, defaultExpression: param.right };
76447
+ }
76448
+ function supportedParams2(fn) {
76449
+ if (SUPPORTED_PARAMS_CACHE2.has(fn)) return SUPPORTED_PARAMS_CACHE2.get(fn) ?? null;
76450
+ const params = [];
76451
+ const earlier = /* @__PURE__ */ new Set();
76452
+ for (const param of fn.params ?? []) {
76453
+ const parsed = supportedParam2(param, earlier);
76454
+ if (!parsed) {
76455
+ SUPPORTED_PARAMS_CACHE2.set(fn, null);
76456
+ return null;
76457
+ }
76458
+ params.push(parsed);
76459
+ earlier.add(parsed.name);
76460
+ }
76461
+ SUPPORTED_PARAMS_CACHE2.set(fn, params);
76462
+ return params;
76463
+ }
75534
76464
  function isShapeEligible2(fn) {
75535
- return isFunctionNode3(fn) && fn.body?.type === "BlockStatement" && !(fn.params ?? []).some((p2) => p2.type !== "Identifier");
76465
+ return isFunctionNode3(fn) && fn.body?.type === "BlockStatement" && supportedParams2(fn) !== null;
75536
76466
  }
75537
76467
  function callsAny2(node, names) {
75538
76468
  let hit = false;
@@ -75582,20 +76512,55 @@ function timelineBuildingNames2(candidates, timelineVar) {
75582
76512
  function bump2(counts, key2) {
75583
76513
  counts.set(key2, (counts.get(key2) ?? 0) + 1);
75584
76514
  }
76515
+ function undefinedIdentifier2() {
76516
+ return { type: "Identifier", name: "undefined" };
76517
+ }
76518
+ function isExplicitUndefined2(node) {
76519
+ return node?.type === "Identifier" && node.name === "undefined" || node?.type === "UnaryExpression" && node.operator === "void" && node.argument?.type === "Literal" && node.argument.value === 0;
76520
+ }
76521
+ function resolveHelperBindings2(call, params) {
76522
+ if (call.arguments?.some((arg) => arg?.type === "SpreadElement")) return null;
76523
+ const bindings = /* @__PURE__ */ new Map();
76524
+ for (let i2 = 0; i2 < params.length; i2++) {
76525
+ const param = params[i2];
76526
+ const arg = call.arguments?.[i2];
76527
+ if (arg && !isExplicitUndefined2(arg)) {
76528
+ bindings.set(param.name, arg);
76529
+ } else if (param.defaultExpression) {
76530
+ bindings.set(param.name, substituteParams2(cloneNode3(param.defaultExpression), bindings));
76531
+ } else {
76532
+ bindings.set(param.name, undefinedIdentifier2());
76533
+ }
76534
+ }
76535
+ return bindings;
76536
+ }
76537
+ function statementHelperCall2(node, names) {
76538
+ if (node.type !== "ExpressionStatement") return void 0;
76539
+ const expression = node.expression;
76540
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier") {
76541
+ return void 0;
76542
+ }
76543
+ return names.has(expression.callee.name) ? expression : void 0;
76544
+ }
75585
76545
  function safelyDroppable2(program, candidates) {
75586
76546
  const names = new Set(candidates.keys());
75587
76547
  const totalIds = /* @__PURE__ */ new Map();
75588
76548
  const stmtCalls = /* @__PURE__ */ new Map();
76549
+ const unbindable = /* @__PURE__ */ new Set();
75589
76550
  walkNodes2(program, (n2) => {
75590
76551
  if (n2.type === "Identifier" && names.has(n2.name)) bump2(totalIds, n2.name);
75591
- const e3 = n2.type === "ExpressionStatement" ? n2.expression : void 0;
75592
- if (e3?.type === "CallExpression" && e3.callee?.type === "Identifier" && names.has(e3.callee.name)) {
75593
- bump2(stmtCalls, e3.callee.name);
75594
- }
76552
+ const call = statementHelperCall2(n2, names);
76553
+ if (!call) return;
76554
+ bump2(stmtCalls, call.callee.name);
76555
+ const fn = candidates.get(call.callee.name);
76556
+ const params = fn && supportedParams2(fn);
76557
+ if (!params || !resolveHelperBindings2(call, params)) unbindable.add(call.callee.name);
75595
76558
  });
75596
76559
  const safe = /* @__PURE__ */ new Map();
75597
76560
  for (const [name, fn] of candidates) {
75598
- if ((totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) safe.set(name, fn);
76561
+ if (!unbindable.has(name) && (totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) {
76562
+ safe.set(name, fn);
76563
+ }
75599
76564
  }
75600
76565
  return safe;
75601
76566
  }
@@ -75638,11 +76603,11 @@ function expandBody2(bodyStmts, bindings, prov, ctx) {
75638
76603
  }
75639
76604
  function inlineHelper2(call, ctx) {
75640
76605
  const fn = ctx.helpers.get(call.callee.name);
75641
- const bindings = /* @__PURE__ */ new Map();
75642
- (fn.params ?? []).forEach((p2, i2) => {
75643
- const arg = call.arguments?.[i2];
75644
- if (arg) bindings.set(p2.name, arg);
75645
- });
76606
+ if (!fn) return null;
76607
+ const params = supportedParams2(fn);
76608
+ if (!params) return null;
76609
+ const bindings = resolveHelperBindings2(call, params);
76610
+ if (!bindings) return null;
75646
76611
  const prov = {
75647
76612
  kind: "helper",
75648
76613
  fn: call.callee.name,
@@ -77117,7 +78082,7 @@ function extractGsapLabels(script) {
77117
78082
  return [];
77118
78083
  }
77119
78084
  }
77120
- var PROPERTY_GROUPS2, PROP_TO_GROUP2, SKIP_KEYS2, FUNCTION_TYPES2, GSAP_METHODS3, MAX_DEPTH2, MAX_ITERS2, roundPercentage2, GSAP_METHODS22, QUERY_METHODS2, ITERATION_METHODS2, SCOPE_NODE_TYPES2, CONST_NODES2, MATH_FNS2, MATH_CONSTS2, BUILTIN_VAR_KEYS2, DROPPED_VAR_KEYS2, EXTRAS_KEYS2, PERCENTAGE_KEY_RE2, GSAP_DEFAULT_DURATION2;
78085
+ var PROPERTY_GROUPS2, PROP_TO_GROUP2, SKIP_KEYS2, FUNCTION_TYPES2, GSAP_METHODS3, MAX_DEPTH2, MAX_ITERS2, SAFE_DEFAULT_NODES2, SUPPORTED_PARAMS_CACHE2, roundPercentage2, GSAP_METHODS22, QUERY_METHODS2, ITERATION_METHODS2, SCOPE_NODE_TYPES2, CONST_NODES2, MATH_FNS2, MATH_CONSTS2, BUILTIN_VAR_KEYS2, DROPPED_VAR_KEYS2, EXTRAS_KEYS2, PERCENTAGE_KEY_RE2, GSAP_DEFAULT_DURATION2;
77121
78086
  var init_gsapParserAcorn = __esm({
77122
78087
  "../parsers/dist/gsapParserAcorn.js"() {
77123
78088
  "use strict";
@@ -77144,6 +78109,23 @@ var init_gsapParserAcorn = __esm({
77144
78109
  GSAP_METHODS3 = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
77145
78110
  MAX_DEPTH2 = 8;
77146
78111
  MAX_ITERS2 = 512;
78112
+ SAFE_DEFAULT_NODES2 = /* @__PURE__ */ new Set([
78113
+ "ArrayExpression",
78114
+ "BinaryExpression",
78115
+ "ChainExpression",
78116
+ "ConditionalExpression",
78117
+ "Identifier",
78118
+ "Literal",
78119
+ "LogicalExpression",
78120
+ "MemberExpression",
78121
+ "ObjectExpression",
78122
+ "Property",
78123
+ "SpreadElement",
78124
+ "TemplateElement",
78125
+ "TemplateLiteral",
78126
+ "UnaryExpression"
78127
+ ]);
78128
+ SUPPORTED_PARAMS_CACHE2 = /* @__PURE__ */ new WeakMap();
77147
78129
  roundPercentage2 = (percentage) => Math.round(percentage * 10) / 10;
77148
78130
  GSAP_METHODS22 = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
77149
78131
  QUERY_METHODS2 = /* @__PURE__ */ new Set(["querySelector", "querySelectorAll"]);
@@ -77184,7 +78166,7 @@ __export(dist_exports2, {
77184
78166
  });
77185
78167
  import postcss2 from "postcss";
77186
78168
  import postcss22 from "postcss";
77187
- import { existsSync as existsSync22, readFileSync as readFileSync4, readdirSync as readdirSync3 } from "fs";
78169
+ import { existsSync as existsSync22, readFileSync as readFileSync4, readdirSync as readdirSync4 } from "fs";
77188
78170
  import { dirname as dirname7, extname as extname3, join as join22, relative as relative3, resolve as resolve8 } from "path";
77189
78171
  import { execFile } from "child_process";
77190
78172
  import { existsSync as existsSync11 } from "fs";
@@ -79013,6 +79995,7 @@ async function probeIsHevc(ffprobePath, filePath) {
79013
79995
  "stream=codec_name",
79014
79996
  "-of",
79015
79997
  "json",
79998
+ "--",
79016
79999
  filePath
79017
80000
  ]);
79018
80001
  return hasHevcStream(JSON.parse(stdout2));
@@ -79169,7 +80152,7 @@ async function lintProject(projectDir, entryFile) {
79169
80152
  if (!entryFile && existsSync22(compositionsDir)) {
79170
80153
  const collectHtmlFiles = (dir, rel) => {
79171
80154
  const out = [];
79172
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
80155
+ for (const entry of readdirSync4(dir, { withFileTypes: true })) {
79173
80156
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
79174
80157
  if (entry.isDirectory()) {
79175
80158
  if (!rel && entry.name === "components") continue;
@@ -79230,7 +80213,7 @@ function lintProjectAudioFiles(projectDir, htmlSources) {
79230
80213
  const findings = [];
79231
80214
  let audioFiles;
79232
80215
  try {
79233
- audioFiles = readdirSync3(projectDir).filter(
80216
+ audioFiles = readdirSync4(projectDir).filter(
79234
80217
  (f3) => AUDIO_EXTENSIONS.has(extname3(f3).toLowerCase())
79235
80218
  );
79236
80219
  } catch {
@@ -79349,7 +80332,7 @@ function lintTextureMaskAssetNotFound(projectDir, htmlSources) {
79349
80332
  function lintMultipleRootCompositions(projectDir) {
79350
80333
  const findings = [];
79351
80334
  try {
79352
- const rootHtmlFiles = readdirSync3(projectDir).filter(
80335
+ const rootHtmlFiles = readdirSync4(projectDir).filter(
79353
80336
  (file) => file.endsWith(".html") && !file.startsWith("._")
79354
80337
  );
79355
80338
  const rootCompositions = [];
@@ -83972,13 +84955,13 @@ var init_htmlTemplate = __esm({
83972
84955
  });
83973
84956
 
83974
84957
  // ../engine/src/services/extractionCache.ts
83975
- import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
84958
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
83976
84959
  import {
83977
84960
  existsSync as existsSync13,
83978
84961
  lstatSync as lstatSync2,
83979
84962
  mkdirSync as mkdirSync6,
83980
- readdirSync as readdirSync4,
83981
- renameSync as renameSync3,
84963
+ readdirSync as readdirSync5,
84964
+ renameSync as renameSync2,
83982
84965
  rmSync as rmSync3,
83983
84966
  statSync as statSync5,
83984
84967
  utimesSync,
@@ -84020,7 +85003,7 @@ function lookupCacheEntry(rootDir, input2) {
84020
85003
  return { entry: { dir, keyHash }, hit: complete };
84021
85004
  }
84022
85005
  function partialCacheEntryDir(entry) {
84023
- return `${entry.dir}.partial-${process.pid}-${randomUUID2().slice(0, 8)}`;
85006
+ return `${entry.dir}.partial-${process.pid}-${randomUUID3().slice(0, 8)}`;
84024
85007
  }
84025
85008
  function isTargetExistsRenameError(err) {
84026
85009
  const code = err.code;
@@ -84038,7 +85021,7 @@ function publishCacheEntry(entry, partialDir) {
84038
85021
  return { dir: partialDir, published: false };
84039
85022
  }
84040
85023
  try {
84041
- renameSync3(partialDir, entry.dir);
85024
+ renameSync2(partialDir, entry.dir);
84042
85025
  return { dir: entry.dir, published: true };
84043
85026
  } catch (err) {
84044
85027
  if (!isTargetExistsRenameError(err)) return { dir: partialDir, published: false };
@@ -84051,7 +85034,7 @@ function publishCacheEntry(entry, partialDir) {
84051
85034
  return { dir: partialDir, published: false };
84052
85035
  }
84053
85036
  try {
84054
- renameSync3(partialDir, entry.dir);
85037
+ renameSync2(partialDir, entry.dir);
84055
85038
  return { dir: entry.dir, published: true };
84056
85039
  } catch {
84057
85040
  return adoptPublishedWinner(entry, partialDir) ?? { dir: partialDir, published: false };
@@ -84080,7 +85063,7 @@ function directorySizeBytes(path2) {
84080
85063
  let total = 0;
84081
85064
  let children;
84082
85065
  try {
84083
- children = readdirSync4(path2);
85066
+ children = readdirSync5(path2);
84084
85067
  } catch {
84085
85068
  return 0;
84086
85069
  }
@@ -84138,7 +85121,7 @@ function gcExtractionCache(rootDir, opts) {
84138
85121
  try {
84139
85122
  const now = Date.now();
84140
85123
  const entries2 = [];
84141
- for (const child of readdirSync4(rootDir, { withFileTypes: true })) {
85124
+ for (const child of readdirSync5(rootDir, { withFileTypes: true })) {
84142
85125
  if (!child.isDirectory() || !isCacheLikeChild(child.name)) continue;
84143
85126
  const entry = collectGcEntry(
84144
85127
  join11(rootDir, child.name),
@@ -84168,7 +85151,7 @@ function rehydrateCacheEntry(entry, options) {
84168
85151
  const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${options.format}`;
84169
85152
  const framePaths = /* @__PURE__ */ new Map();
84170
85153
  const suffix = `.${options.format}`;
84171
- const files = readdirSync4(entry.dir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(suffix)).sort();
85154
+ const files = readdirSync5(entry.dir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(suffix)).sort();
84172
85155
  files.forEach((file, idx) => {
84173
85156
  framePaths.set(idx, join11(entry.dir, file));
84174
85157
  });
@@ -84197,7 +85180,7 @@ var init_extractionCache = __esm({
84197
85180
  });
84198
85181
 
84199
85182
  // ../engine/src/services/videoFrameExtractor.ts
84200
- import { copyFileSync as copyFileSync2, existsSync as existsSync14, linkSync, mkdirSync as mkdirSync7, readdirSync as readdirSync5, rmSync as rmSync4 } from "fs";
85183
+ import { copyFileSync as copyFileSync2, existsSync as existsSync14, linkSync as linkSync2, mkdirSync as mkdirSync7, readdirSync as readdirSync6, rmSync as rmSync4 } from "fs";
84201
85184
  import { isAbsolute as isAbsolute4, join as join12, posix as posix3, resolve as resolve10, sep as sep3 } from "path";
84202
85185
  function isVideoFrameFormat(value) {
84203
85186
  return typeof value === "string" && VIDEO_FRAME_FORMATS.includes(value);
@@ -84281,6 +85264,14 @@ function classifyVideoExtractionError(error) {
84281
85264
  diagnostic
84282
85265
  );
84283
85266
  }
85267
+ if (error.kind === "invalid_payload") {
85268
+ return new VideoSourceExtractionError(
85269
+ "invalid_media",
85270
+ false,
85271
+ "Video source download returned a non-media payload",
85272
+ diagnostic
85273
+ );
85274
+ }
84284
85275
  if (error.retryable) {
84285
85276
  return new VideoSourceExtractionError(
84286
85277
  "download_transient",
@@ -84578,7 +85569,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
84578
85569
  );
84579
85570
  }
84580
85571
  const framePaths = /* @__PURE__ */ new Map();
84581
- const files = readdirSync5(videoOutputDir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(`.${format}`)).sort();
85572
+ const files = readdirSync6(videoOutputDir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(`.${format}`)).sort();
84582
85573
  files.forEach((file, index) => {
84583
85574
  framePaths.set(index, join12(videoOutputDir, file));
84584
85575
  });
@@ -84755,7 +85746,7 @@ function resolveFrameFormat(metadata, requested) {
84755
85746
  }
84756
85747
  function extractedFrameFileNames(outputDir, format) {
84757
85748
  const suffix = `.${format}`;
84758
- return readdirSync5(outputDir).filter((file) => file.startsWith(FRAME_FILENAME_PREFIX) && file.endsWith(suffix)).sort();
85749
+ return readdirSync6(outputDir).filter((file) => file.startsWith(FRAME_FILENAME_PREFIX) && file.endsWith(suffix)).sort();
84759
85750
  }
84760
85751
  function extractedFramesFromDirectory(work, outputDir, srcPath, fps) {
84761
85752
  const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${work.format}`;
@@ -84779,7 +85770,7 @@ function frameFileName(frameNumber, format) {
84779
85770
  }
84780
85771
  function linkOrCopyFrame(src, dest) {
84781
85772
  try {
84782
- linkSync(src, dest);
85773
+ linkSync2(src, dest);
84783
85774
  } catch {
84784
85775
  copyFileSync2(src, dest);
84785
85776
  }
@@ -84964,7 +85955,8 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
84964
85955
  downloadDir,
84965
85956
  void 0,
84966
85957
  signal,
84967
- () => recordTransientRetries(1)
85958
+ () => recordTransientRetries(1),
85959
+ { onTelemetry: writeUrlDownloadTelemetry }
84968
85960
  );
84969
85961
  }
84970
85962
  if (!existsSync14(videoPath)) {
@@ -86021,7 +87013,7 @@ var init_videoFrameInjector = __esm({
86021
87013
  });
86022
87014
 
86023
87015
  // ../engine/src/services/audioVolumeEnvelope.ts
86024
- import { readFileSync as readFileSync6, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "fs";
87016
+ import { readFileSync as readFileSync6, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "fs";
86025
87017
  import { randomBytes } from "crypto";
86026
87018
  function parseWavLayout(buffer) {
86027
87019
  if (buffer.length < 12 || buffer.toString("ascii", 0, 4) !== "RIFF") return null;
@@ -86083,7 +87075,7 @@ function applyVolumeEnvelopeToWav(wavPath, keyframes, trackStart, baseVolume) {
86083
87075
  }
86084
87076
  const tempPath = `${wavPath}.${randomBytes(6).toString("hex")}.tmp`;
86085
87077
  writeFileSync5(tempPath, buffer);
86086
- renameSync4(tempPath, wavPath);
87078
+ renameSync3(tempPath, wavPath);
86087
87079
  return true;
86088
87080
  } catch {
86089
87081
  return false;
@@ -86224,15 +87216,17 @@ function probeFailure(message, elementId) {
86224
87216
  detail: boundedDetail(`Audio probe failed for element ${elementId}: ${message}`)
86225
87217
  };
86226
87218
  }
86227
- function downloadFailure(message, elementId) {
86228
- const invalidSource = /(?:invalid URL|only HTTPS|private\/reserved|HTTP (?:400|401|403|404|405|410|422)\b)/i.test(
87219
+ function downloadFailure(error, elementId) {
87220
+ const message = error instanceof Error ? error.message : String(error);
87221
+ const invalidSource = error instanceof UrlDownloadError ? error.kind === "http_not_found" || error.kind === "http_rejected" || error.kind === "invalid_payload" || error.kind === "cancelled" : /(?:invalid URL|only HTTPS|private\/reserved|HTTP (?:400|401|403|404|405|410|422)\b)/i.test(
86229
87222
  message
86230
87223
  );
87224
+ const retryable = error instanceof UrlDownloadError ? error.retryable : !invalidSource;
86231
87225
  return {
86232
87226
  stage: "download",
86233
87227
  reason: "download_failed",
86234
87228
  owner: invalidSource ? "user" : "system",
86235
- retryable: !invalidSource,
87229
+ retryable,
86236
87230
  elementId,
86237
87231
  detail: boundedDetail(`Download failed for audio element ${elementId}: ${message}`)
86238
87232
  };
@@ -86579,11 +87573,11 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
86579
87573
  }
86580
87574
  if (isHttpUrl(srcPath)) {
86581
87575
  try {
86582
- srcPath = await downloadToTemp(srcPath, workDir);
87576
+ srcPath = await downloadToTemp(srcPath, workDir, void 0, signal, void 0, {
87577
+ onTelemetry: writeUrlDownloadTelemetry
87578
+ });
86583
87579
  } catch (err) {
86584
- failures.push(
86585
- downloadFailure(err instanceof Error ? err.message : String(err), element.id)
86586
- );
87580
+ failures.push(downloadFailure(err, element.id));
86587
87581
  return;
86588
87582
  }
86589
87583
  }
@@ -86863,7 +87857,7 @@ var init_readWebGlVendorInfoFromCanvas = __esm({
86863
87857
 
86864
87858
  // ../engine/src/services/parallelCoordinator.ts
86865
87859
  import { cpus, freemem } from "os";
86866
- import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync6 } from "fs";
87860
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9, readdirSync as readdirSync7 } from "fs";
86867
87861
  import { copyFile, readFile, rename } from "fs/promises";
86868
87862
  import { join as join15 } from "path";
86869
87863
  import { getHeapStatistics } from "v8";
@@ -87289,7 +88283,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
87289
88283
  if (!existsSync16(task.outputDir)) {
87290
88284
  continue;
87291
88285
  }
87292
- const files = readdirSync6(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
88286
+ const files = readdirSync7(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
87293
88287
  const copyTasks = files.map(async (file) => {
87294
88288
  const sourcePath = join15(task.outputDir, file);
87295
88289
  const targetPath = join15(outputDir, file);
@@ -88804,7 +89798,7 @@ var init_shaderTransitions = __esm({
88804
89798
  });
88805
89799
 
88806
89800
  // ../engine/src/services/hdrCapture.ts
88807
- import { existsSync as existsSync18, readdirSync as readdirSync7 } from "fs";
89801
+ import { existsSync as existsSync18, readdirSync as readdirSync8 } from "fs";
88808
89802
  import { join as join17 } from "path";
88809
89803
  import { homedir as homedir3 } from "os";
88810
89804
  function linearToPQ(L2) {
@@ -88923,7 +89917,7 @@ function float16ToPqRgb(rawBuffer, bytesPerRow, width, height) {
88923
89917
  function resolveHeadedChromePath() {
88924
89918
  const baseDir = join17(homedir3(), ".cache", "puppeteer", "chrome");
88925
89919
  if (!existsSync18(baseDir)) return void 0;
88926
- const versions = readdirSync7(baseDir).sort().reverse();
89920
+ const versions = readdirSync8(baseDir).sort().reverse();
88927
89921
  for (const version2 of versions) {
88928
89922
  const candidates = [
88929
89923
  join17(
@@ -89086,6 +90080,7 @@ __export(src_exports, {
89086
90080
  decodePng: () => decodePng,
89087
90081
  decodePngToRgb48le: () => decodePngToRgb48le,
89088
90082
  defaultExtractCacheDir: () => defaultExtractCacheDir,
90083
+ deriveBeginFrameProbeTimeTicks: () => deriveBeginFrameProbeTimeTicks,
89089
90084
  detectGpuEncoder: () => detectGpuEncoder,
89090
90085
  detectTransfer: () => detectTransfer,
89091
90086
  diffGpuParityFrames: () => diffGpuParityFrames,
@@ -89105,6 +90100,7 @@ __export(src_exports, {
89105
90100
  extractVideoFramesRange: () => extractVideoFramesRange,
89106
90101
  extractVideoMetadata: () => extractVideoMetadata,
89107
90102
  extractionFrameCountForDuration: () => extractionFrameCountForDuration,
90103
+ fetchPublicHttpsText: () => fetchPublicHttpsText,
89108
90104
  float16ToPqRgb: () => float16ToPqRgb,
89109
90105
  formatFfmpegError: () => formatFfmpegError,
89110
90106
  getCapturePerfSummary: () => getCapturePerfSummary,
@@ -89178,6 +90174,7 @@ __export(src_exports, {
89178
90174
  roundedRectAlpha: () => roundedRectAlpha,
89179
90175
  runFfmpeg: () => runFfmpeg,
89180
90176
  runVideoExtractionWithRetry: () => runVideoExtractionWithRetry,
90177
+ safeDownloadUrlIdentity: () => safeDownloadUrlIdentity,
89181
90178
  sampleRgb48le: () => sampleRgb48le,
89182
90179
  scaleProtocolTimeoutForComposition: () => scaleProtocolTimeoutForComposition,
89183
90180
  selectVerifySampleIndicesForTask: () => selectVerifySampleIndicesForTask,
@@ -89190,7 +90187,8 @@ __export(src_exports, {
89190
90187
  validateEngineConfigSnapshot: () => validateEngineConfigSnapshot,
89191
90188
  verifyDiskDrawElementSamples: () => verifyDiskDrawElementSamples,
89192
90189
  verifyGpuParity: () => verifyGpuParity,
89193
- writeCapturedFrame: () => writeCapturedFrame
90190
+ writeCapturedFrame: () => writeCapturedFrame,
90191
+ writeUrlDownloadTelemetry: () => writeUrlDownloadTelemetry
89194
90192
  });
89195
90193
  var init_src = __esm({
89196
90194
  "../engine/src/index.ts"() {
@@ -89748,10 +90746,10 @@ var init_canary2 = __esm({
89748
90746
 
89749
90747
  // src/telemetry/transport.ts
89750
90748
  import { spawn as spawn5 } from "child_process";
89751
- import { randomUUID as randomUUID3 } from "crypto";
90749
+ import { randomUUID as randomUUID4 } from "crypto";
89752
90750
  function enqueue(event, properties, distinctId) {
89753
90751
  eventQueue.push({
89754
- uuid: randomUUID3(),
90752
+ uuid: randomUUID4(),
89755
90753
  event,
89756
90754
  distinctId,
89757
90755
  properties,
@@ -93231,12 +94229,12 @@ var init_ffmpeg = __esm({
93231
94229
  });
93232
94230
 
93233
94231
  // src/utils/download.ts
93234
- import { createWriteStream as createWriteStream2, renameSync as renameSync5, unlinkSync } from "fs";
94232
+ import { createWriteStream as createWriteStream2, renameSync as renameSync4, unlinkSync as unlinkSync2 } from "fs";
93235
94233
  import { get as httpsGet } from "https";
93236
94234
  import { pipeline as pipeline2 } from "stream/promises";
93237
94235
  function removePartialFile(path2) {
93238
94236
  try {
93239
- unlinkSync(path2);
94237
+ unlinkSync2(path2);
93240
94238
  } catch {
93241
94239
  }
93242
94240
  }
@@ -93267,7 +94265,7 @@ function downloadFile(url, dest, options = {}) {
93267
94265
  const file = createWriteStream2(tmp);
93268
94266
  responsePipelineStarted = true;
93269
94267
  pipeline2(res, file).then(() => {
93270
- renameSync5(tmp, dest);
94268
+ renameSync4(tmp, dest);
93271
94269
  resolve77();
93272
94270
  }).catch((err) => {
93273
94271
  removePartialFile(tmp);
@@ -93500,10 +94498,10 @@ __export(transcribe_exports, {
93500
94498
  wrapWhisperTimeoutError: () => wrapWhisperTimeoutError
93501
94499
  });
93502
94500
  import { execFileSync as execFileSync5 } from "child_process";
93503
- import { existsSync as existsSync25, readFileSync as readFileSync14, mkdirSync as mkdirSync12, unlinkSync as unlinkSync2 } from "fs";
94501
+ import { existsSync as existsSync25, readFileSync as readFileSync14, mkdirSync as mkdirSync12, unlinkSync as unlinkSync3 } from "fs";
93504
94502
  import { join as join21, extname as extname5 } from "path";
93505
94503
  import { tmpdir as tmpdir3 } from "os";
93506
- import { randomUUID as randomUUID4 } from "crypto";
94504
+ import { randomUUID as randomUUID5 } from "crypto";
93507
94505
  function detectLanguage(whisperPath, modelPath2, wavPath) {
93508
94506
  try {
93509
94507
  const output = execFileSync5(whisperPath, ["--model", modelPath2, "--detect-language", wavPath], {
@@ -93573,6 +94571,7 @@ function getMediaDurationSeconds(filePath) {
93573
94571
  "format=duration",
93574
94572
  "-of",
93575
94573
  "default=noprint_wrappers=1:nokey=1",
94574
+ "--",
93576
94575
  filePath
93577
94576
  ],
93578
94577
  { encoding: "utf-8", timeout: 1e4 }
@@ -93644,7 +94643,7 @@ function isVideoFile(filePath) {
93644
94643
  return VIDEO_EXTENSIONS.has(extname5(filePath).toLowerCase());
93645
94644
  }
93646
94645
  function tempWavPath() {
93647
- return join21(tmpdir3(), `hyperframes-audio-${process.pid}-${randomUUID4()}.wav`);
94646
+ return join21(tmpdir3(), `hyperframes-audio-${process.pid}-${randomUUID5()}.wav`);
93648
94647
  }
93649
94648
  function extractAudio(videoPath) {
93650
94649
  const ffmpegPath = findFFmpeg();
@@ -93670,7 +94669,7 @@ function isWav16kMono(filePath) {
93670
94669
  if (!ffprobePath) return false;
93671
94670
  const raw = execFileSync5(
93672
94671
  ffprobePath,
93673
- ["-v", "quiet", "-print_format", "json", "-show_streams", filePath],
94672
+ ["-v", "quiet", "-print_format", "json", "-show_streams", "--", filePath],
93674
94673
  { encoding: "utf-8", timeout: 1e4 }
93675
94674
  );
93676
94675
  const parsed = JSON.parse(raw);
@@ -93802,7 +94801,7 @@ async function transcribe(inputPath, outputDir, options) {
93802
94801
  const speechOnsetSeconds = detectSpeechOnset(wavPath);
93803
94802
  if (wavPath !== inputPath) {
93804
94803
  try {
93805
- unlinkSync2(wavPath);
94804
+ unlinkSync3(wavPath);
93806
94805
  } catch {
93807
94806
  }
93808
94807
  }
@@ -93872,7 +94871,7 @@ __export(normalize_exports, {
93872
94871
  stripBeforeOnset: () => stripBeforeOnset,
93873
94872
  wordsToCues: () => wordsToCues
93874
94873
  });
93875
- import { readFileSync as readFileSync15, readdirSync as readdirSync8, writeFileSync as writeFileSync9 } from "fs";
94874
+ import { readFileSync as readFileSync15, readdirSync as readdirSync9, writeFileSync as writeFileSync9 } from "fs";
93876
94875
  import { extname as extname6, join as join23 } from "path";
93877
94876
  function detectFormat(filePath) {
93878
94877
  const ext = extname6(filePath).toLowerCase();
@@ -94150,7 +95149,7 @@ function patchCaptionHtml(dir, words) {
94150
95149
  const wordsJson = JSON.stringify(words, null, 2).replace(/\n/g, "\n ");
94151
95150
  let htmlFiles;
94152
95151
  try {
94153
- htmlFiles = readdirSync8(dir, { withFileTypes: true, recursive: true }).filter((e3) => e3.isFile() && e3.name.endsWith(".html")).map((e3) => join23(e3.parentPath, e3.name));
95152
+ htmlFiles = readdirSync9(dir, { withFileTypes: true, recursive: true }).filter((e3) => e3.isFile() && e3.name.endsWith(".html")).map((e3) => join23(e3.parentPath, e3.name));
94154
95153
  } catch {
94155
95154
  return;
94156
95155
  }
@@ -94640,9 +95639,9 @@ import { execFile as execFile3 } from "child_process";
94640
95639
  import { createHash as createHash3 } from "crypto";
94641
95640
  import {
94642
95641
  existsSync as existsSync27,
94643
- readdirSync as readdirSync9,
95642
+ readdirSync as readdirSync10,
94644
95643
  readFileSync as readFileSync18,
94645
- renameSync as renameSync6,
95644
+ renameSync as renameSync5,
94646
95645
  statSync as statSync8,
94647
95646
  writeFileSync as writeFileSync11
94648
95647
  } from "fs";
@@ -94655,7 +95654,7 @@ function isCoreSkill(name) {
94655
95654
  function listFilesSorted(dir) {
94656
95655
  const out = [];
94657
95656
  const walk = (d2) => {
94658
- for (const name of readdirSync9(d2)) {
95657
+ for (const name of readdirSync10(d2)) {
94659
95658
  if (name === ".DS_Store") continue;
94660
95659
  const p2 = join26(d2, name);
94661
95660
  if (statSync8(p2).isDirectory()) walk(p2);
@@ -94681,7 +95680,7 @@ function hashSkillBundle(skillDir) {
94681
95680
  return { hash: h3.digest("hex").slice(0, 16), files: files.length };
94682
95681
  }
94683
95682
  function buildManifest(skillsRoot, meta) {
94684
- const names = readdirSync9(skillsRoot).filter((n2) => existsSync27(join26(skillsRoot, n2, "SKILL.md"))).sort();
95683
+ const names = readdirSync10(skillsRoot).filter((n2) => existsSync27(join26(skillsRoot, n2, "SKILL.md"))).sort();
94685
95684
  const skills = {};
94686
95685
  for (const name of names) skills[name] = hashSkillBundle(join26(skillsRoot, name));
94687
95686
  return { source: meta.source, skills };
@@ -94697,7 +95696,7 @@ function agentFromDir(dir) {
94697
95696
  }
94698
95697
  function listSubdirs(dir) {
94699
95698
  try {
94700
- return readdirSync9(dir, { withFileTypes: true }).filter((e3) => e3.isDirectory() || e3.isSymbolicLink()).map((e3) => e3.name);
95699
+ return readdirSync10(dir, { withFileTypes: true }).filter((e3) => e3.isDirectory() || e3.isSymbolicLink()).map((e3) => e3.name);
94701
95700
  } catch {
94702
95701
  return [];
94703
95702
  }
@@ -94837,7 +95836,7 @@ function pruneOrphanedLockEntries(names, scope, opts = {}) {
94837
95836
  const mode = statSync8(path2).mode & 511;
94838
95837
  const tmp = `${path2}.tmp`;
94839
95838
  writeFileSync11(tmp, JSON.stringify(lock, null, 2), { mode });
94840
- renameSync6(tmp, path2);
95839
+ renameSync5(tmp, path2);
94841
95840
  return pruned;
94842
95841
  }
94843
95842
  function findRepoManifest(cwd = process.cwd()) {
@@ -95053,7 +96052,7 @@ var init_agentDirs_generated = __esm({
95053
96052
  });
95054
96053
 
95055
96054
  // src/utils/skillsMirror.ts
95056
- import { cpSync, existsSync as existsSync28, mkdirSync as mkdirSync13, readdirSync as readdirSync10, rmSync as rmSync7, symlinkSync } from "fs";
96055
+ import { cpSync, existsSync as existsSync28, mkdirSync as mkdirSync13, readdirSync as readdirSync11, rmSync as rmSync7, symlinkSync } from "fs";
95057
96056
  import { homedir as homedir7 } from "os";
95058
96057
  import { dirname as dirname11, isAbsolute as isAbsolute7, join as join27, relative as relative7 } from "path";
95059
96058
  function resolveBases(home, env) {
@@ -95069,7 +96068,7 @@ function resolveBases(home, env) {
95069
96068
  };
95070
96069
  }
95071
96070
  function listSkillDirs(store) {
95072
- return readdirSync10(store, { withFileTypes: true }).filter(
96071
+ return readdirSync11(store, { withFileTypes: true }).filter(
95073
96072
  (e3) => (e3.isDirectory() || e3.isSymbolicLink()) && existsSync28(join27(store, e3.name, "SKILL.md"))
95074
96073
  ).map((e3) => e3.name);
95075
96074
  }
@@ -97981,7 +98980,7 @@ var init_chunk_W2SBTCO2 = __esm({
97981
98980
  }
97982
98981
  });
97983
98982
 
97984
- // ../studio-server/dist/chunk-I2USK772.js
98983
+ // ../studio-server/dist/chunk-6H3V3WGJ.js
97985
98984
  import { existsSync as existsSync33, statSync as statSync10 } from "fs";
97986
98985
  import { relative as relative8, resolve as resolve19, sep as sep5 } from "path";
97987
98986
  import { execFile as execFile5 } from "child_process";
@@ -98048,6 +99047,7 @@ async function probeMediaMetadata(filePath, runner = execFileRunner) {
98048
99047
  "stream=codec_type,codec_name,profile,pix_fmt,color_space,color_transfer,color_primaries,bits_per_raw_sample:stream_disposition=attached_pic",
98049
99048
  "-of",
98050
99049
  "json",
99050
+ "--",
98051
99051
  filePath
98052
99052
  ],
98053
99053
  { timeout: 15e3, maxBuffer: 1024 * 1024 }
@@ -98184,8 +99184,8 @@ async function scanProjectMediaCodecMap(projectDir, htmlSources, options = {}) {
98184
99184
  return map;
98185
99185
  }
98186
99186
  var execFileRunner, VIDEO_EXT, IMAGE_EXT, AUDIO_EXT, ALPHA_PIX_FMT_RE, BROWSER_HOSTILE_CODECS, PROXY_VARIANT_CONFIG, defaultProbeCache, MAX_PROBE_CACHE_ENTRIES, VIDEO_SRC_RE, PROBE_CONCURRENCY2;
98187
- var init_chunk_I2USK772 = __esm({
98188
- "../studio-server/dist/chunk-I2USK772.js"() {
99187
+ var init_chunk_6H3V3WGJ = __esm({
99188
+ "../studio-server/dist/chunk-6H3V3WGJ.js"() {
98189
99189
  "use strict";
98190
99190
  init_assets();
98191
99191
  init_assetResolution();
@@ -98244,20 +99244,20 @@ var init_chunk_I2USK772 = __esm({
98244
99244
  }
98245
99245
  });
98246
99246
 
98247
- // ../studio-server/dist/chunk-IQAVZUQP.js
99247
+ // ../studio-server/dist/chunk-ZPI6QXJH.js
98248
99248
  import { spawn as spawn8 } from "child_process";
98249
- import { createHash as createHash6, randomUUID as randomUUID5 } from "crypto";
99249
+ import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
98250
99250
  import {
98251
99251
  existsSync as existsSync210,
98252
99252
  mkdirSync as mkdirSync15,
98253
99253
  realpathSync as realpathSync4,
98254
- renameSync as renameSync7,
99254
+ renameSync as renameSync6,
98255
99255
  statSync as statSync22,
98256
99256
  unlinkSync as unlinkSync22,
98257
99257
  utimesSync as utimesSync2
98258
99258
  } from "fs";
98259
99259
  import { basename as basename4, dirname as dirname14, isAbsolute as isAbsolute8, join as join29, relative as relative9, resolve as resolve20, sep as sep6 } from "path";
98260
- import { existsSync as existsSync34, readdirSync as readdirSync11, statSync as statSync11, unlinkSync as unlinkSync3 } from "fs";
99260
+ import { existsSync as existsSync34, readdirSync as readdirSync12, statSync as statSync11, unlinkSync as unlinkSync4 } from "fs";
98261
99261
  import { extname as extname8, join as join30 } from "path";
98262
99262
  function positiveEnvNumber(name, fallback) {
98263
99263
  const parsed = Number(process.env[name]);
@@ -98283,7 +99283,7 @@ function shouldSkipSweep(cacheDir, now, minSweepIntervalMs) {
98283
99283
  function readCacheInventory(cacheDir, protectedPaths, now, staleTempMs) {
98284
99284
  const entries2 = [];
98285
99285
  const staleTemps = [];
98286
- for (const dirent of readdirSync11(cacheDir, { withFileTypes: true })) {
99286
+ for (const dirent of readdirSync12(cacheDir, { withFileTypes: true })) {
98287
99287
  if (!dirent.isFile()) continue;
98288
99288
  const path2 = join30(cacheDir, dirent.name);
98289
99289
  const stat3 = statSync11(path2);
@@ -98309,7 +99309,7 @@ function evictCacheEntries(entries2, staleTemps, now, maxIdleMs, maxBytes) {
98309
99309
  let bytesAfter = bytesBefore;
98310
99310
  const removed = [];
98311
99311
  const remove2 = (entry, countsTowardBudget) => {
98312
- unlinkSync3(entry.path);
99312
+ unlinkSync4(entry.path);
98313
99313
  removed.push(entry.path);
98314
99314
  if (countsTowardBudget) bytesAfter -= entry.size;
98315
99315
  };
@@ -98570,10 +99570,10 @@ async function transcodeToCache(absoluteSourcePath, cachePath2, variant) {
98570
99570
  if (existsSync210(cachePath2)) return cachePath2;
98571
99571
  const cacheDir = dirname14(cachePath2);
98572
99572
  mkdirSync15(cacheDir, { recursive: true });
98573
- const tempPath = join29(cacheDir, `.tmp-${randomUUID5()}-${basename4(cachePath2)}`);
99573
+ const tempPath = join29(cacheDir, `.tmp-${randomUUID6()}-${basename4(cachePath2)}`);
98574
99574
  try {
98575
99575
  await runFfmpeg2(absoluteSourcePath, tempPath, variant);
98576
- renameSync7(tempPath, cachePath2);
99576
+ renameSync6(tempPath, cachePath2);
98577
99577
  maintainProxyCache(cacheDir);
98578
99578
  return cachePath2;
98579
99579
  } finally {
@@ -98610,10 +99610,10 @@ async function resolveProxy(projectDir, absoluteSourcePath, variant = "h264") {
98610
99610
  return promise;
98611
99611
  }
98612
99612
  var DEFAULT_MAX_BYTES, DEFAULT_STALE_TEMP_MS, DEFAULT_MIN_SWEEP_INTERVAL_MS, PROXY_EXTENSIONS, lastSweepAt, PROXY_PARAMS_VERSION, CACHE_DIR_NAME, MAX_CONCURRENT_TRANSCODES, MAX_QUEUED_TRANSCODES, STDERR_TAIL_MAX_CHARS, TRANSCODE_TIMEOUT_MS, FAILURE_CACHE_TTL_MS, MAX_FAILURE_CACHE_ENTRIES, DEFAULT_PROXY_WAIT_TIMEOUT_MS, ProxyTranscodeError, FfmpegUnavailableError, FfmpegMissingFilterError, ProxyCapacityError, ProxySourceOutsideProjectError, ProxyWaitTimeoutError, activeTranscodes, waitQueue, inFlight, failedTranscodes, hdrFilterCheck;
98613
- var init_chunk_IQAVZUQP = __esm({
98614
- "../studio-server/dist/chunk-IQAVZUQP.js"() {
99613
+ var init_chunk_ZPI6QXJH = __esm({
99614
+ "../studio-server/dist/chunk-ZPI6QXJH.js"() {
98615
99615
  "use strict";
98616
- init_chunk_I2USK772();
99616
+ init_chunk_6H3V3WGJ();
98617
99617
  init_ffBinaries();
98618
99618
  DEFAULT_MAX_BYTES = 10 * 1024 * 1024 * 1024;
98619
99619
  DEFAULT_STALE_TEMP_MS = 60 * 60 * 1e3;
@@ -98681,7 +99681,7 @@ var init_chunk_IQAVZUQP = __esm({
98681
99681
  }
98682
99682
  });
98683
99683
 
98684
- // ../studio-server/dist/chunk-JOZUTP73.js
99684
+ // ../studio-server/dist/chunk-LHYV3WLZ.js
98685
99685
  import { resolve as resolve21 } from "path";
98686
99686
  function isAutoProxyEnabled(adapter2) {
98687
99687
  return adapter2.autoProxy !== false;
@@ -98728,11 +99728,11 @@ async function injectMediaCodecMap(html, adapter2, projectDir, compSrcPath, prob
98728
99728
  if (!isAutoProxyEnabled(adapter2)) return html;
98729
99729
  return injectMediaCodecMapIntoHtml(html, projectDir, [{ html, compSrcPath }], probeCache);
98730
99730
  }
98731
- var init_chunk_JOZUTP73 = __esm({
98732
- "../studio-server/dist/chunk-JOZUTP73.js"() {
99731
+ var init_chunk_LHYV3WLZ = __esm({
99732
+ "../studio-server/dist/chunk-LHYV3WLZ.js"() {
98733
99733
  "use strict";
98734
- init_chunk_IQAVZUQP();
98735
- init_chunk_I2USK772();
99734
+ init_chunk_ZPI6QXJH();
99735
+ init_chunk_6H3V3WGJ();
98736
99736
  }
98737
99737
  });
98738
99738
 
@@ -102421,7 +103421,7 @@ var init_gsapWriterAcorn = __esm({
102421
103421
 
102422
103422
  // ../core/dist/fonts/systemFontLocator.js
102423
103423
  import { execFileSync as execFileSync7 } from "child_process";
102424
- import { existsSync as existsSync35, lstatSync as lstatSync3, readdirSync as readdirSync12, realpathSync as realpathSync5 } from "fs";
103424
+ import { existsSync as existsSync35, lstatSync as lstatSync3, readdirSync as readdirSync13, realpathSync as realpathSync5 } from "fs";
102425
103425
  import { homedir as homedir9, platform as platform5 } from "os";
102426
103426
  import { join as join31, resolve as resolve22 } from "path";
102427
103427
  function getAllowedFontDirs() {
@@ -102516,7 +103516,7 @@ function collectFontFileEntries(dir, depth = 0) {
102516
103516
  return [];
102517
103517
  const entries2 = [];
102518
103518
  try {
102519
- for (const entry of readdirSync12(dir, { withFileTypes: true })) {
103519
+ for (const entry of readdirSync13(dir, { withFileTypes: true })) {
102520
103520
  const fullPath = join31(dir, entry.name);
102521
103521
  if (entry.isDirectory()) {
102522
103522
  entries2.push(...collectFontFileEntries(fullPath, depth + 1));
@@ -105455,7 +106455,7 @@ import { Hono as Hono2 } from "hono";
105455
106455
  import { readFile as readFile2 } from "fs/promises";
105456
106456
  import { join as join210 } from "path";
105457
106457
  import { join as join32 } from "path";
105458
- import { readdirSync as readdirSync13 } from "fs";
106458
+ import { readdirSync as readdirSync14 } from "fs";
105459
106459
  import { createHash as createHash7 } from "crypto";
105460
106460
  import { lstatSync as lstatSync4, readFileSync as readFileSync21, readdirSync as readdirSync22 } from "fs";
105461
106461
  import { extname as extname9, isAbsolute as isAbsolute9, relative as relative10, resolve as resolve23 } from "path";
@@ -105473,7 +106473,7 @@ import {
105473
106473
  unlinkSync as unlinkSync23,
105474
106474
  rmSync as rmSync22,
105475
106475
  statSync as statSync12,
105476
- renameSync as renameSync8,
106476
+ renameSync as renameSync7,
105477
106477
  readdirSync as readdirSync42
105478
106478
  } from "fs";
105479
106479
  import { resolve as resolve32, dirname as dirname22, join as join62 } from "path";
@@ -105484,10 +106484,10 @@ import { spawnSync } from "child_process";
105484
106484
  import { mkdtempSync as mkdtempSync3, rmSync as rmSync9, writeFileSync as writeFileSync22 } from "fs";
105485
106485
  import { tmpdir as tmpdir4 } from "os";
105486
106486
  import { basename as basename5, join as join42 } from "path";
105487
- import { mkdirSync as mkdirSync22, readdirSync as readdirSync32, readFileSync as readFileSync32, unlinkSync as unlinkSync4, writeFileSync as writeFileSync32 } from "fs";
106487
+ import { mkdirSync as mkdirSync22, readdirSync as readdirSync32, readFileSync as readFileSync32, unlinkSync as unlinkSync5, writeFileSync as writeFileSync32 } from "fs";
105488
106488
  import { Buffer as Buffer2 } from "buffer";
105489
106489
  import { join as join52, relative as relative22 } from "path";
105490
- import { createHash as createHash22, randomUUID as randomUUID6 } from "crypto";
106490
+ import { createHash as createHash22, randomUUID as randomUUID7 } from "crypto";
105491
106491
  import { existsSync as existsSync37, readFileSync as readFileSync42, realpathSync as realpathSync6 } from "fs";
105492
106492
  import { randomUUID as randomUUID22 } from "crypto";
105493
106493
  import { dirname as dirname15, relative as relative32, resolve as resolve24, sep as sep7 } from "path";
@@ -105532,7 +106532,7 @@ function isInHiddenOrVendorDir(relPath) {
105532
106532
  }
105533
106533
  function walkDir(dir, prefix = "") {
105534
106534
  const files = [];
105535
- for (const entry of readdirSync13(dir, { withFileTypes: true })) {
106535
+ for (const entry of readdirSync14(dir, { withFileTypes: true })) {
105536
106536
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
105537
106537
  if (IGNORE_DIRS.has(entry.name) || shouldIgnoreDir(rel)) continue;
105538
106538
  if (entry.isDirectory()) {
@@ -105838,6 +106838,7 @@ function validateUploadedMedia(filePath, runner = spawnSync) {
105838
106838
  "stream=codec_type",
105839
106839
  "-of",
105840
106840
  "json",
106841
+ "--",
105841
106842
  filePath
105842
106843
  ]);
105843
106844
  if (result.error?.code === "ENOENT") {
@@ -105929,7 +106930,7 @@ function pruneBackups(backupDir, backupKey, keepPerFile) {
105929
106930
  });
105930
106931
  for (const file of matches2.slice(keep)) {
105931
106932
  try {
105932
- unlinkSync4(file);
106933
+ unlinkSync5(file);
105933
106934
  } catch {
105934
106935
  }
105935
106936
  }
@@ -105939,7 +106940,7 @@ function fileContentVersion(content) {
105939
106940
  }
105940
106941
  function createWriteToken(requestToken) {
105941
106942
  const token = requestToken?.trim();
105942
- return token && token.length <= 200 ? token : randomUUID6();
106943
+ return token && token.length <= 200 ? token : randomUUID7();
105943
106944
  }
105944
106945
  function recordFileWriteReceipt(absPath, receipt) {
105945
106946
  const now = Date.now();
@@ -108048,7 +109049,7 @@ function registerFileRoutes(api, adapter2) {
108048
109049
  return c3.json({ error: "already exists" }, 409);
108049
109050
  }
108050
109051
  ensureDir(newAbs);
108051
- renameSync8(res.absPath, newAbs);
109052
+ renameSync7(res.absPath, newAbs);
108052
109053
  const updatedFiles = updateReferences(res.project.dir, res.filePath, body.newPath);
108053
109054
  return c3.json({ ok: true, path: body.newPath, updatedReferences: updatedFiles });
108054
109055
  });
@@ -109650,9 +110651,9 @@ var init_dist9 = __esm({
109650
110651
  init_chunk_X62ASOGO();
109651
110652
  init_chunk_VPA335OG();
109652
110653
  init_chunk_W2SBTCO2();
109653
- init_chunk_JOZUTP73();
109654
- init_chunk_IQAVZUQP();
109655
- init_chunk_I2USK772();
110654
+ init_chunk_LHYV3WLZ();
110655
+ init_chunk_ZPI6QXJH();
110656
+ init_chunk_6H3V3WGJ();
109656
110657
  init_chunk_6XMC64FJ();
109657
110658
  init_chunk_4ETS2LXI();
109658
110659
  init_dist3();
@@ -110193,7 +111194,7 @@ __export(manager_exports2, {
110193
111194
  withInstallLock: () => withInstallLock
110194
111195
  });
110195
111196
  import { execSync as execSync4, spawnSync as spawnSync2 } from "child_process";
110196
- import { existsSync as existsSync38, mkdirSync as mkdirSync17, readdirSync as readdirSync14, rmSync as rmSync10, statSync as statSync13, utimesSync as utimesSync3 } from "fs";
111197
+ import { existsSync as existsSync38, mkdirSync as mkdirSync17, readdirSync as readdirSync15, rmSync as rmSync10, statSync as statSync13, utimesSync as utimesSync3 } from "fs";
110197
111198
  import { basename as basename6 } from "path";
110198
111199
  import { homedir as homedir11 } from "os";
110199
111200
  import { join as join35 } from "path";
@@ -110392,7 +111393,7 @@ function findFromPuppeteerCache() {
110392
111393
  if (!executable) return void 0;
110393
111394
  let versions;
110394
111395
  try {
110395
- versions = [...readdirSync14(PUPPETEER_CACHE_DIR)].sort(compareVersionDirsDescending);
111396
+ versions = [...readdirSync15(PUPPETEER_CACHE_DIR)].sort(compareVersionDirsDescending);
110396
111397
  } catch {
110397
111398
  return void 0;
110398
111399
  }
@@ -111093,7 +112094,7 @@ var init_logger = __esm({
111093
112094
  // ../producer/src/services/fileServer.ts
111094
112095
  import { Hono as Hono3 } from "hono";
111095
112096
  import { serve as serve2 } from "@hono/node-server";
111096
- import { existsSync as existsSync40, realpathSync as realpathSync7, statSync as statSync14, createReadStream as createReadStream2 } from "fs";
112097
+ import { existsSync as existsSync40, realpathSync as realpathSync7, statSync as statSync14, createReadStream as createReadStream3 } from "fs";
111097
112098
  import { readFile as readFile3 } from "fs/promises";
111098
112099
  import { Readable as Readable2 } from "stream";
111099
112100
  import { join as join36, extname as extname10, resolve as resolve27, sep as sep9 } from "path";
@@ -111490,7 +112491,7 @@ function createFileServer2(options) {
111490
112491
  if (rangeRequest.kind === "satisfiable") {
111491
112492
  const { start, end } = rangeRequest;
111492
112493
  const length = end - start + 1;
111493
- const stream2 = createReadStream2(filePath, { start, end });
112494
+ const stream2 = createReadStream3(filePath, { start, end });
111494
112495
  const webStream2 = Readable2.toWeb(stream2);
111495
112496
  return new Response(webStream2, {
111496
112497
  status: 206,
@@ -111502,7 +112503,7 @@ function createFileServer2(options) {
111502
112503
  }
111503
112504
  });
111504
112505
  }
111505
- const stream = createReadStream2(filePath);
112506
+ const stream = createReadStream3(filePath);
111506
112507
  const webStream = Readable2.toWeb(stream);
111507
112508
  return new Response(webStream, {
111508
112509
  status: 200,
@@ -112144,8 +113145,8 @@ import {
112144
113145
  mkdtempSync as mkdtempSync4,
112145
113146
  openSync as openSync5,
112146
113147
  readSync as readSync2,
112147
- readdirSync as readdirSync15,
112148
- renameSync as renameSync9,
113148
+ readdirSync as readdirSync16,
113149
+ renameSync as renameSync8,
112149
113150
  rmSync as rmSync12
112150
113151
  } from "fs";
112151
113152
  import { basename as basename9, dirname as dirname18, extname as extname11, join as join39, resolve as resolve29 } from "path";
@@ -112170,7 +113171,7 @@ function assertReadableNonEmptyFile(path2) {
112170
113171
  function collectDirectoryFiles(root) {
112171
113172
  const files = [];
112172
113173
  const visit = (directory) => {
112173
- for (const entry of readdirSync15(directory, { withFileTypes: true })) {
113174
+ for (const entry of readdirSync16(directory, { withFileTypes: true })) {
112174
113175
  const path2 = join39(directory, entry.name);
112175
113176
  if (entry.isDirectory()) visit(path2);
112176
113177
  else if (entry.isFile()) files.push(path2);
@@ -112185,7 +113186,7 @@ var init_artifactTransaction = __esm({
112185
113186
  "use strict";
112186
113187
  defaultFileSystem = {
112187
113188
  existsSync: existsSync43,
112188
- renameSync: renameSync9,
113189
+ renameSync: renameSync8,
112189
113190
  rmSync: rmSync12
112190
113191
  };
112191
113192
  ArtifactTransaction = class {
@@ -113444,9 +114445,11 @@ var init_ffprobe2 = __esm({
113444
114445
  // ../producer/src/utils/urlDownloader.ts
113445
114446
  var urlDownloader_exports = {};
113446
114447
  __export(urlDownloader_exports, {
113447
- assertPublicHttpsUrl: () => assertPublicHttpsUrl,
113448
114448
  downloadToTemp: () => downloadToTemp,
113449
- isHttpUrl: () => isHttpUrl
114449
+ fetchPublicHttpsText: () => fetchPublicHttpsText,
114450
+ isHttpUrl: () => isHttpUrl,
114451
+ safeDownloadUrlIdentity: () => safeDownloadUrlIdentity,
114452
+ writeUrlDownloadTelemetry: () => writeUrlDownloadTelemetry
113450
114453
  });
113451
114454
  var init_urlDownloader2 = __esm({
113452
114455
  "../producer/src/utils/urlDownloader.ts"() {
@@ -116632,7 +117635,7 @@ __export(fontCompression_exports, {
116632
117635
  fontToDataUri: () => fontToDataUri
116633
117636
  });
116634
117637
  import { createHash as createHash10 } from "crypto";
116635
- import { existsSync as existsSync44, mkdirSync as mkdirSync19, readFileSync as readFileSync26, renameSync as renameSync10, rmSync as rmSync13, writeFileSync as writeFileSync15 } from "fs";
117638
+ import { existsSync as existsSync44, mkdirSync as mkdirSync19, readFileSync as readFileSync26, renameSync as renameSync9, rmSync as rmSync13, writeFileSync as writeFileSync15 } from "fs";
116636
117639
  import { homedir as homedir12, tmpdir as tmpdir5 } from "os";
116637
117640
  import { dirname as dirname19, join as join41 } from "path";
116638
117641
  async function compressToWoff2(input2) {
@@ -116663,7 +117666,7 @@ function cacheCompression(path2, compressed) {
116663
117666
  try {
116664
117667
  mkdirSync19(dirname19(path2), { recursive: true });
116665
117668
  writeFileSync15(tmpPath, compressed, { flag: "wx", mode: 420 });
116666
- renameSync10(tmpPath, path2);
117669
+ renameSync9(tmpPath, path2);
116667
117670
  } catch {
116668
117671
  } finally {
116669
117672
  try {
@@ -117488,7 +118491,7 @@ import {
117488
118491
  existsSync as existsSync46,
117489
118492
  mkdirSync as mkdirSync21,
117490
118493
  readFileSync as readFileSync28,
117491
- renameSync as renameSync11,
118494
+ renameSync as renameSync10,
117492
118495
  rmSync as rmSync14,
117493
118496
  statSync as statSync15
117494
118497
  } from "fs";
@@ -117661,7 +118664,7 @@ async function ensurePreparedWebm(input2) {
117661
118664
  throw new Error("Animated GIF transcode produced an empty output");
117662
118665
  }
117663
118666
  if (!isUsableFile(input2.cachePath)) {
117664
- renameSync11(tmpPath, input2.cachePath);
118667
+ renameSync10(tmpPath, input2.cachePath);
117665
118668
  } else {
117666
118669
  rmSync14(tmpPath, { force: true });
117667
118670
  }
@@ -117980,8 +118983,11 @@ var init_assetMediaType = __esm({
117980
118983
  });
117981
118984
 
117982
118985
  // ../producer/src/services/htmlCompiler.ts
117983
- import { createReadStream as createReadStream3, existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync29 } from "fs";
118986
+ import { createReadStream as createReadStream4, existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync29 } from "fs";
117984
118987
  import { join as join45, dirname as dirname21, resolve as resolve31, basename as basename10 } from "path";
118988
+ function logRemoteDownloadTelemetry(event) {
118989
+ defaultLogger.info("[Compiler] Remote asset download integrity", { ...event });
118990
+ }
117985
118991
  function parseSubCompHtmlForValidity(html) {
117986
118992
  return parseHTML(html).document;
117987
118993
  }
@@ -118141,7 +119147,9 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
118141
119147
  if (isHttpUrl(src)) {
118142
119148
  if (!existsSync48(downloadDir)) mkdirSync23(downloadDir, { recursive: true });
118143
119149
  try {
118144
- filePath = await downloadToTemp(src, downloadDir);
119150
+ filePath = await downloadToTemp(src, downloadDir, void 0, void 0, void 0, {
119151
+ onTelemetry: logRemoteDownloadTelemetry
119152
+ });
118145
119153
  } catch {
118146
119154
  return { duration: 0, resolvedPath: src };
118147
119155
  }
@@ -118669,12 +119677,17 @@ async function downloadAndRewriteUrls(urlSet, html, remoteDir, warnLabel, logLab
118669
119677
  await Promise.all(
118670
119678
  [...urlSet].map(async (url) => {
118671
119679
  try {
118672
- const localPath = await downloadToTemp(url, remoteDir);
119680
+ const localPath = await downloadToTemp(url, remoteDir, void 0, void 0, void 0, {
119681
+ onTelemetry: logRemoteDownloadTelemetry
119682
+ });
118673
119683
  urlToLocal.set(url, localPath);
118674
119684
  } catch (err) {
118675
- defaultLogger.warn(
118676
- `[Compiler] ${warnLabel} ${url} \u2014 using original URL as fallback. ${err instanceof Error ? err.message : String(err)}`
118677
- );
119685
+ const identity = safeDownloadUrlIdentity(url);
119686
+ defaultLogger.warn(`[Compiler] ${warnLabel} \u2014 using original URL as fallback.`, {
119687
+ urlFingerprint: identity.urlFingerprint,
119688
+ host: identity.host,
119689
+ error: err instanceof Error ? err.message : String(err)
119690
+ });
118678
119691
  }
118679
119692
  })
118680
119693
  );
@@ -118705,7 +119718,7 @@ async function localizeRemoteMediaSources(html, downloadDir) {
118705
119718
  urlSet,
118706
119719
  html,
118707
119720
  join45(downloadDir, REMOTE_MEDIA_SUBDIR),
118708
- "Remote media download failed for",
119721
+ "Remote media download failed",
118709
119722
  "Localized remote media source(s)"
118710
119723
  );
118711
119724
  }
@@ -118720,7 +119733,7 @@ async function localizeRemoteImageSources(html, downloadDir) {
118720
119733
  urlSet,
118721
119734
  html,
118722
119735
  join45(downloadDir, REMOTE_MEDIA_SUBDIR),
118723
- "Remote image download failed for",
119736
+ "Remote image download failed",
118724
119737
  "Localized remote image source(s)"
118725
119738
  );
118726
119739
  }
@@ -118735,7 +119748,7 @@ async function localizeRemoteBackgroundImages(html, downloadDir) {
118735
119748
  urlSet,
118736
119749
  html,
118737
119750
  join45(downloadDir, REMOTE_MEDIA_SUBDIR),
118738
- "Remote background-image download failed for",
119751
+ "Remote background-image download failed",
118739
119752
  "Localized remote background-image(s)",
118740
119753
  // Quoted url('..')/url("..") are rewritten by downloadAndRewriteUrls' default
118741
119754
  // replaceAll; this handles the unquoted url(https://..) form.
@@ -118751,40 +119764,18 @@ function isGoogleFontsUrl(href) {
118751
119764
  }
118752
119765
  }
118753
119766
  async function fetchExternalStylesheetCss(href) {
119767
+ const identity = safeDownloadUrlIdentity(href);
118754
119768
  try {
118755
- assertPublicHttpsUrl(href);
118756
- } catch {
118757
- return null;
118758
- }
118759
- try {
118760
- const response = await fetch(href, {
118761
- signal: AbortSignal.timeout(15e3)
119769
+ return await fetchPublicHttpsText(href, {
119770
+ maxBytes: MAX_STYLESHEET_BYTES,
119771
+ timeoutMs: 15e3
118762
119772
  });
118763
- if (!response.ok) {
118764
- defaultLogger.warn(
118765
- `[Compiler] External stylesheet fetch failed for ${href} \u2014 HTTP ${response.status}`
118766
- );
118767
- return null;
118768
- }
118769
- const contentLength = response.headers.get("content-length");
118770
- if (contentLength && parseInt(contentLength, 10) > MAX_STYLESHEET_BYTES) {
118771
- defaultLogger.warn(
118772
- `[Compiler] External stylesheet too large (${contentLength} bytes): ${href}`
118773
- );
118774
- return null;
118775
- }
118776
- const text2 = await response.text();
118777
- if (text2.length > MAX_STYLESHEET_BYTES) {
118778
- defaultLogger.warn(
118779
- `[Compiler] External stylesheet too large (${text2.length} bytes): ${href}`
118780
- );
118781
- return null;
118782
- }
118783
- return text2;
118784
119773
  } catch (err) {
118785
- defaultLogger.warn(
118786
- `[Compiler] External stylesheet fetch failed for ${href} \u2014 ${err instanceof Error ? err.message : String(err)}`
118787
- );
119774
+ defaultLogger.warn("[Compiler] External stylesheet fetch failed \u2014 preserving link tag.", {
119775
+ urlFingerprint: identity.urlFingerprint,
119776
+ host: identity.host,
119777
+ error: err instanceof Error ? err.message : String(err)
119778
+ });
118788
119779
  return null;
118789
119780
  }
118790
119781
  }
@@ -118840,13 +119831,16 @@ async function inlineExternalFontStylesheets(html) {
118840
119831
  if (css === null) continue;
118841
119832
  const fontFaceBlocks = extractFontFaceBlocks(css);
118842
119833
  if (fontFaceBlocks.length === 0) continue;
118843
- const inlineStyle = `<style>/* Inlined from ${href} */
119834
+ const identity = safeDownloadUrlIdentity(href);
119835
+ const inlineStyle = `<style>/* Inlined external font stylesheet */
118844
119836
  ${fontFaceBlocks.join("\n")}
118845
119837
  </style>`;
118846
119838
  result = result.replace(fullMatch, inlineStyle);
118847
- defaultLogger.info(
118848
- `[Compiler] Inlined ${fontFaceBlocks.length} @font-face rule(s) from external stylesheet: ${href}`
118849
- );
119839
+ defaultLogger.info("[Compiler] Inlined external @font-face rule(s)", {
119840
+ count: fontFaceBlocks.length,
119841
+ urlFingerprint: identity.urlFingerprint,
119842
+ host: identity.host
119843
+ });
118850
119844
  }
118851
119845
  return result;
118852
119846
  }
@@ -118887,7 +119881,7 @@ async function localizeRemoteFontFaces(html, downloadDir) {
118887
119881
  urlSet,
118888
119882
  processed,
118889
119883
  join45(downloadDir, REMOTE_MEDIA_SUBDIR),
118890
- "Remote font download failed for",
119884
+ "Remote font download failed",
118891
119885
  "Localized remote font face(s)",
118892
119886
  (h3, url, relPath) => h3.replaceAll(`url(${url})`, `url("${relPath}")`)
118893
119887
  );
@@ -118895,7 +119889,7 @@ async function localizeRemoteFontFaces(html, downloadDir) {
118895
119889
  async function readLocalFont(absPath) {
118896
119890
  const chunks = [];
118897
119891
  let totalBytes = 0;
118898
- for await (const chunk of createReadStream3(absPath)) {
119892
+ for await (const chunk of createReadStream4(absPath)) {
118899
119893
  const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
118900
119894
  totalBytes += buffer.length;
118901
119895
  if (totalBytes > MAX_LOCAL_FONT_DATA_URI_BYTES) {
@@ -119799,9 +120793,9 @@ async function runProbeStage(input2) {
119799
120793
  if (probeSession.launchCaptureMode === "beginframe") {
119800
120794
  const probeTimeoutMs = Number(process.env.PRODUCER_BEGINFRAME_PROBE_TIMEOUT_MS) > 0 ? Number(process.env.PRODUCER_BEGINFRAME_PROBE_TIMEOUT_MS) : 3e4;
119801
120795
  const livenessStart = Date.now();
119802
- const probeTick = Math.max(
119803
- 0,
119804
- probeSession.beginFrameTimeTicks - 5 * probeSession.beginFrameIntervalMs
120796
+ const probeTick = deriveBeginFrameProbeTimeTicks(
120797
+ probeSession.beginFrameTimeTicks,
120798
+ probeSession.beginFrameIntervalMs
119805
120799
  );
119806
120800
  const alive = await probeBeginFrameLiveness(
119807
120801
  probeSession.page,
@@ -123319,7 +124313,7 @@ var init_gifEncodeArgs = __esm({
123319
124313
  });
123320
124314
 
123321
124315
  // ../producer/src/services/render/stages/encodeStage.ts
123322
- import { copyFileSync as copyFileSync5, existsSync as existsSync53, mkdirSync as mkdirSync26, readdirSync as readdirSync16, rmSync as rmSync16, statSync as statSync16 } from "fs";
124316
+ import { copyFileSync as copyFileSync5, existsSync as existsSync53, mkdirSync as mkdirSync26, readdirSync as readdirSync17, rmSync as rmSync16, statSync as statSync16 } from "fs";
123323
124317
  import { dirname as dirname24, join as join59 } from "path";
123324
124318
  function resolveGifLoop(loop) {
123325
124319
  const resolved2 = loop ?? 0;
@@ -123330,7 +124324,7 @@ function resolveGifLoop(loop) {
123330
124324
  }
123331
124325
  async function encodeGifFromDir(framesDir, framePattern, outputPath, input2) {
123332
124326
  const startTime = Date.now();
123333
- const files = readdirSync16(framesDir).filter((file) => file.match(/\.(jpg|jpeg|png)$/i));
124327
+ const files = readdirSync17(framesDir).filter((file) => file.match(/\.(jpg|jpeg|png)$/i));
123334
124328
  const frameCount = files.length;
123335
124329
  if (frameCount === 0) {
123336
124330
  return {
@@ -123419,7 +124413,7 @@ async function runEncodeStage(input2) {
123419
124413
  if (isPngSequence) {
123420
124414
  updateJobStatus(job, "encoding", "Writing PNG sequence", 75, onProgress);
123421
124415
  if (!existsSync53(outputPath)) mkdirSync26(outputPath, { recursive: true });
123422
- const captured = readdirSync16(framesDir).filter((name) => name.endsWith(".png")).sort();
124416
+ const captured = readdirSync17(framesDir).filter((name) => name.endsWith(".png")).sort();
123423
124417
  if (captured.length === 0) {
123424
124418
  throw new Error(
123425
124419
  `[Render] png-sequence output requested but no PNGs were captured to ${framesDir}`
@@ -123582,6 +124576,10 @@ function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, tar
123582
124576
  function formatSeconds(sec) {
123583
124577
  return sec.toFixed(6);
123584
124578
  }
124579
+ function sanitizeProbeFailure(reason, paths) {
124580
+ const message = reason instanceof Error ? reason.message : String(reason);
124581
+ return redactTelemetryString(redactKnownPaths(message, paths));
124582
+ }
123585
124583
  async function padOrTrimAudioToVideoFrameCount(input2) {
123586
124584
  const probeVideo2 = input2.probeVideoFrameInfo ?? ((videoPath) => defaultProbeVideoFrameInfo(videoPath, input2.signal));
123587
124585
  const probeAudio = input2.probeAudioInfo ?? defaultProbeAudioInfo;
@@ -123590,12 +124588,16 @@ async function padOrTrimAudioToVideoFrameCount(input2) {
123590
124588
  probeVideo2(input2.videoPath),
123591
124589
  probeAudio(input2.audioPath, input2.signal)
123592
124590
  ]);
124591
+ const probePaths = [input2.videoPath, input2.audioPath, input2.outputPath];
123593
124592
  if (videoResult.status === "rejected") {
123594
124593
  return failResult(
123595
124594
  input2.outputPath,
123596
124595
  0,
123597
124596
  audioResult.status === "fulfilled" ? audioResult.value.durationSeconds : 0,
123598
- `audioPadTrim: failed to probe video: ${videoResult.reason.message}`
124597
+ `audioPadTrim: failed to probe video: ${sanitizeProbeFailure(
124598
+ videoResult.reason,
124599
+ probePaths
124600
+ )}`
123599
124601
  );
123600
124602
  }
123601
124603
  if (audioResult.status === "rejected") {
@@ -123603,7 +124605,10 @@ async function padOrTrimAudioToVideoFrameCount(input2) {
123603
124605
  input2.outputPath,
123604
124606
  0,
123605
124607
  0,
123606
- `audioPadTrim: failed to probe audio: ${audioResult.reason.message}`
124608
+ `audioPadTrim: failed to probe audio: ${sanitizeProbeFailure(
124609
+ audioResult.reason,
124610
+ probePaths
124611
+ )}`
123607
124612
  );
123608
124613
  }
123609
124614
  const videoInfo = videoResult.value;
@@ -123678,6 +124683,7 @@ async function defaultProbeVideoFrameInfo(videoPath, signal) {
123678
124683
  "stream=nb_frames,r_frame_rate",
123679
124684
  "-of",
123680
124685
  "json",
124686
+ "--",
123681
124687
  videoPath
123682
124688
  ],
123683
124689
  signal
@@ -123698,6 +124704,7 @@ async function defaultProbeVideoFrameInfo(videoPath, signal) {
123698
124704
  "stream=nb_read_packets,r_frame_rate",
123699
124705
  "-of",
123700
124706
  "json",
124707
+ "--",
123701
124708
  videoPath
123702
124709
  ],
123703
124710
  signal
@@ -123737,7 +124744,10 @@ async function defaultRunFfmpeg(args, signal) {
123737
124744
  };
123738
124745
  }
123739
124746
  async function runFfprobeJson(args, signal) {
123740
- const proc = spawn11(getFfprobeBinary(), args);
124747
+ if (!args.includes("--")) {
124748
+ throw new Error('[audioPadTrim] ffprobe args must terminate options with "--".');
124749
+ }
124750
+ const proc = spawn11(getFfprobeBinary(), args, { stdio: ["ignore", "pipe", "pipe"] });
123741
124751
  trackChildProcess(proc);
123742
124752
  let stdout2 = "";
123743
124753
  proc.stdout.on("data", (data2) => {
@@ -123755,7 +124765,9 @@ async function runFfprobeJson(args, signal) {
123755
124765
  throw outcome.error ?? new Error(outcome.stderr);
123756
124766
  }
123757
124767
  if (outcome.reason !== "exit" || outcome.exitCode !== 0) {
123758
- throw new Error(`ffprobe ${outcome.reason}: ${outcome.stderr}`);
124768
+ const probed = args[args.length - 1];
124769
+ const scrubbed = redactKnownPaths(outcome.stderr, probed === void 0 ? [] : [probed]);
124770
+ throw new Error(`ffprobe ${outcome.reason}: ${redactTelemetryString(scrubbed, 2e3)}`);
123759
124771
  }
123760
124772
  try {
123761
124773
  return JSON.parse(stdout2);
@@ -123768,6 +124780,7 @@ var init_audioPadTrim = __esm({
123768
124780
  "../producer/src/services/render/audioPadTrim.ts"() {
123769
124781
  "use strict";
123770
124782
  init_src();
124783
+ init_dist3();
123771
124784
  AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
123772
124785
  }
123773
124786
  });
@@ -123845,7 +124858,7 @@ import {
123845
124858
  mkdirSync as mkdirSync27,
123846
124859
  mkdtempSync as mkdtempSync7,
123847
124860
  readFileSync as readFileSync31,
123848
- readdirSync as readdirSync17,
124861
+ readdirSync as readdirSync18,
123849
124862
  rmSync as rmSync18,
123850
124863
  statSync as statSync17,
123851
124864
  writeFileSync as writeFileSync17,
@@ -123855,7 +124868,7 @@ import {
123855
124868
  import { tmpdir as tmpdir8 } from "os";
123856
124869
  import { join as join60, dirname as dirname25, resolve as resolve33 } from "path";
123857
124870
  import { totalmem as totalmem2 } from "os";
123858
- import { randomUUID as randomUUID7 } from "crypto";
124871
+ import { randomUUID as randomUUID8 } from "crypto";
123859
124872
  import { fileURLToPath as fileURLToPath5 } from "url";
123860
124873
  function sampleDirectoryBytes(dir) {
123861
124874
  let total = 0;
@@ -123865,7 +124878,7 @@ function sampleDirectoryBytes(dir) {
123865
124878
  if (!current2) continue;
123866
124879
  let entries2 = [];
123867
124880
  try {
123868
- entries2 = readdirSync17(current2);
124881
+ entries2 = readdirSync18(current2);
123869
124882
  } catch {
123870
124883
  continue;
123871
124884
  }
@@ -124214,7 +125227,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
124214
125227
  }
124215
125228
  function createRenderJob(config) {
124216
125229
  return {
124217
- id: randomUUID7(),
125230
+ id: randomUUID8(),
124218
125231
  config: {
124219
125232
  ...config,
124220
125233
  fps: toFps(config.fps),
@@ -126607,7 +127620,7 @@ import {
126607
127620
  mkdtempSync as mkdtempSync8,
126608
127621
  writeFileSync as writeFileSync18,
126609
127622
  rmSync as rmSync19,
126610
- createReadStream as createReadStream4
127623
+ createReadStream as createReadStream5
126611
127624
  } from "fs";
126612
127625
  import { resolve as resolve35, dirname as dirname27, join as join64 } from "path";
126613
127626
  import { tmpdir as tmpdir9 } from "os";
@@ -127166,7 +128179,7 @@ function createRenderHandlers(options = {}) {
127166
128179
  return c3.json({ success: false, error: "Output artifact file missing" }, 404);
127167
128180
  }
127168
128181
  const stats = statSync19(artifact.path);
127169
- return new Response(createReadStream4(artifact.path), {
128182
+ return new Response(createReadStream5(artifact.path), {
127170
128183
  headers: {
127171
128184
  "content-type": "video/mp4",
127172
128185
  "content-length": String(stats.size),
@@ -127437,7 +128450,7 @@ var init_planHash = __esm({
127437
128450
  });
127438
128451
 
127439
128452
  // ../producer/src/services/render/stages/freezePlan.ts
127440
- import { existsSync as existsSync58, mkdirSync as mkdirSync29, readFileSync as readFileSync34, readdirSync as readdirSync18, writeFileSync as writeFileSync19 } from "fs";
128453
+ import { existsSync as existsSync58, mkdirSync as mkdirSync29, readFileSync as readFileSync34, readdirSync as readdirSync19, writeFileSync as writeFileSync19 } from "fs";
127441
128454
  import { join as join65, relative as relative12, resolve as resolve36 } from "path";
127442
128455
  function stripUndefined(value) {
127443
128456
  if (Array.isArray(value)) return value.map(stripUndefined);
@@ -127457,7 +128470,7 @@ function listPlanFiles(planDir) {
127457
128470
  const results = [];
127458
128471
  const rootResolved = resolve36(planDir);
127459
128472
  function walk(dir) {
127460
- const entries2 = readdirSync18(dir, { withFileTypes: true });
128473
+ const entries2 = readdirSync19(dir, { withFileTypes: true });
127461
128474
  for (const entry of entries2) {
127462
128475
  const full2 = join65(dir, entry.name);
127463
128476
  if (entry.isDirectory()) {
@@ -127868,7 +128881,7 @@ var init_shared2 = __esm({
127868
128881
 
127869
128882
  // ../producer/src/services/distributed/planSize.ts
127870
128883
  import { createHash as createHash15 } from "crypto";
127871
- import { lstatSync as lstatSync5, readdirSync as readdirSync19 } from "fs";
128884
+ import { lstatSync as lstatSync5, readdirSync as readdirSync20 } from "fs";
127872
128885
  import { extname as extname13, join as join67, relative as relative13 } from "path";
127873
128886
  function hashComponent(value) {
127874
128887
  return createHash15("sha256").update(value).digest("hex").slice(0, 12);
@@ -127950,7 +128963,7 @@ function recordFile(result, components, rootDir, rootKind, filePath) {
127950
128963
  function walkRegularFiles(dir, visit) {
127951
128964
  let entries2;
127952
128965
  try {
127953
- entries2 = readdirSync19(dir, { withFileTypes: true });
128966
+ entries2 = readdirSync20(dir, { withFileTypes: true });
127954
128967
  } catch {
127955
128968
  return;
127956
128969
  }
@@ -128007,7 +129020,7 @@ var init_planSize = __esm({
128007
129020
  });
128008
129021
 
128009
129022
  // ../producer/src/services/distributed/plan.ts
128010
- import { cpSync as cpSync3, existsSync as existsSync60, mkdirSync as mkdirSync30, renameSync as renameSync12, rmSync as rmSync20, writeFileSync as writeFileSync20 } from "fs";
129023
+ import { cpSync as cpSync3, existsSync as existsSync60, mkdirSync as mkdirSync30, renameSync as renameSync11, rmSync as rmSync20, writeFileSync as writeFileSync20 } from "fs";
128011
129024
  import { join as join68, relative as relative14, sep as sep10 } from "path";
128012
129025
  function applyDistributedAudioWarningPolicy(job, audioError, audioFailures = [], log2 = defaultLogger) {
128013
129026
  const failureOwner = audioFailures.length === 0 ? void 0 : audioFailures.some((failure) => failure.owner === "system") ? "system" : "user";
@@ -128357,12 +129370,12 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
128357
129370
  const videoFramesDst = join68(planDir, "video-frames");
128358
129371
  if (existsSync60(videoFramesDst)) rmSync20(videoFramesDst, { recursive: true, force: true });
128359
129372
  if (existsSync60(stagedVideoFrames)) {
128360
- renameSync12(stagedVideoFrames, videoFramesDst);
129373
+ renameSync11(stagedVideoFrames, videoFramesDst);
128361
129374
  } else {
128362
129375
  mkdirSync30(videoFramesDst, { recursive: true });
128363
129376
  }
128364
129377
  if (existsSync60(finalCompiledDir)) rmSync20(finalCompiledDir, { recursive: true, force: true });
128365
- renameSync12(compiledDir, finalCompiledDir);
129378
+ renameSync11(compiledDir, finalCompiledDir);
128366
129379
  const planVideosJson = buildPlanVideosJson({
128367
129380
  videos: composition.videos,
128368
129381
  compositionEnd: job.duration ?? Number.NaN,
@@ -128383,7 +129396,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
128383
129396
  );
128384
129397
  const planAudioPath = join68(planDir, PLAN_AUDIO_RELATIVE_PATH);
128385
129398
  if (audioResult.hasAudio && existsSync60(audioResult.audioOutputPath)) {
128386
- renameSync12(audioResult.audioOutputPath, planAudioPath);
129399
+ renameSync11(audioResult.audioOutputPath, planAudioPath);
128387
129400
  }
128388
129401
  const maxParallel = config.maxParallelChunks ?? DEFAULT_MAX_PARALLEL_CHUNKS;
128389
129402
  const { chunkCount, effectiveChunkSize } = resolveChunkPlan(
@@ -128609,10 +129622,10 @@ var init_planV2Layout = __esm({
128609
129622
  import {
128610
129623
  copyFileSync as copyFileSync7,
128611
129624
  existsSync as existsSync61,
128612
- linkSync as linkSync2,
129625
+ linkSync as linkSync3,
128613
129626
  mkdirSync as mkdirSync31,
128614
129627
  mkdtempSync as mkdtempSync9,
128615
- renameSync as renameSync13,
129628
+ renameSync as renameSync12,
128616
129629
  rmSync as rmSync21,
128617
129630
  statSync as statSync20,
128618
129631
  writeFileSync as writeFileSync21
@@ -128659,7 +129672,7 @@ var init_planV2Publisher = __esm({
128659
129672
  throw new PlanV2IntegrityError(`output directory already exists: ${destinationDir}`);
128660
129673
  }
128661
129674
  this.destinationDir = destinationDir;
128662
- this.#linkFile = options.linkFile ?? linkSync2;
129675
+ this.#linkFile = options.linkFile ?? linkSync3;
128663
129676
  mkdirSync31(dirname29(destinationDir), { recursive: true });
128664
129677
  this.temporaryDir = mkdtempSync9(join70(dirname29(destinationDir), ".plan-v2-publish-"));
128665
129678
  }
@@ -128683,7 +129696,7 @@ var init_planV2Publisher = __esm({
128683
129696
  if (!canFallbackToCopy(error)) throw error;
128684
129697
  copyFileSync7(blob.sourcePath, temporaryPath);
128685
129698
  }
128686
- renameSync13(temporaryPath, destinationPath);
129699
+ renameSync12(temporaryPath, destinationPath);
128687
129700
  } finally {
128688
129701
  rmSync21(stagingDir, { recursive: true, force: true });
128689
129702
  }
@@ -128697,7 +129710,7 @@ var init_planV2Publisher = __esm({
128697
129710
  }
128698
129711
  }
128699
129712
  writeFileSync21(join70(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
128700
- renameSync13(this.temporaryDir, this.destinationDir);
129713
+ renameSync12(this.temporaryDir, this.destinationDir);
128701
129714
  this.#committed = true;
128702
129715
  }
128703
129716
  async abort() {
@@ -128720,8 +129733,8 @@ import {
128720
129733
  openSync as openSync7,
128721
129734
  readFileSync as readFileSync36,
128722
129735
  readSync as readSync4,
128723
- readdirSync as readdirSync20,
128724
- renameSync as renameSync14,
129736
+ readdirSync as readdirSync21,
129737
+ renameSync as renameSync13,
128725
129738
  rmSync as rmSync23,
128726
129739
  statSync as statSync21,
128727
129740
  writeFileSync as writeFileSync23
@@ -128758,7 +129771,7 @@ function listFiles(root) {
128758
129771
  const files = [];
128759
129772
  const rootResolved = resolve37(root);
128760
129773
  function walk(dir) {
128761
- for (const entry of readdirSync20(dir, { withFileTypes: true })) {
129774
+ for (const entry of readdirSync21(dir, { withFileTypes: true })) {
128762
129775
  const absolutePath = join71(dir, entry.name);
128763
129776
  if (entry.isDirectory()) {
128764
129777
  walk(absolutePath);
@@ -128803,10 +129816,10 @@ function assertValidExtractionCacheCompleteSentinel(path2) {
128803
129816
  function validateExtractionCacheCompleteSentinels(executionPlanDir) {
128804
129817
  const videoRoot = join71(executionPlanDir, "video-frames");
128805
129818
  if (!existsSync63(videoRoot)) return;
128806
- for (const videoEntry of readdirSync20(videoRoot, { withFileTypes: true })) {
129819
+ for (const videoEntry of readdirSync21(videoRoot, { withFileTypes: true })) {
128807
129820
  if (!videoEntry.isDirectory()) continue;
128808
129821
  const videoDir = join71(videoRoot, videoEntry.name);
128809
- if (readdirSync20(videoDir).includes(EXTRACTION_CACHE_COMPLETE_SENTINEL)) {
129822
+ if (readdirSync21(videoDir).includes(EXTRACTION_CACHE_COMPLETE_SENTINEL)) {
128810
129823
  const sentinelPath = join71(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
128811
129824
  assertValidExtractionCacheCompleteSentinel(sentinelPath);
128812
129825
  }
@@ -128843,7 +129856,7 @@ function artifactTargets(path2, videoDependencies) {
128843
129856
  function listVideoFramePaths(executionPlanDir, videos) {
128844
129857
  return videos.extracted.map((video) => {
128845
129858
  const outputDir = resolveExtractedVideoOutputDir(executionPlanDir, video.videoId);
128846
- const frameNames = readdirSync20(outputDir).sort();
129859
+ const frameNames = readdirSync21(outputDir).sort();
128847
129860
  const framePaths = /* @__PURE__ */ new Map();
128848
129861
  for (const frameName of frameNames) {
128849
129862
  if (frameName === EXTRACTION_CACHE_COMPLETE_SENTINEL) {
@@ -128964,7 +129977,7 @@ function writeBlob(sourcePath, destinationPath) {
128964
129977
  const temporaryPath = join71(temporaryDir, "blob");
128965
129978
  try {
128966
129979
  copyFileSync8(sourcePath, temporaryPath);
128967
- renameSync14(temporaryPath, destinationPath);
129980
+ renameSync13(temporaryPath, destinationPath);
128968
129981
  } finally {
128969
129982
  rmSync23(temporaryDir, { recursive: true, force: true });
128970
129983
  }
@@ -129056,7 +130069,7 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
129056
130069
  canonicalJsonStringify(publication.manifest),
129057
130070
  "utf-8"
129058
130071
  );
129059
- renameSync14(tempDir, planV2Dir);
130072
+ renameSync13(tempDir, planV2Dir);
129060
130073
  return resultFromManifest(planV2Dir, publication.manifest);
129061
130074
  } catch (error) {
129062
130075
  rmSync23(tempDir, { recursive: true, force: true });
@@ -129310,7 +130323,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir) {
129310
130323
  canonicalJsonStringify({ manifest, target }),
129311
130324
  "utf-8"
129312
130325
  );
129313
- renameSync14(tempDir, destinationDir);
130326
+ renameSync13(tempDir, destinationDir);
129314
130327
  } catch (error) {
129315
130328
  rmSync23(tempDir, { recursive: true, force: true });
129316
130329
  throw error;
@@ -129378,7 +130391,7 @@ import {
129378
130391
  existsSync as existsSync64,
129379
130392
  mkdirSync as mkdirSync34,
129380
130393
  readFileSync as readFileSync37,
129381
- readdirSync as readdirSync21,
130394
+ readdirSync as readdirSync23,
129382
130395
  rmSync as rmSync24,
129383
130396
  statSync as statSync24,
129384
130397
  writeFileSync as writeFileSync24
@@ -129589,7 +130602,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
129589
130602
  `[assemble] png-sequence chunk must be a directory: ${chunkDir} (got a file)`
129590
130603
  );
129591
130604
  }
129592
- const frames = readdirSync21(chunkDir).filter((name) => name.endsWith(".png")).sort();
130605
+ const frames = readdirSync23(chunkDir).filter((name) => name.endsWith(".png")).sort();
129593
130606
  if (frames.length === 0) {
129594
130607
  throw new Error(`[assemble] png-sequence chunk has no frames: ${chunkDir}`);
129595
130608
  }
@@ -129609,7 +130622,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
129609
130622
  cpSync4(audioPath, sidecar);
129610
130623
  }
129611
130624
  let fileSize = 0;
129612
- for (const name of readdirSync21(outputPath)) {
130625
+ for (const name of readdirSync23(outputPath)) {
129613
130626
  try {
129614
130627
  fileSize += statSync24(join73(outputPath, name)).size;
129615
130628
  } catch {
@@ -129637,7 +130650,7 @@ var init_assemble = __esm({
129637
130650
 
129638
130651
  // ../producer/src/services/distributed/renderChunk.ts
129639
130652
  import { randomBytes as randomBytes2 } from "crypto";
129640
- import { existsSync as existsSync65, mkdirSync as mkdirSync35, readFileSync as readFileSync38, readdirSync as readdirSync23, rmSync as rmSync25, writeFileSync as writeFileSync25 } from "fs";
130653
+ import { existsSync as existsSync65, mkdirSync as mkdirSync35, readFileSync as readFileSync38, readdirSync as readdirSync24, rmSync as rmSync25, writeFileSync as writeFileSync25 } from "fs";
129641
130654
  import { extname as extname14, join as join74 } from "path";
129642
130655
  function validatePlanVideosForChunk(value) {
129643
130656
  try {
@@ -129691,7 +130704,10 @@ async function runCaptureWithScreenshotFallback(input2) {
129691
130704
  async function beginFrameSessionNeedsScreenshotFallback(session, probe = probeBeginFrameLiveness) {
129692
130705
  if (session.launchCaptureMode !== "beginframe") return false;
129693
130706
  const timeoutMs = Number(process.env.PRODUCER_BEGINFRAME_PROBE_TIMEOUT_MS) > 0 ? Number(process.env.PRODUCER_BEGINFRAME_PROBE_TIMEOUT_MS) : 3e4;
129694
- const probeTick = Math.max(0, session.beginFrameTimeTicks - 5 * session.beginFrameIntervalMs);
130707
+ const probeTick = deriveBeginFrameProbeTimeTicks(
130708
+ session.beginFrameTimeTicks,
130709
+ session.beginFrameIntervalMs
130710
+ );
129695
130711
  return !await probe(session.page, timeoutMs, probeTick, session.beginFrameIntervalMs);
129696
130712
  }
129697
130713
  function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v1") {
@@ -129704,7 +130720,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
129704
130720
  );
129705
130721
  }
129706
130722
  const ext = (extname14(v2.framePattern) || ".jpg").toLowerCase();
129707
- const frames = readdirSync23(outputDir).filter((name) => name.toLowerCase().endsWith(ext)).sort();
130723
+ const frames = readdirSync24(outputDir).filter((name) => name.toLowerCase().endsWith(ext)).sort();
129708
130724
  const framePaths = /* @__PURE__ */ new Map();
129709
130725
  for (let i2 = 0; i2 < frames.length; i2++) {
129710
130726
  const frameName = frames[i2];
@@ -129734,7 +130750,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
129734
130750
  }
129735
130751
  function hashChunkOutput(outputPath, kind) {
129736
130752
  if (kind === "file") return sha256Hex(readFileSync38(outputPath));
129737
- const entries2 = readdirSync23(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
130753
+ const entries2 = readdirSync24(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
129738
130754
  const lines = entries2.map(
129739
130755
  (name) => `${name}\0${sha256Hex(readFileSync38(join74(outputPath, name)))}`
129740
130756
  );
@@ -130259,7 +131275,7 @@ var init_planV2Execution = __esm({
130259
131275
  });
130260
131276
 
130261
131277
  // ../producer/src/services/distributed/projectHash.ts
130262
- import { readdirSync as readdirSync24, readFileSync as readFileSync39 } from "fs";
131278
+ import { readdirSync as readdirSync25, readFileSync as readFileSync39 } from "fs";
130263
131279
  import { createHash as createHash17 } from "crypto";
130264
131280
  import { join as join76, relative as relative16 } from "path";
130265
131281
  var init_projectHash = __esm({
@@ -130961,7 +131977,7 @@ __export(studioServer_exports, {
130961
131977
  });
130962
131978
  import { Hono as Hono5 } from "hono";
130963
131979
  import { streamSSE as streamSSE4 } from "hono/streaming";
130964
- import { existsSync as existsSync67, readFileSync as readFileSync40, writeFileSync as writeFileSync26, statSync as statSync25, unlinkSync as unlinkSync5 } from "fs";
131980
+ import { existsSync as existsSync67, readFileSync as readFileSync40, writeFileSync as writeFileSync26, statSync as statSync25, unlinkSync as unlinkSync6 } from "fs";
130965
131981
  import { resolve as resolve38, join as join78, basename as basename11 } from "path";
130966
131982
  async function loadStudioProducer() {
130967
131983
  return isDevMode() ? await Promise.resolve().then(() => (init_src2(), src_exports2)) : await Promise.resolve().then(() => (init_src2(), src_exports2));
@@ -131200,7 +132216,7 @@ function createStudioServer(options) {
131200
132216
  async transformPreviewHtml({ html, project: project2 }) {
131201
132217
  const { injectDeterministicFontFaces: injectDeterministicFontFaces2 } = await Promise.resolve().then(() => (init_deterministicFonts(), deterministicFonts_exports));
131202
132218
  const { prepareAnimatedGifInputs: prepareAnimatedGifInputs2 } = await Promise.resolve().then(() => (init_animatedGifPrep(), animatedGifPrep_exports));
131203
- const { downloadToTemp: downloadToTemp2 } = await Promise.resolve().then(() => (init_urlDownloader2(), urlDownloader_exports));
132219
+ const { downloadToTemp: downloadToTemp2, writeUrlDownloadTelemetry: writeUrlDownloadTelemetry2 } = await Promise.resolve().then(() => (init_urlDownloader2(), urlDownloader_exports));
131204
132220
  const gifOutputDir = join78(project2.dir, ".hyperframes", "prepared-assets", "gif");
131205
132221
  const gifDownloadDir = join78(project2.dir, ".hyperframes", "prepared-assets", "downloads");
131206
132222
  const prepared = await prepareAnimatedGifInputs2(html, {
@@ -131209,7 +132225,13 @@ function createStudioServer(options) {
131209
132225
  outputDir: gifOutputDir,
131210
132226
  outputSrcPrefix: ".hyperframes/prepared-assets/gif",
131211
132227
  cacheDir: gifOutputDir,
131212
- sourceAssets: await downloadRemoteGifImageSources(html, gifDownloadDir, downloadToTemp2)
132228
+ sourceAssets: await downloadRemoteGifImageSources(
132229
+ html,
132230
+ gifDownloadDir,
132231
+ (url, destDir) => downloadToTemp2(url, destDir, void 0, void 0, void 0, {
132232
+ onTelemetry: writeUrlDownloadTelemetry2
132233
+ })
132234
+ )
131213
132235
  });
131214
132236
  return injectDeterministicFontFaces2(prepared.html);
131215
132237
  },
@@ -131242,7 +132264,7 @@ function createStudioServer(options) {
131242
132264
  for (const suffix of ["", ".meta.json"]) {
131243
132265
  const fp = suffix ? opts.outputPath.replace(/\.(mp4|webm|mov)$/, suffix) : opts.outputPath;
131244
132266
  try {
131245
- if (existsSync67(fp)) unlinkSync5(fp);
132267
+ if (existsSync67(fp)) unlinkSync6(fp);
131246
132268
  } catch {
131247
132269
  }
131248
132270
  }
@@ -131621,7 +132643,7 @@ import {
131621
132643
  readFileSync as readFileSync41,
131622
132644
  readlinkSync,
131623
132645
  symlinkSync as symlinkSync3,
131624
- unlinkSync as unlinkSync6
132646
+ unlinkSync as unlinkSync7
131625
132647
  } from "fs";
131626
132648
  import { resolve as resolve39, dirname as dirname33, basename as basename12, join as join79 } from "path";
131627
132649
  import { fileURLToPath as fileURLToPath8 } from "url";
@@ -131955,7 +132977,7 @@ function linkProjectIntoStudioData(dir, projectsDir, projectName) {
131955
132977
  try {
131956
132978
  const stat3 = lstatSync7(symlinkPath);
131957
132979
  if (stat3.isSymbolicLink() && resolve39(readlinkSync(symlinkPath)) !== resolve39(dir)) {
131958
- unlinkSync6(symlinkPath);
132980
+ unlinkSync7(symlinkPath);
131959
132981
  }
131960
132982
  } catch {
131961
132983
  }
@@ -131971,7 +132993,7 @@ function removeSymlinkOnExit(createdSymlink, symlinkPath) {
131971
132993
  if (!createdSymlink) return;
131972
132994
  process.on("exit", () => {
131973
132995
  try {
131974
- if (existsSync68(symlinkPath)) unlinkSync6(symlinkPath);
132996
+ if (existsSync68(symlinkPath)) unlinkSync7(symlinkPath);
131975
132997
  } catch {
131976
132998
  }
131977
132999
  });
@@ -132541,7 +133563,7 @@ import {
132541
133563
  cpSync as cpSync5,
132542
133564
  writeFileSync as writeFileSync27,
132543
133565
  readFileSync as readFileSync43,
132544
- readdirSync as readdirSync25
133566
+ readdirSync as readdirSync26
132545
133567
  } from "fs";
132546
133568
  import { resolve as resolve40, basename as basename13, join as join80, dirname as dirname34 } from "path";
132547
133569
  import { fileURLToPath as fileURLToPath9 } from "url";
@@ -132561,7 +133583,7 @@ function probeVideo(filePath) {
132561
133583
  if (!ffprobePath) return void 0;
132562
133584
  const raw = execFileSync8(
132563
133585
  ffprobePath,
132564
- ["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", filePath],
133586
+ ["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", "--", filePath],
132565
133587
  { encoding: "utf-8", timeout: 15e3 }
132566
133588
  );
132567
133589
  const parsed = JSON.parse(raw);
@@ -132692,7 +133714,7 @@ function listHtmlFiles(dir) {
132692
133714
  const files = [];
132693
133715
  const ignoredDirs = /* @__PURE__ */ new Set([".git", "dist", "node_modules"]);
132694
133716
  function walk(currentDir) {
132695
- for (const entry of readdirSync25(currentDir, { withFileTypes: true })) {
133717
+ for (const entry of readdirSync26(currentDir, { withFileTypes: true })) {
132696
133718
  const entryPath = join80(currentDir, entry.name);
132697
133719
  if (entry.isDirectory()) {
132698
133720
  if (!ignoredDirs.has(entry.name)) walk(entryPath);
@@ -132738,7 +133760,7 @@ function writeTailwindSupport(destDir) {
132738
133760
  }
132739
133761
  }
132740
133762
  function patchVideoSrc(dir, videoFilename, durationSeconds) {
132741
- const htmlFiles = readdirSync25(dir, { withFileTypes: true, recursive: true }).filter((e3) => e3.isFile() && e3.name.endsWith(".html")).map((e3) => join80(e3.parentPath, e3.name));
133763
+ const htmlFiles = readdirSync26(dir, { withFileTypes: true, recursive: true }).filter((e3) => e3.isFile() && e3.name.endsWith(".html")).map((e3) => join80(e3.parentPath, e3.name));
132742
133764
  for (const file of htmlFiles) {
132743
133765
  let content = readFileSync43(file, "utf-8");
132744
133766
  if (videoFilename) {
@@ -132926,7 +133948,7 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
132926
133948
  writeDefaultPackageJson(destDir, name);
132927
133949
  const sharedDir = getSharedTemplateDir();
132928
133950
  if (existsSync69(sharedDir)) {
132929
- for (const entry of readdirSync25(sharedDir, { withFileTypes: true })) {
133951
+ for (const entry of readdirSync26(sharedDir, { withFileTypes: true })) {
132930
133952
  const src = join80(sharedDir, entry.name);
132931
133953
  const dest = resolve40(destDir, entry.name);
132932
133954
  if (entry.isFile() || entry.isSymbolicLink()) {
@@ -133145,7 +134167,7 @@ var init_init = __esm({
133145
134167
  const templateId2 = exampleFlag ?? "blank";
133146
134168
  const name2 = args.name ?? "my-video";
133147
134169
  const destDir2 = resolve40(name2);
133148
- if (existsSync69(destDir2) && readdirSync25(destDir2).length > 0) {
134170
+ if (existsSync69(destDir2) && readdirSync26(destDir2).length > 0) {
133149
134171
  console.error(c.error(`Directory already exists and is not empty: ${name2}`));
133150
134172
  failCommand();
133151
134173
  }
@@ -133226,7 +134248,7 @@ var init_init = __esm({
133226
134248
  await patchTranscript(destDir2, transcriptFile2);
133227
134249
  }
133228
134250
  console.log(c.success(`Created ${c.accent(name2 + "/")}`));
133229
- for (const f3 of readdirSync25(destDir2).filter((f4) => !f4.startsWith("."))) {
134251
+ for (const f3 of readdirSync26(destDir2).filter((f4) => !f4.startsWith("."))) {
133230
134252
  console.log(` ${c.accent(f3)}`);
133231
134253
  }
133232
134254
  if (!skipSkills) {
@@ -133286,7 +134308,7 @@ var init_init = __esm({
133286
134308
  name = nameResult;
133287
134309
  }
133288
134310
  const destDir = resolve40(name);
133289
- if (existsSync69(destDir) && readdirSync25(destDir).length > 0) {
134311
+ if (existsSync69(destDir) && readdirSync26(destDir).length > 0) {
133290
134312
  const overwrite = await ue({
133291
134313
  message: `Directory ${c.accent(name)} already exists and is not empty. Overwrite?`,
133292
134314
  initialValue: false
@@ -133418,7 +134440,7 @@ ${c.dim("Use --example blank for offline use.")}`
133418
134440
  if (existsSync69(transcriptFile)) {
133419
134441
  await patchTranscript(destDir, transcriptFile);
133420
134442
  }
133421
- const files = readdirSync25(destDir);
134443
+ const files = readdirSync26(destDir);
133422
134444
  Se(files.map((f3) => c.accent(f3)).join("\n"), c.success(`Created ${name}/`));
133423
134445
  if (!skipSkills) {
133424
134446
  await keepSkillsCurrent(destDir);
@@ -133882,14 +134904,14 @@ var init_catalog = __esm({
133882
134904
  var init_mediaProxyPreview = __esm({
133883
134905
  "../studio-server/dist/helpers/mediaProxyPreview.js"() {
133884
134906
  "use strict";
133885
- init_chunk_JOZUTP73();
133886
- init_chunk_IQAVZUQP();
133887
- init_chunk_I2USK772();
134907
+ init_chunk_LHYV3WLZ();
134908
+ init_chunk_ZPI6QXJH();
134909
+ init_chunk_6H3V3WGJ();
133888
134910
  }
133889
134911
  });
133890
134912
 
133891
134913
  // src/utils/compositionServer.ts
133892
- import { createReadStream as createReadStream5, existsSync as existsSync71, statSync as statSync26 } from "fs";
134914
+ import { createReadStream as createReadStream6, existsSync as existsSync71, statSync as statSync26 } from "fs";
133893
134915
  import { resolve as resolve44, dirname as dirname35 } from "path";
133894
134916
  import { Readable as Readable3 } from "stream";
133895
134917
  import { fileURLToPath as fileURLToPath10 } from "url";
@@ -133937,7 +134959,7 @@ function buildRangeResponse(filePath, contentType, rangeHeader) {
133937
134959
  const size = statSync26(filePath).size;
133938
134960
  const last = size - 1;
133939
134961
  const match = rangeHeader ? /^bytes=(\d*)-(\d*)$/.exec(rangeHeader.trim()) : null;
133940
- const body = (start2, end2) => size === 0 ? null : Readable3.toWeb(createReadStream5(filePath, { start: start2, end: end2 }));
134962
+ const body = (start2, end2) => size === 0 ? null : Readable3.toWeb(createReadStream6(filePath, { start: start2, end: end2 }));
133941
134963
  if (!match) {
133942
134964
  return new Response(body(0, last), {
133943
134965
  status: 200,
@@ -134004,8 +135026,8 @@ var init_compositionServer = __esm({
134004
135026
  var init_proxyTranscoder = __esm({
134005
135027
  "../studio-server/dist/helpers/proxyTranscoder.js"() {
134006
135028
  "use strict";
134007
- init_chunk_IQAVZUQP();
134008
- init_chunk_I2USK772();
135029
+ init_chunk_ZPI6QXJH();
135030
+ init_chunk_6H3V3WGJ();
134009
135031
  }
134010
135032
  });
134011
135033
 
@@ -134013,7 +135035,7 @@ var init_proxyTranscoder = __esm({
134013
135035
  var init_mediaCodecMap = __esm({
134014
135036
  "../studio-server/dist/helpers/mediaCodecMap.js"() {
134015
135037
  "use strict";
134016
- init_chunk_I2USK772();
135038
+ init_chunk_6H3V3WGJ();
134017
135039
  }
134018
135040
  });
134019
135041
 
@@ -135591,7 +136613,7 @@ var init_auth = __esm({
135591
136613
  });
135592
136614
 
135593
136615
  // src/utils/projectLink.ts
135594
- import { randomUUID as randomUUID8 } from "crypto";
136616
+ import { randomUUID as randomUUID9 } from "crypto";
135595
136617
  import { existsSync as existsSync75, mkdirSync as mkdirSync39, readFileSync as readFileSync46, writeFileSync as writeFileSync28 } from "fs";
135596
136618
  import { homedir as homedir16 } from "os";
135597
136619
  import { join as join83, resolve as resolve47 } from "path";
@@ -135642,7 +136664,7 @@ function ensureProjectId(absDir) {
135642
136664
  const path2 = resolve47(absDir);
135643
136665
  const existing = links[path2];
135644
136666
  if (existing) return existing.projectId;
135645
- const projectId = randomUUID8();
136667
+ const projectId = randomUUID9();
135646
136668
  links[path2] = { projectId, url: "" };
135647
136669
  writeProjectLinks(links);
135648
136670
  return projectId;
@@ -135680,7 +136702,7 @@ var init_projectLink = __esm({
135680
136702
 
135681
136703
  // src/utils/publishProject.ts
135682
136704
  import { basename as basename14, dirname as dirname37, join as join84, posix as posix5, relative as relative18, resolve as resolve48 } from "path";
135683
- import { existsSync as existsSync76, readdirSync as readdirSync26, readFileSync as readFileSync47, statSync as statSync27 } from "fs";
136705
+ import { existsSync as existsSync76, readdirSync as readdirSync27, readFileSync as readFileSync47, statSync as statSync27 } from "fs";
135684
136706
  import AdmZip from "adm-zip";
135685
136707
  import ignore2 from "ignore";
135686
136708
  function isRecord8(value) {
@@ -135792,7 +136814,7 @@ function createProjectIgnore(rootDir) {
135792
136814
  return matcher;
135793
136815
  }
135794
136816
  function collectProjectFiles(rootDir, currentDir, paths, matcher) {
135795
- for (const entry of readdirSync26(currentDir, { withFileTypes: true })) {
136817
+ for (const entry of readdirSync27(currentDir, { withFileTypes: true })) {
135796
136818
  if (shouldIgnoreSegment(entry.name)) continue;
135797
136819
  const absolutePath = join84(currentDir, entry.name);
135798
136820
  const relativePath = relative18(rootDir, absolutePath).replaceAll("\\", "/");
@@ -137495,6 +138517,7 @@ function probeWebmAlpha(filePath) {
137495
138517
  "stream=codec_name:stream_tags=alpha_mode",
137496
138518
  "-of",
137497
138519
  "json",
138520
+ "--",
137498
138521
  filePath
137499
138522
  ],
137500
138523
  { encoding: "utf-8", timeout: 15e3 }
@@ -138042,7 +139065,7 @@ __export(render_exports, {
138042
139065
  renderLocal: () => renderLocal,
138043
139066
  resolveBrowserGpuForCli: () => resolveBrowserGpuForCli
138044
139067
  });
138045
- import { mkdtempSync as mkdtempSync12, readdirSync as readdirSync27, readFileSync as readFileSync53, statSync as statSync29, writeFileSync as writeFileSync30, rmSync as rmSync27 } from "fs";
139068
+ import { mkdtempSync as mkdtempSync12, readdirSync as readdirSync28, readFileSync as readFileSync53, statSync as statSync29, writeFileSync as writeFileSync30, rmSync as rmSync27 } from "fs";
138046
139069
  import { freemem as freemem5, tmpdir as tmpdir12 } from "os";
138047
139070
  import { resolve as resolve54, dirname as dirname41, join as join88, basename as basename16 } from "path";
138048
139071
  import { execFileSync as execFileSync11, spawn as spawn15 } from "child_process";
@@ -138725,7 +139748,7 @@ function printRenderComplete(outputPath, elapsedMs, quiet, outputDurationSeconds
138725
139748
  isDirectory = stat3.isDirectory();
138726
139749
  if (stat3.isDirectory()) {
138727
139750
  let total = 0;
138728
- for (const entry of readdirSync27(outputPath, { withFileTypes: true })) {
139751
+ for (const entry of readdirSync28(outputPath, { withFileTypes: true })) {
138729
139752
  if (!entry.isFile()) continue;
138730
139753
  try {
138731
139754
  total += statSync29(join88(outputPath, entry.name)).size;
@@ -139141,7 +140164,7 @@ __export(staticProjectServer_exports, {
139141
140164
  serveStaticProjectHtml: () => serveStaticProjectHtml
139142
140165
  });
139143
140166
  import { createServer as createServer2 } from "http";
139144
- import { createReadStream as createReadStream6, existsSync as existsSync80, statSync as statSync30 } from "fs";
140167
+ import { createReadStream as createReadStream7, existsSync as existsSync80, statSync as statSync30 } from "fs";
139145
140168
  import { isAbsolute as isAbsolute14, relative as relative20, resolve as resolve55 } from "path";
139146
140169
  function serveFileWithRange(filePath, rangeHeader, res, contentType = getMimeType(filePath)) {
139147
140170
  const size = statSync30(filePath).size;
@@ -139167,7 +140190,7 @@ function serveFileWithRange(filePath, rangeHeader, res, contentType = getMimeTyp
139167
140190
  headers["Content-Range"] = `bytes ${start}-${end}/${size}`;
139168
140191
  }
139169
140192
  headers["Content-Length"] = String(end - start + 1);
139170
- const stream = createReadStream6(filePath, { start, end });
140193
+ const stream = createReadStream7(filePath, { start, end });
139171
140194
  stream.on("open", () => {
139172
140195
  res.writeHead(status, headers);
139173
140196
  stream.pipe(res);
@@ -139709,7 +140732,7 @@ var init_motionAudit = __esm({
139709
140732
  });
139710
140733
 
139711
140734
  // src/utils/motionSpec.ts
139712
- import { existsSync as existsSync81, readFileSync as readFileSync54, readdirSync as readdirSync28 } from "fs";
140735
+ import { existsSync as existsSync81, readFileSync as readFileSync54, readdirSync as readdirSync29 } from "fs";
139713
140736
  import { basename as basename17, join as join89 } from "path";
139714
140737
  function isObject2(value) {
139715
140738
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -139753,7 +140776,7 @@ function parseMotionSpec(raw) {
139753
140776
  }
139754
140777
  function findMotionSpec(projectDir) {
139755
140778
  if (!existsSync81(projectDir)) return null;
139756
- const entries2 = readdirSync28(projectDir);
140779
+ const entries2 = readdirSync29(projectDir);
139757
140780
  const sidecars = entries2.filter((name) => name.endsWith(".motion.json")).sort();
139758
140781
  if (!sidecars[0]) return null;
139759
140782
  if (sidecars.length === 1) return join89(projectDir, sidecars[0]);
@@ -143727,8 +144750,62 @@ function containsTimelineCall3(node, timelineVar) {
143727
144750
  function rangeOf3(node) {
143728
144751
  return typeof node.start === "number" && typeof node.end === "number" ? [node.start, node.end] : void 0;
143729
144752
  }
144753
+ function isSafeDefaultExpression3(node, earlierParams) {
144754
+ let safe = true;
144755
+ const visit = (current2, parent, key2) => {
144756
+ if (!isNode4(current2) || !safe) return;
144757
+ if (!SAFE_DEFAULT_NODES3.has(current2.type)) {
144758
+ safe = false;
144759
+ return;
144760
+ }
144761
+ if (current2.type === "UnaryExpression" && current2.operator === "delete") {
144762
+ safe = false;
144763
+ return;
144764
+ }
144765
+ if (current2.type === "Identifier") {
144766
+ const nonValue = parent && key2 ? isNonValueIdentifierSlot3(parent, key2) : false;
144767
+ if (!nonValue && current2.name !== "undefined" && !earlierParams.has(current2.name)) {
144768
+ safe = false;
144769
+ }
144770
+ return;
144771
+ }
144772
+ for (const childKey of Object.keys(current2)) {
144773
+ if (SKIP_KEYS3.has(childKey)) continue;
144774
+ const child = current2[childKey];
144775
+ if (Array.isArray(child)) {
144776
+ for (const item of child) visit(item, current2, childKey);
144777
+ } else {
144778
+ visit(child, current2, childKey);
144779
+ }
144780
+ }
144781
+ };
144782
+ visit(node);
144783
+ return safe;
144784
+ }
144785
+ function supportedParam3(param, earlier) {
144786
+ if (param.type === "Identifier") return { name: param.name };
144787
+ if (param.type !== "AssignmentPattern" || param.left?.type !== "Identifier") return null;
144788
+ if (!isSafeDefaultExpression3(param.right, earlier)) return null;
144789
+ return { name: param.left.name, defaultExpression: param.right };
144790
+ }
144791
+ function supportedParams3(fn) {
144792
+ if (SUPPORTED_PARAMS_CACHE3.has(fn)) return SUPPORTED_PARAMS_CACHE3.get(fn) ?? null;
144793
+ const params = [];
144794
+ const earlier = /* @__PURE__ */ new Set();
144795
+ for (const param of fn.params ?? []) {
144796
+ const parsed = supportedParam3(param, earlier);
144797
+ if (!parsed) {
144798
+ SUPPORTED_PARAMS_CACHE3.set(fn, null);
144799
+ return null;
144800
+ }
144801
+ params.push(parsed);
144802
+ earlier.add(parsed.name);
144803
+ }
144804
+ SUPPORTED_PARAMS_CACHE3.set(fn, params);
144805
+ return params;
144806
+ }
143730
144807
  function isShapeEligible3(fn) {
143731
- return isFunctionNode6(fn) && fn.body?.type === "BlockStatement" && !(fn.params ?? []).some((p2) => p2.type !== "Identifier");
144808
+ return isFunctionNode6(fn) && fn.body?.type === "BlockStatement" && supportedParams3(fn) !== null;
143732
144809
  }
143733
144810
  function callsAny3(node, names) {
143734
144811
  let hit = false;
@@ -143778,20 +144855,55 @@ function timelineBuildingNames3(candidates, timelineVar) {
143778
144855
  function bump3(counts, key2) {
143779
144856
  counts.set(key2, (counts.get(key2) ?? 0) + 1);
143780
144857
  }
144858
+ function undefinedIdentifier3() {
144859
+ return { type: "Identifier", name: "undefined" };
144860
+ }
144861
+ function isExplicitUndefined3(node) {
144862
+ return node?.type === "Identifier" && node.name === "undefined" || node?.type === "UnaryExpression" && node.operator === "void" && node.argument?.type === "Literal" && node.argument.value === 0;
144863
+ }
144864
+ function resolveHelperBindings3(call, params) {
144865
+ if (call.arguments?.some((arg) => arg?.type === "SpreadElement")) return null;
144866
+ const bindings = /* @__PURE__ */ new Map();
144867
+ for (let i2 = 0; i2 < params.length; i2++) {
144868
+ const param = params[i2];
144869
+ const arg = call.arguments?.[i2];
144870
+ if (arg && !isExplicitUndefined3(arg)) {
144871
+ bindings.set(param.name, arg);
144872
+ } else if (param.defaultExpression) {
144873
+ bindings.set(param.name, substituteParams3(cloneNode4(param.defaultExpression), bindings));
144874
+ } else {
144875
+ bindings.set(param.name, undefinedIdentifier3());
144876
+ }
144877
+ }
144878
+ return bindings;
144879
+ }
144880
+ function statementHelperCall3(node, names) {
144881
+ if (node.type !== "ExpressionStatement") return void 0;
144882
+ const expression = node.expression;
144883
+ if (expression?.type !== "CallExpression" || expression.callee?.type !== "Identifier") {
144884
+ return void 0;
144885
+ }
144886
+ return names.has(expression.callee.name) ? expression : void 0;
144887
+ }
143781
144888
  function safelyDroppable3(program, candidates) {
143782
144889
  const names = new Set(candidates.keys());
143783
144890
  const totalIds = /* @__PURE__ */ new Map();
143784
144891
  const stmtCalls = /* @__PURE__ */ new Map();
144892
+ const unbindable = /* @__PURE__ */ new Set();
143785
144893
  walkNodes3(program, (n2) => {
143786
144894
  if (n2.type === "Identifier" && names.has(n2.name)) bump3(totalIds, n2.name);
143787
- const e3 = n2.type === "ExpressionStatement" ? n2.expression : void 0;
143788
- if (e3?.type === "CallExpression" && e3.callee?.type === "Identifier" && names.has(e3.callee.name)) {
143789
- bump3(stmtCalls, e3.callee.name);
143790
- }
144895
+ const call = statementHelperCall3(n2, names);
144896
+ if (!call) return;
144897
+ bump3(stmtCalls, call.callee.name);
144898
+ const fn = candidates.get(call.callee.name);
144899
+ const params = fn && supportedParams3(fn);
144900
+ if (!params || !resolveHelperBindings3(call, params)) unbindable.add(call.callee.name);
143791
144901
  });
143792
144902
  const safe = /* @__PURE__ */ new Map();
143793
144903
  for (const [name, fn] of candidates) {
143794
- if ((totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) safe.set(name, fn);
144904
+ if (!unbindable.has(name) && (totalIds.get(name) ?? 0) === 1 + (stmtCalls.get(name) ?? 0)) {
144905
+ safe.set(name, fn);
144906
+ }
143795
144907
  }
143796
144908
  return safe;
143797
144909
  }
@@ -143834,11 +144946,11 @@ function expandBody3(bodyStmts, bindings, prov, ctx) {
143834
144946
  }
143835
144947
  function inlineHelper3(call, ctx) {
143836
144948
  const fn = ctx.helpers.get(call.callee.name);
143837
- const bindings = /* @__PURE__ */ new Map();
143838
- (fn.params ?? []).forEach((p2, i2) => {
143839
- const arg = call.arguments?.[i2];
143840
- if (arg) bindings.set(p2.name, arg);
143841
- });
144949
+ if (!fn) return null;
144950
+ const params = supportedParams3(fn);
144951
+ if (!params) return null;
144952
+ const bindings = resolveHelperBindings3(call, params);
144953
+ if (!bindings) return null;
143842
144954
  const prov = {
143843
144955
  kind: "helper",
143844
144956
  fn: call.callee.name,
@@ -145157,7 +146269,7 @@ function parseGsapScriptAcorn3(script) {
145157
146269
  return { animations: [], timelineVar: "tl", preamble: "", postamble: "" };
145158
146270
  }
145159
146271
  }
145160
- var recast3, import_parser4, PROPERTY_GROUPS6, PROP_TO_GROUP6, roundPercentage5, SKIP_KEYS3, FUNCTION_TYPES3, GSAP_METHODS6, MAX_DEPTH3, MAX_ITERS3, GSAP_METHODS23, QUERY_METHODS5, ITERATION_METHODS5, SCOPE_NODE_TYPES5, CONST_NODES4, MATH_FNS4, MATH_CONSTS4, BUILTIN_VAR_KEYS5, DROPPED_VAR_KEYS5, EXTRAS_KEYS5, PERCENTAGE_KEY_RE5, GSAP_DEFAULT_DURATION5;
146272
+ var recast3, import_parser4, PROPERTY_GROUPS6, PROP_TO_GROUP6, roundPercentage5, SKIP_KEYS3, FUNCTION_TYPES3, GSAP_METHODS6, MAX_DEPTH3, MAX_ITERS3, SAFE_DEFAULT_NODES3, SUPPORTED_PARAMS_CACHE3, GSAP_METHODS23, QUERY_METHODS5, ITERATION_METHODS5, SCOPE_NODE_TYPES5, CONST_NODES4, MATH_FNS4, MATH_CONSTS4, BUILTIN_VAR_KEYS5, DROPPED_VAR_KEYS5, EXTRAS_KEYS5, PERCENTAGE_KEY_RE5, GSAP_DEFAULT_DURATION5;
145161
146273
  var init_gsapParserExports = __esm({
145162
146274
  "../parsers/dist/gsapParserExports.js"() {
145163
146275
  "use strict";
@@ -145187,6 +146299,23 @@ var init_gsapParserExports = __esm({
145187
146299
  GSAP_METHODS6 = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
145188
146300
  MAX_DEPTH3 = 8;
145189
146301
  MAX_ITERS3 = 512;
146302
+ SAFE_DEFAULT_NODES3 = /* @__PURE__ */ new Set([
146303
+ "ArrayExpression",
146304
+ "BinaryExpression",
146305
+ "ChainExpression",
146306
+ "ConditionalExpression",
146307
+ "Identifier",
146308
+ "Literal",
146309
+ "LogicalExpression",
146310
+ "MemberExpression",
146311
+ "ObjectExpression",
146312
+ "Property",
146313
+ "SpreadElement",
146314
+ "TemplateElement",
146315
+ "TemplateLiteral",
146316
+ "UnaryExpression"
146317
+ ]);
146318
+ SUPPORTED_PARAMS_CACHE3 = /* @__PURE__ */ new WeakMap();
145190
146319
  GSAP_METHODS23 = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
145191
146320
  QUERY_METHODS5 = /* @__PURE__ */ new Set(["querySelector", "querySelectorAll"]);
145192
146321
  ITERATION_METHODS5 = /* @__PURE__ */ new Set(["forEach", "map"]);
@@ -146555,7 +147684,7 @@ __export(info_exports, {
146555
147684
  examples: () => examples16,
146556
147685
  orientation: () => orientation
146557
147686
  });
146558
- import { readFileSync as readFileSync60, readdirSync as readdirSync29, statSync as statSync33 } from "fs";
147687
+ import { readFileSync as readFileSync60, readdirSync as readdirSync30, statSync as statSync33 } from "fs";
146559
147688
  import { join as join98 } from "path";
146560
147689
  function orientation(width, height) {
146561
147690
  if (width > height) return "landscape";
@@ -146569,7 +147698,7 @@ function durationFromHtml(html, fallback) {
146569
147698
  }
146570
147699
  function totalSize(dir) {
146571
147700
  let total = 0;
146572
- for (const entry of readdirSync29(dir, { withFileTypes: true })) {
147701
+ for (const entry of readdirSync30(dir, { withFileTypes: true })) {
146573
147702
  const path2 = join98(dir, entry.name);
146574
147703
  if (entry.isDirectory()) {
146575
147704
  total += totalSize(path2);
@@ -148018,7 +149147,7 @@ __export(synthesize_exports, {
148018
149147
  synthesize: () => synthesize
148019
149148
  });
148020
149149
  import { execFileSync as execFileSync14 } from "child_process";
148021
- import { existsSync as existsSync95, writeFileSync as writeFileSync38, mkdirSync as mkdirSync48, readdirSync as readdirSync30, unlinkSync as unlinkSync7 } from "fs";
149150
+ import { existsSync as existsSync95, writeFileSync as writeFileSync38, mkdirSync as mkdirSync48, readdirSync as readdirSync31, unlinkSync as unlinkSync8 } from "fs";
148022
149151
  import { join as join104, dirname as dirname50, basename as basename20 } from "path";
148023
149152
  import { homedir as homedir19 } from "os";
148024
149153
  function ensureSynthScript() {
@@ -148027,10 +149156,10 @@ function ensureSynthScript() {
148027
149156
  writeFileSync38(SCRIPT_PATH, SYNTH_SCRIPT);
148028
149157
  const currentName = basename20(SCRIPT_PATH);
148029
149158
  try {
148030
- for (const entry of readdirSync30(SCRIPT_DIR)) {
149159
+ for (const entry of readdirSync31(SCRIPT_DIR)) {
148031
149160
  if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
148032
149161
  try {
148033
- unlinkSync7(join104(SCRIPT_DIR, entry));
149162
+ unlinkSync8(join104(SCRIPT_DIR, entry));
148034
149163
  } catch {
148035
149164
  }
148036
149165
  }
@@ -148875,7 +150004,7 @@ __export(upgrade_exports, {
148875
150004
  upgradeProjectPins: () => upgradeProjectPins
148876
150005
  });
148877
150006
  import { execFileSync as execFileSync16 } from "child_process";
148878
- import { existsSync as existsSync99, readFileSync as readFileSync66, writeFileSync as writeFileSync39, renameSync as renameSync15 } from "fs";
150007
+ import { existsSync as existsSync99, readFileSync as readFileSync66, writeFileSync as writeFileSync39, renameSync as renameSync14 } from "fs";
148879
150008
  import { resolve as resolve65 } from "path";
148880
150009
  async function confirmUpgrade() {
148881
150010
  const shouldUpgrade = await ue({ message: "Upgrade now?" });
@@ -148948,7 +150077,7 @@ async function upgradeProjectPins(dir, opts) {
148948
150077
  const tmp = `${pkgPath}.tmp`;
148949
150078
  writeFileSync39(tmp, `${JSON.stringify(raw, null, 2)}
148950
150079
  `, "utf-8");
148951
- renameSync15(tmp, pkgPath);
150080
+ renameSync14(tmp, pkgPath);
148952
150081
  }
148953
150082
  return { changed: rewrite.changed, from: rewrite.fromVersions, to: latest, path: pkgPath };
148954
150083
  }
@@ -149215,7 +150344,7 @@ __export(feedback_exports, {
149215
150344
  default: () => feedback_default,
149216
150345
  examples: () => examples26
149217
150346
  });
149218
- import { randomUUID as randomUUID9 } from "crypto";
150347
+ import { randomUUID as randomUUID10 } from "crypto";
149219
150348
  import { resolve as resolve66 } from "path";
149220
150349
  import open from "open";
149221
150350
  function normalizeComment(raw) {
@@ -149368,7 +150497,7 @@ var init_feedback2 = __esm({
149368
150497
  }
149369
150498
  const comment = normalizeComment(args.comment);
149370
150499
  const doctorSummary = await getDoctorSummary();
149371
- const feedbackId = randomUUID9();
150500
+ const feedbackId = randomUUID10();
149372
150501
  const config = readConfig();
149373
150502
  const joinKeys = buildTelemetryJoinKeys({
149374
150503
  feedbackId,
@@ -149593,7 +150722,7 @@ __export(contactSheet_exports, {
149593
150722
  createSvgContactSheet: () => createSvgContactSheet
149594
150723
  });
149595
150724
  import sharp from "sharp";
149596
- import { readdirSync as readdirSync31, readFileSync as readFileSync67, writeFileSync as writeFileSync40, unlinkSync as unlinkSync8, existsSync as existsSync100 } from "fs";
150725
+ import { readdirSync as readdirSync33, readFileSync as readFileSync67, writeFileSync as writeFileSync40, unlinkSync as unlinkSync9, existsSync as existsSync100 } from "fs";
149597
150726
  import { join as join106, extname as extname19, basename as basename21, dirname as dirname53 } from "path";
149598
150727
  async function createContactSheet(imagePaths, outputPath, opts = {}) {
149599
150728
  const {
@@ -149681,7 +150810,7 @@ async function createContactSheetPages(imagePaths, outputBasePath, opts = {}, la
149681
150810
  }
149682
150811
  async function createScrollContactSheet(screenshotsDir, outputPath, budget = {}) {
149683
150812
  if (!existsSync100(screenshotsDir)) return [];
149684
- const scrollFiles = readdirSync31(screenshotsDir).filter((f3) => f3.startsWith("scroll-") && f3.endsWith(".png")).sort();
150813
+ const scrollFiles = readdirSync33(screenshotsDir).filter((f3) => f3.startsWith("scroll-") && f3.endsWith(".png")).sort();
149685
150814
  if (scrollFiles.length === 0) return [];
149686
150815
  const paths = scrollFiles.map((f3) => join106(screenshotsDir, f3));
149687
150816
  const labels = scrollFiles.map((f3) => {
@@ -149698,7 +150827,7 @@ async function createScrollContactSheet(screenshotsDir, outputPath, budget = {})
149698
150827
  }
149699
150828
  async function createSnapshotContactSheet(snapshotsDir, outputPath, budget = {}) {
149700
150829
  if (!existsSync100(snapshotsDir)) return [];
149701
- const snapshotFiles = readdirSync31(snapshotsDir).filter((f3) => f3.startsWith("frame-") && f3.endsWith(".png")).sort();
150830
+ const snapshotFiles = readdirSync33(snapshotsDir).filter((f3) => f3.startsWith("frame-") && f3.endsWith(".png")).sort();
149702
150831
  if (snapshotFiles.length === 0) return [];
149703
150832
  const paths = snapshotFiles.map((f3) => join106(snapshotsDir, f3));
149704
150833
  const labels = snapshotFiles.map((f3) => {
@@ -149716,7 +150845,7 @@ async function createSnapshotContactSheet(snapshotsDir, outputPath, budget = {})
149716
150845
  async function createAssetContactSheet(assetsDir, outputPath, budget = {}) {
149717
150846
  if (!existsSync100(assetsDir)) return [];
149718
150847
  const imageExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp"]);
149719
- const assetFiles = readdirSync31(assetsDir).filter((f3) => imageExts.has(extname19(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
150848
+ const assetFiles = readdirSync33(assetsDir).filter((f3) => imageExts.has(extname19(f3).toLowerCase()) && !f3.includes("contact-sheet")).sort();
149720
150849
  if (assetFiles.length === 0) return [];
149721
150850
  const paths = assetFiles.map((f3) => join106(assetsDir, f3));
149722
150851
  return createContactSheetPages(paths, outputPath, {
@@ -149735,7 +150864,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir, budget
149735
150864
  const seen = /* @__PURE__ */ new Set();
149736
150865
  const svgPaths = [];
149737
150866
  for (const dir of dirsToScan) {
149738
- for (const f3 of readdirSync31(dir).filter((f4) => f4.endsWith(".svg")).sort()) {
150867
+ for (const f3 of readdirSync33(dir).filter((f4) => f4.endsWith(".svg")).sort()) {
149739
150868
  if (!seen.has(f3)) {
149740
150869
  seen.add(f3);
149741
150870
  svgPaths.push(join106(dir, f3));
@@ -149782,7 +150911,7 @@ async function createSvgContactSheet(svgsDir, outputPath, assetsRootDir, budget
149782
150911
  } finally {
149783
150912
  for (const tmp of tmpPaths) {
149784
150913
  try {
149785
- unlinkSync8(tmp);
150914
+ unlinkSync9(tmp);
149786
150915
  } catch {
149787
150916
  }
149788
150917
  }
@@ -155954,7 +157083,7 @@ var require_node_domexception = __commonJS({
155954
157083
  });
155955
157084
 
155956
157085
  // ../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js
155957
- import { statSync as statSync35, createReadStream as createReadStream7, promises as fs3 } from "fs";
157086
+ import { statSync as statSync35, createReadStream as createReadStream8, promises as fs3 } from "fs";
155958
157087
  import { basename as basename23 } from "path";
155959
157088
  var import_node_domexception, stat, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
155960
157089
  var init_from = __esm({
@@ -156006,7 +157135,7 @@ var init_from = __esm({
156006
157135
  if (mtimeMs > this.lastModified) {
156007
157136
  throw new import_node_domexception.default("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.", "NotReadableError");
156008
157137
  }
156009
- yield* createReadStream7(this.#path, {
157138
+ yield* createReadStream8(this.#path, {
156010
157139
  start: this.#start,
156011
157140
  end: this.#start + this.size - 1
156012
157141
  });
@@ -157673,7 +158802,7 @@ var require_gaxios = __commonJS({
157673
158802
  var retry_js_1 = require_retry3();
157674
158803
  var stream_1 = __require("stream");
157675
158804
  var interceptor_js_1 = require_interceptor();
157676
- var randomUUID10 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
158805
+ var randomUUID11 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
157677
158806
  var HTTP_STATUS_NO_CONTENT = 204;
157678
158807
  var Gaxios = class {
157679
158808
  agentCache = /* @__PURE__ */ new Map();
@@ -157946,7 +159075,7 @@ var require_gaxios = __commonJS({
157946
159075
  */
157947
159076
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
157948
159077
  if (opts.multipart?.length) {
157949
- const boundary = await randomUUID10();
159078
+ const boundary = await randomUUID11();
157950
159079
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
157951
159080
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
157952
159081
  } else if (shouldDirectlyPassData) {
@@ -189703,8 +190832,8 @@ async function captureSnapshots(projectDir, opts) {
189703
190832
  const snapshotDir = opts.outputDir ?? join107(projectDir, "snapshots");
189704
190833
  mkdirSync49(snapshotDir, { recursive: true });
189705
190834
  try {
189706
- const { readdirSync: readdirSync38 } = await import("fs");
189707
- for (const file of readdirSync38(snapshotDir)) {
190835
+ const { readdirSync: readdirSync39 } = await import("fs");
190836
+ for (const file of readdirSync39(snapshotDir)) {
189708
190837
  if (/\.(png|jpg|jpeg)$/i.test(file)) {
189709
190838
  rmSync30(join107(snapshotDir, file), { force: true });
189710
190839
  }
@@ -190159,6 +191288,7 @@ function probeMedia2(mediaPath, ffprobePath) {
190159
191288
  "stream=color_space,color_transfer,color_primaries,pix_fmt,duration:format=duration",
190160
191289
  "-of",
190161
191290
  "json",
191291
+ "--",
190162
191292
  mediaPath
190163
191293
  ], { encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "pipe"] });
190164
191294
  const parsed = asRecord(JSON.parse(raw));
@@ -191614,7 +192744,7 @@ __export(compare_exports, {
191614
192744
  parseCompareArgs: () => parseCompareArgs,
191615
192745
  prepareCompareVariantProjects: () => prepareCompareVariantProjects
191616
192746
  });
191617
- import { cpSync as cpSync6, existsSync as existsSync105, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync17, renameSync as renameSync16, rmSync as rmSync32, statSync as statSync36 } from "fs";
192747
+ import { cpSync as cpSync6, existsSync as existsSync105, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync17, renameSync as renameSync15, rmSync as rmSync32, statSync as statSync36 } from "fs";
191618
192748
  import { tmpdir as tmpdir17 } from "os";
191619
192749
  import { basename as basename28, dirname as dirname55, extname as extname23, join as join110 } from "path";
191620
192750
  function defaultLabelForPath(input2) {
@@ -191726,7 +192856,7 @@ function stageHtmlVariant(variant) {
191726
192856
  });
191727
192857
  const sourceName = basename28(variant.inputPath);
191728
192858
  if (sourceName !== "index.html") {
191729
- renameSync16(join110(stagedDir, sourceName), join110(stagedDir, "index.html"));
192859
+ renameSync15(join110(stagedDir, sourceName), join110(stagedDir, "index.html"));
191730
192860
  }
191731
192861
  return {
191732
192862
  ...variant,
@@ -192304,7 +193434,7 @@ __export(video_exports, {
192304
193434
  runVideoMode: () => runVideoMode,
192305
193435
  safeFilename: () => safeFilename
192306
193436
  });
192307
- import { createWriteStream as createWriteStream4, existsSync as existsSync106, mkdirSync as mkdirSync54, readFileSync as readFileSync71, unlinkSync as unlinkSync9 } from "fs";
193437
+ import { createWriteStream as createWriteStream4, existsSync as existsSync106, mkdirSync as mkdirSync54, readFileSync as readFileSync71, unlinkSync as unlinkSync10 } from "fs";
192308
193438
  import { resolve as resolve71, join as join113, basename as basename29 } from "path";
192309
193439
  async function streamToFile(url, destPath) {
192310
193440
  const r2 = await safeFetch(url, {
@@ -192367,7 +193497,7 @@ async function streamToFile(url, destPath) {
192367
193497
  file.destroy();
192368
193498
  if (e3.code !== "EEXIST") {
192369
193499
  try {
192370
- unlinkSync9(destPath);
193500
+ unlinkSync10(destPath);
192371
193501
  } catch {
192372
193502
  }
192373
193503
  }
@@ -193726,7 +194856,7 @@ var init_designStyleExtractor = __esm({
193726
194856
  });
193727
194857
 
193728
194858
  // src/capture/fontMetadataExtractor.ts
193729
- import { readdirSync as readdirSync33, readFileSync as readFileSync73, writeFileSync as writeFileSync46, existsSync as existsSync107 } from "fs";
194859
+ import { readdirSync as readdirSync34, readFileSync as readFileSync73, writeFileSync as writeFileSync46, existsSync as existsSync107 } from "fs";
193730
194860
  import { join as join114 } from "path";
193731
194861
  import * as fontkit from "fontkit";
193732
194862
  function isFontCollection(value) {
@@ -193736,7 +194866,7 @@ function extractFontMetadata(fontsDir, outputPath) {
193736
194866
  const files = [];
193737
194867
  const unidentified = [];
193738
194868
  if (existsSync107(fontsDir)) {
193739
- const fontFiles = readdirSync33(fontsDir).filter((f3) => /\.(woff2?|ttf|otf)$/i.test(f3));
194869
+ const fontFiles = readdirSync34(fontsDir).filter((f3) => /\.(woff2?|ttf|otf)$/i.test(f3));
193740
194870
  for (const filename of fontFiles) {
193741
194871
  const fullPath = join114(fontsDir, filename);
193742
194872
  const meta = readSingleFont(fullPath, filename);
@@ -194049,7 +195179,7 @@ var init_animationCataloger = __esm({
194049
195179
  });
194050
195180
 
194051
195181
  // src/capture/mediaCapture.ts
194052
- import { mkdirSync as mkdirSync55, writeFileSync as writeFileSync47, readdirSync as readdirSync34, readFileSync as readFileSync74, statSync as statSync37 } from "fs";
195182
+ import { mkdirSync as mkdirSync55, writeFileSync as writeFileSync47, readdirSync as readdirSync35, readFileSync as readFileSync74, statSync as statSync37 } from "fs";
194053
195183
  import { join as join115, extname as extname25 } from "path";
194054
195184
  function liveRemainingMs(budget, fallbackMs) {
194055
195185
  return budget.remainingMs?.() ?? fallbackMs;
@@ -194118,7 +195248,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir, budget
194118
195248
  const manifest = [];
194119
195249
  const previewDir = join115(lottieDir, "previews");
194120
195250
  mkdirSync55(previewDir, { recursive: true });
194121
- for (const file of readdirSync34(lottieDir)) {
195251
+ for (const file of readdirSync35(lottieDir)) {
194122
195252
  if (!file.endsWith(".json")) continue;
194123
195253
  if (liveRemainingMs(budget, 1) <= 0) break;
194124
195254
  try {
@@ -194434,7 +195564,7 @@ var init_mediaCapture = __esm({
194434
195564
  });
194435
195565
 
194436
195566
  // src/capture/contentExtractor.ts
194437
- import { existsSync as existsSync108, readdirSync as readdirSync35, statSync as statSync38, readFileSync as readFileSync75 } from "fs";
195567
+ import { existsSync as existsSync108, readdirSync as readdirSync36, statSync as statSync38, readFileSync as readFileSync75 } from "fs";
194438
195568
  import { basename as basename30, join as join116 } from "path";
194439
195569
  function resolveVisionPhaseCompletion(outcome, remainingMs) {
194440
195570
  if (outcome.budgetExhausted || remainingMs <= 0) {
@@ -194673,7 +195803,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
194673
195803
  return response.text?.trim() || "";
194674
195804
  };
194675
195805
  }
194676
- const imageFiles = readdirSync35(join116(outputDir, "assets")).filter(
195806
+ const imageFiles = readdirSync36(join116(outputDir, "assets")).filter(
194677
195807
  (f3) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f3)
194678
195808
  );
194679
195809
  const BATCH_SIZE = 20;
@@ -194735,12 +195865,12 @@ async function captionImagesWithGemini(outputDir, progress, warnings, options =
194735
195865
  );
194736
195866
  const svgFiles = [];
194737
195867
  const assetsDir = join116(outputDir, "assets");
194738
- for (const f3 of readdirSync35(assetsDir)) {
195868
+ for (const f3 of readdirSync36(assetsDir)) {
194739
195869
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: f3 });
194740
195870
  }
194741
195871
  const svgsSubdir = join116(assetsDir, "svgs");
194742
195872
  if (existsSync108(svgsSubdir)) {
194743
- for (const f3 of readdirSync35(svgsSubdir)) {
195873
+ for (const f3 of readdirSync36(svgsSubdir)) {
194744
195874
  if (/\.svg$/i.test(f3)) svgFiles.push({ file: f3, relPath: `svgs/${f3}` });
194745
195875
  }
194746
195876
  }
@@ -194840,7 +195970,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
194840
195970
  const fontLines = [];
194841
195971
  const assetsPath = join116(outputDir, "assets");
194842
195972
  try {
194843
- for (const file of readdirSync35(assetsPath)) {
195973
+ for (const file of readdirSync36(assetsPath)) {
194844
195974
  if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
194845
195975
  const filePath = join116(assetsPath, file);
194846
195976
  const stat3 = statSync38(filePath);
@@ -194872,7 +196002,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
194872
196002
  }
194873
196003
  try {
194874
196004
  const svgsPath = join116(assetsPath, "svgs");
194875
- for (const file of readdirSync35(svgsPath)) {
196005
+ for (const file of readdirSync36(svgsPath)) {
194876
196006
  if (!file.endsWith(".svg")) continue;
194877
196007
  const svgMatch = tokens.svgs.find(
194878
196008
  (s2) => s2.label && file.includes(
@@ -194891,7 +196021,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
194891
196021
  }
194892
196022
  try {
194893
196023
  const fontsPath = join116(assetsPath, "fonts");
194894
- for (const file of readdirSync35(fontsPath)) {
196024
+ for (const file of readdirSync36(fontsPath)) {
194895
196025
  fontLines.push(`fonts/${file} \u2014 font file`);
194896
196026
  }
194897
196027
  } catch {
@@ -194934,7 +196064,7 @@ var agentPromptGenerator_exports = {};
194934
196064
  __export(agentPromptGenerator_exports, {
194935
196065
  generateAgentPrompt: () => generateAgentPrompt
194936
196066
  });
194937
- import { writeFileSync as writeFileSync48, readdirSync as readdirSync36, existsSync as existsSync109 } from "fs";
196067
+ import { writeFileSync as writeFileSync48, readdirSync as readdirSync37, existsSync as existsSync109 } from "fs";
194938
196068
  import { join as join117 } from "path";
194939
196069
  function inferColorRole(hex) {
194940
196070
  const r2 = parseInt(hex.slice(1, 3), 16) / 255;
@@ -194970,7 +196100,7 @@ function buildPrompt(outputDir, url, tokens, hasScreenshot, hasLottie, hasShader
194970
196100
  const baseName = baseFile.replace(/\.jpg$/, "");
194971
196101
  const escapedBase = baseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
194972
196102
  const paginatedRe = new RegExp(`^${escapedBase}(?:-(\\d+))?\\.jpg$`);
194973
- const all = readdirSync36(fullDir).filter((f3) => paginatedRe.test(f3)).map((f3) => ({ name: f3, page: parseInt(f3.match(paginatedRe)?.[1] ?? "0", 10) })).sort((a, b2) => a.page - b2.page).map((entry) => entry.name);
196103
+ const all = readdirSync37(fullDir).filter((f3) => paginatedRe.test(f3)).map((f3) => ({ name: f3, page: parseInt(f3.match(paginatedRe)?.[1] ?? "0", 10) })).sort((a, b2) => a.page - b2.page).map((entry) => entry.name);
194974
196104
  if (all.length === 0) return [];
194975
196105
  if (all.length === 1) {
194976
196106
  return [`| \`${dir}/${all[0]}\` | ${label2} |`];
@@ -196560,7 +197690,7 @@ __export(state_exports, {
196560
197690
  stateFilePath: () => stateFilePath,
196561
197691
  writeStackOutputs: () => writeStackOutputs
196562
197692
  });
196563
- import { existsSync as existsSync113, mkdirSync as mkdirSync58, readdirSync as readdirSync37, readFileSync as readFileSync77, rmSync as rmSync33, writeFileSync as writeFileSync53 } from "fs";
197693
+ import { existsSync as existsSync113, mkdirSync as mkdirSync58, readdirSync as readdirSync38, readFileSync as readFileSync77, rmSync as rmSync33, writeFileSync as writeFileSync53 } from "fs";
196564
197694
  import { dirname as dirname56, join as join121 } from "path";
196565
197695
  function stateFilePath(stackName = DEFAULT_STACK_NAME, cwd = process.cwd()) {
196566
197696
  return join121(cwd, STATE_DIR_NAME, `${STATE_FILE_PREFIX}${stackName}.json`);
@@ -196587,7 +197717,7 @@ function deleteStackOutputs(stackName = DEFAULT_STACK_NAME, cwd = process.cwd())
196587
197717
  function listStackNames(cwd = process.cwd()) {
196588
197718
  const dir = join121(cwd, STATE_DIR_NAME);
196589
197719
  if (!existsSync113(dir)) return [];
196590
- return readdirSync37(dir).filter((f3) => f3.startsWith(STATE_FILE_PREFIX) && f3.endsWith(".json")).map((f3) => f3.slice(STATE_FILE_PREFIX.length, -".json".length));
197720
+ return readdirSync38(dir).filter((f3) => f3.startsWith(STATE_FILE_PREFIX) && f3.endsWith(".json")).map((f3) => f3.slice(STATE_FILE_PREFIX.length, -".json".length));
196591
197721
  }
196592
197722
  function requireStack(stackName, cwd = process.cwd()) {
196593
197723
  const stack = readStackOutputs(stackName, cwd);
@@ -199001,7 +200131,7 @@ var init_poll = __esm({
199001
200131
  });
199002
200132
 
199003
200133
  // src/cloud/download.ts
199004
- import { createWriteStream as createWriteStream5, mkdirSync as mkdirSync60, unlinkSync as unlinkSync10 } from "fs";
200134
+ import { createWriteStream as createWriteStream5, mkdirSync as mkdirSync60, unlinkSync as unlinkSync11 } from "fs";
199005
200135
  import { dirname as dirname58 } from "path";
199006
200136
  async function downloadToFile(url, destPath, options = {}) {
199007
200137
  const fetchImpl = options.fetchImpl ?? fetch;
@@ -199042,7 +200172,7 @@ async function downloadToFile(url, destPath, options = {}) {
199042
200172
  await closeFile(file);
199043
200173
  if (errored) {
199044
200174
  try {
199045
- unlinkSync10(destPath);
200175
+ unlinkSync11(destPath);
199046
200176
  } catch {
199047
200177
  }
199048
200178
  }