hyperframes 0.4.15-alpha.1 → 0.4.15

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
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.4.15-alpha.1" : "0.0.0-dev";
57
+ VERSION = true ? "0.4.15" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -9821,7 +9821,7 @@ import { get as httpsGet } from "https";
9821
9821
  import { pipeline } from "stream/promises";
9822
9822
  function downloadFile(url, dest) {
9823
9823
  const tmp = `${dest}.tmp`;
9824
- return new Promise((resolve36, reject) => {
9824
+ return new Promise((resolve37, reject) => {
9825
9825
  const follow = (u) => {
9826
9826
  httpsGet(u, (res) => {
9827
9827
  if (res.statusCode === 301 || res.statusCode === 302) {
@@ -9838,7 +9838,7 @@ function downloadFile(url, dest) {
9838
9838
  const file = createWriteStream(tmp);
9839
9839
  pipeline(res, file).then(() => {
9840
9840
  renameSync(tmp, dest);
9841
- resolve36();
9841
+ resolve37();
9842
9842
  }).catch((err) => {
9843
9843
  try {
9844
9844
  unlinkSync(tmp);
@@ -10556,7 +10556,7 @@ function hasNpx() {
10556
10556
  }
10557
10557
  }
10558
10558
  function runSkillsAdd(repo) {
10559
- return new Promise((resolve36, reject) => {
10559
+ return new Promise((resolve37, reject) => {
10560
10560
  const child = spawn("npx", ["skills", "add", repo, "--all"], {
10561
10561
  stdio: "inherit",
10562
10562
  timeout: 12e4,
@@ -10570,7 +10570,7 @@ function runSkillsAdd(repo) {
10570
10570
  env: { ...process.env, GIT_CLONE_PROTECTION_ACTIVE: "0" }
10571
10571
  });
10572
10572
  child.on("close", (code, signal) => {
10573
- if (code === 0) resolve36();
10573
+ if (code === 0) resolve37();
10574
10574
  else if (signal === "SIGINT" || code === 130) process.exit(0);
10575
10575
  else reject(new Error(`npx skills add exited with code ${code}`));
10576
10576
  });
@@ -15315,8 +15315,8 @@ var init_custom_element_registry = __esm({
15315
15315
  } : (element) => element.localName === localName;
15316
15316
  registry.set(localName, { Class, check });
15317
15317
  if (waiting.has(localName)) {
15318
- for (const resolve36 of waiting.get(localName))
15319
- resolve36(Class);
15318
+ for (const resolve37 of waiting.get(localName))
15319
+ resolve37(Class);
15320
15320
  waiting.delete(localName);
15321
15321
  }
15322
15322
  ownerDocument.querySelectorAll(
@@ -15356,13 +15356,13 @@ var init_custom_element_registry = __esm({
15356
15356
  */
15357
15357
  whenDefined(localName) {
15358
15358
  const { registry, waiting } = this;
15359
- return new Promise((resolve36) => {
15359
+ return new Promise((resolve37) => {
15360
15360
  if (registry.has(localName))
15361
- resolve36(registry.get(localName).Class);
15361
+ resolve37(registry.get(localName).Class);
15362
15362
  else {
15363
15363
  if (!waiting.has(localName))
15364
15364
  waiting.set(localName, []);
15365
- waiting.get(localName).push(resolve36);
15365
+ waiting.get(localName).push(resolve37);
15366
15366
  }
15367
15367
  });
15368
15368
  }
@@ -21068,12 +21068,12 @@ var require_CSSValueExpression = __commonJS({
21068
21068
  return false;
21069
21069
  }
21070
21070
  };
21071
- CSSOM.CSSValueExpression.prototype._parseJSString = function(token, idx, sep3) {
21072
- var endIdx = this._findMatchedIdx(token, idx, sep3), text;
21071
+ CSSOM.CSSValueExpression.prototype._parseJSString = function(token, idx, sep4) {
21072
+ var endIdx = this._findMatchedIdx(token, idx, sep4), text;
21073
21073
  if (endIdx === -1) {
21074
21074
  return false;
21075
21075
  } else {
21076
- text = token.substring(idx, endIdx + sep3.length);
21076
+ text = token.substring(idx, endIdx + sep4.length);
21077
21077
  return {
21078
21078
  idx: endIdx,
21079
21079
  text
@@ -21113,15 +21113,15 @@ var require_CSSValueExpression = __commonJS({
21113
21113
  if (!isLegal) {
21114
21114
  return false;
21115
21115
  } else {
21116
- var sep3 = "/";
21117
- return this._parseJSString(token, idx, sep3);
21116
+ var sep4 = "/";
21117
+ return this._parseJSString(token, idx, sep4);
21118
21118
  }
21119
21119
  };
21120
- CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep3) {
21120
+ CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep4) {
21121
21121
  var startIdx = idx, endIdx;
21122
21122
  var NOT_FOUND = -1;
21123
21123
  while (true) {
21124
- endIdx = token.indexOf(sep3, startIdx + 1);
21124
+ endIdx = token.indexOf(sep4, startIdx + 1);
21125
21125
  if (endIdx === -1) {
21126
21126
  endIdx = NOT_FOUND;
21127
21127
  break;
@@ -24755,7 +24755,7 @@ function resolveConfig(overrides) {
24755
24755
  hdr: (() => {
24756
24756
  const raw = env("PRODUCER_HDR_TRANSFER");
24757
24757
  if (raw === "hlg" || raw === "pq") return { transfer: raw };
24758
- return void 0;
24758
+ return false;
24759
24759
  })(),
24760
24760
  hdrAutoDetect: envBool("PRODUCER_HDR_AUTO_DETECT", DEFAULT_CONFIG2.hdrAutoDetect),
24761
24761
  audioGain: envNum("PRODUCER_AUDIO_GAIN", DEFAULT_CONFIG2.audioGain),
@@ -25220,7 +25220,8 @@ async function injectVideoFramesBatch(page, updates) {
25220
25220
  let img = video.nextElementSibling;
25221
25221
  const isNewImage = !img || !img.classList.contains("__render_frame__");
25222
25222
  const computedStyle = window.getComputedStyle(video);
25223
- const computedOpacity = parseFloat(computedStyle.opacity) || 1;
25223
+ const opacityParsed = parseFloat(computedStyle.opacity);
25224
+ const computedOpacity = Number.isNaN(opacityParsed) ? 1 : opacityParsed;
25224
25225
  const sourceIsStatic = !computedStyle.position || computedStyle.position === "static";
25225
25226
  if (isNewImage) {
25226
25227
  img = document.createElement("img");
@@ -25266,7 +25267,6 @@ async function injectVideoFramesBatch(page, updates) {
25266
25267
  img.style.opacity = String(computedOpacity);
25267
25268
  img.style.visibility = "visible";
25268
25269
  video.style.setProperty("visibility", "hidden", "important");
25269
- video.style.setProperty("opacity", "0", "important");
25270
25270
  video.style.setProperty("pointer-events", "none", "important");
25271
25271
  }
25272
25272
  if (pendingDecodes.length > 0) {
@@ -25293,7 +25293,6 @@ async function syncVideoFrameVisibility(page, activeVideoIds) {
25293
25293
  } else {
25294
25294
  video.style.removeProperty("display");
25295
25295
  video.style.setProperty("visibility", "hidden", "important");
25296
- video.style.setProperty("opacity", "0", "important");
25297
25296
  video.style.setProperty("pointer-events", "none", "important");
25298
25297
  if (hasImg) {
25299
25298
  img.style.visibility = "hidden";
@@ -25397,7 +25396,7 @@ async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100)
25397
25396
  while (Date.now() < deadline) {
25398
25397
  const ready = Boolean(await page.evaluate(expression));
25399
25398
  if (ready) return true;
25400
- await new Promise((resolve36) => setTimeout(resolve36, intervalMs));
25399
+ await new Promise((resolve37) => setTimeout(resolve37, intervalMs));
25401
25400
  }
25402
25401
  return Boolean(await page.evaluate(expression));
25403
25402
  }
@@ -25628,9 +25627,15 @@ async function captureFrameToBuffer(session, frameIndex, time) {
25628
25627
  return { buffer, captureTimeMs };
25629
25628
  }
25630
25629
  async function closeCaptureSession(session) {
25631
- if (session.page) await session.page.close().catch(() => {
25632
- });
25633
- if (session.browser) await releaseBrowser(session.browser, session.config);
25630
+ if (!session.pageReleased && session.page) {
25631
+ await session.page.close().catch(() => {
25632
+ });
25633
+ session.pageReleased = true;
25634
+ }
25635
+ if (!session.browserReleased && session.browser) {
25636
+ await releaseBrowser(session.browser, session.config);
25637
+ session.browserReleased = true;
25638
+ }
25634
25639
  session.isInitialized = false;
25635
25640
  }
25636
25641
  function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
@@ -25680,7 +25685,7 @@ var init_frameCapture = __esm({
25680
25685
  // ../engine/src/utils/gpuEncoder.ts
25681
25686
  import { spawn as spawn2 } from "child_process";
25682
25687
  async function detectGpuEncoder() {
25683
- return new Promise((resolve36) => {
25688
+ return new Promise((resolve37) => {
25684
25689
  const ffmpeg = spawn2("ffmpeg", ["-encoders"], {
25685
25690
  stdio: ["pipe", "pipe", "pipe"]
25686
25691
  });
@@ -25689,13 +25694,13 @@ async function detectGpuEncoder() {
25689
25694
  stdout2 += data.toString();
25690
25695
  });
25691
25696
  ffmpeg.on("close", () => {
25692
- if (stdout2.includes("h264_nvenc")) resolve36("nvenc");
25693
- else if (stdout2.includes("h264_videotoolbox")) resolve36("videotoolbox");
25694
- else if (stdout2.includes("h264_vaapi")) resolve36("vaapi");
25695
- else if (stdout2.includes("h264_qsv")) resolve36("qsv");
25696
- else resolve36(null);
25697
+ if (stdout2.includes("h264_nvenc")) resolve37("nvenc");
25698
+ else if (stdout2.includes("h264_videotoolbox")) resolve37("videotoolbox");
25699
+ else if (stdout2.includes("h264_vaapi")) resolve37("vaapi");
25700
+ else if (stdout2.includes("h264_qsv")) resolve37("qsv");
25701
+ else resolve37(null);
25697
25702
  });
25698
- ffmpeg.on("error", () => resolve36(null));
25703
+ ffmpeg.on("error", () => resolve37(null));
25699
25704
  });
25700
25705
  }
25701
25706
  async function getCachedGpuEncoder() {
@@ -25727,6 +25732,51 @@ var init_gpuEncoder = __esm({
25727
25732
  }
25728
25733
  });
25729
25734
 
25735
+ // ../engine/src/utils/hdr.ts
25736
+ function isHdrColorSpace(cs) {
25737
+ if (!cs) return false;
25738
+ return cs.colorPrimaries.includes("bt2020") || cs.colorSpace.includes("bt2020") || cs.colorTransfer === "smpte2084" || cs.colorTransfer === "arib-std-b67";
25739
+ }
25740
+ function detectTransfer(cs) {
25741
+ if (cs?.colorTransfer === "smpte2084") return "pq";
25742
+ return "hlg";
25743
+ }
25744
+ function getHdrEncoderColorParams(transfer, mastering = DEFAULT_HDR10_MASTERING) {
25745
+ const colorTrc = transfer === "pq" ? "smpte2084" : "arib-std-b67";
25746
+ const tagging = `colorprim=bt2020:transfer=${colorTrc}:colormatrix=bt2020nc`;
25747
+ const metadata = `master-display=${mastering.masterDisplay}:max-cll=${mastering.maxCll}`;
25748
+ return {
25749
+ colorPrimaries: "bt2020",
25750
+ colorTrc,
25751
+ colorspace: "bt2020nc",
25752
+ pixelFormat: "yuv420p10le",
25753
+ x265ColorParams: `${tagging}:${metadata}`,
25754
+ mastering
25755
+ };
25756
+ }
25757
+ function analyzeCompositionHdr(colorSpaces) {
25758
+ let hasPq = false;
25759
+ let hasHdr = false;
25760
+ for (const cs of colorSpaces) {
25761
+ if (!isHdrColorSpace(cs)) continue;
25762
+ hasHdr = true;
25763
+ if (cs?.colorTransfer === "smpte2084") hasPq = true;
25764
+ }
25765
+ if (!hasHdr) return { hasHdr: false, dominantTransfer: null };
25766
+ const dominantTransfer = hasPq ? "pq" : "hlg";
25767
+ return { hasHdr: true, dominantTransfer };
25768
+ }
25769
+ var DEFAULT_HDR10_MASTERING;
25770
+ var init_hdr = __esm({
25771
+ "../engine/src/utils/hdr.ts"() {
25772
+ "use strict";
25773
+ DEFAULT_HDR10_MASTERING = {
25774
+ masterDisplay: "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)",
25775
+ maxCll: "1000,400"
25776
+ };
25777
+ }
25778
+ });
25779
+
25730
25780
  // ../engine/src/utils/runFfmpeg.ts
25731
25781
  import { spawn as spawn3 } from "child_process";
25732
25782
  async function runFfmpeg(args, opts) {
@@ -25734,7 +25784,7 @@ async function runFfmpeg(args, opts) {
25734
25784
  const signal = opts?.signal;
25735
25785
  const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
25736
25786
  const onStderr = opts?.onStderr;
25737
- return new Promise((resolve36) => {
25787
+ return new Promise((resolve37) => {
25738
25788
  const ffmpeg = spawn3("ffmpeg", args);
25739
25789
  let stderr = "";
25740
25790
  const onAbort = () => {
@@ -25760,7 +25810,7 @@ async function runFfmpeg(args, opts) {
25760
25810
  ffmpeg.on("close", (code) => {
25761
25811
  clearTimeout(timer);
25762
25812
  if (signal) signal.removeEventListener("abort", onAbort);
25763
- resolve36({
25813
+ resolve37({
25764
25814
  success: !signal?.aborted && code === 0,
25765
25815
  exitCode: code,
25766
25816
  stderr,
@@ -25770,7 +25820,7 @@ async function runFfmpeg(args, opts) {
25770
25820
  ffmpeg.on("error", (err) => {
25771
25821
  clearTimeout(timer);
25772
25822
  if (signal) signal.removeEventListener("abort", onAbort);
25773
- resolve36({
25823
+ resolve37({
25774
25824
  success: false,
25775
25825
  exitCode: null,
25776
25826
  stderr: err.message,
@@ -25830,6 +25880,12 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
25830
25880
  pixelFormat = "yuv420p",
25831
25881
  useGpu = false
25832
25882
  } = options;
25883
+ if (options.hdr && codec === "h264") {
25884
+ console.warn(
25885
+ "[chunkEncoder] HDR is not supported with codec=h264 (libx264 has no HDR support). Stripping HDR metadata and tagging output as SDR/BT.709. Use codec=h265 for HDR output."
25886
+ );
25887
+ options = { ...options, hdr: void 0 };
25888
+ }
25833
25889
  const args = [...inputArgs, "-r", String(fps)];
25834
25890
  const shouldUseGpu = useGpu && gpuEncoder !== null;
25835
25891
  if (codec === "h264" || codec === "h265") {
@@ -25868,7 +25924,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
25868
25924
  if (bitrate) args.push("-b:v", bitrate);
25869
25925
  else args.push("-crf", String(quality));
25870
25926
  const xParamsFlag = codec === "h264" ? "-x264-params" : "-x265-params";
25871
- const colorParams = "colorprim=bt709:transfer=bt709:colormatrix=bt709";
25927
+ const colorParams = codec === "h265" && options.hdr ? getHdrEncoderColorParams(options.hdr.transfer).x265ColorParams : "colorprim=bt709:transfer=bt709:colormatrix=bt709";
25872
25928
  if (preset === "ultrafast") {
25873
25929
  args.push(xParamsFlag, `aq-mode=3:${colorParams}`);
25874
25930
  } else {
@@ -25892,16 +25948,30 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
25892
25948
  return [...args, "-y", outputPath];
25893
25949
  }
25894
25950
  if (codec === "h264" || codec === "h265") {
25895
- args.push(
25896
- "-colorspace:v",
25897
- "bt709",
25898
- "-color_primaries:v",
25899
- "bt709",
25900
- "-color_trc:v",
25901
- "bt709",
25902
- "-color_range",
25903
- "tv"
25904
- );
25951
+ if (options.hdr) {
25952
+ const transferTag = options.hdr.transfer === "pq" ? "smpte2084" : "arib-std-b67";
25953
+ args.push(
25954
+ "-colorspace:v",
25955
+ "bt2020nc",
25956
+ "-color_primaries:v",
25957
+ "bt2020",
25958
+ "-color_trc:v",
25959
+ transferTag,
25960
+ "-color_range",
25961
+ "tv"
25962
+ );
25963
+ } else {
25964
+ args.push(
25965
+ "-colorspace:v",
25966
+ "bt709",
25967
+ "-color_primaries:v",
25968
+ "bt709",
25969
+ "-color_trc:v",
25970
+ "bt709",
25971
+ "-color_range",
25972
+ "tv"
25973
+ );
25974
+ }
25905
25975
  if (gpuEncoder === "vaapi") {
25906
25976
  const vfIdx = args.indexOf("-vf");
25907
25977
  if (vfIdx !== -1) {
@@ -25941,7 +26011,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
25941
26011
  const inputPath = join19(framesDir, framePattern);
25942
26012
  const inputArgs = ["-framerate", String(options.fps), "-i", inputPath];
25943
26013
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
25944
- return new Promise((resolve36) => {
26014
+ return new Promise((resolve37) => {
25945
26015
  const ffmpeg = spawn4("ffmpeg", args);
25946
26016
  let stderr = "";
25947
26017
  const onAbort = () => {
@@ -25966,7 +26036,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
25966
26036
  if (signal) signal.removeEventListener("abort", onAbort);
25967
26037
  const durationMs = Date.now() - startTime;
25968
26038
  if (signal?.aborted) {
25969
- resolve36({
26039
+ resolve37({
25970
26040
  success: false,
25971
26041
  outputPath,
25972
26042
  durationMs,
@@ -25977,7 +26047,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
25977
26047
  return;
25978
26048
  }
25979
26049
  if (code !== 0) {
25980
- resolve36({
26050
+ resolve37({
25981
26051
  success: false,
25982
26052
  outputPath,
25983
26053
  durationMs,
@@ -25988,12 +26058,12 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
25988
26058
  return;
25989
26059
  }
25990
26060
  const fileSize = existsSync15(outputPath) ? statSync4(outputPath).size : 0;
25991
- resolve36({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
26061
+ resolve37({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
25992
26062
  });
25993
26063
  ffmpeg.on("error", (err) => {
25994
26064
  clearTimeout(timer);
25995
26065
  if (signal) signal.removeEventListener("abort", onAbort);
25996
- resolve36({
26066
+ resolve37({
25997
26067
  success: false,
25998
26068
  outputPath,
25999
26069
  durationMs: Date.now() - startTime,
@@ -26051,18 +26121,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26051
26121
  let gpuEncoder = null;
26052
26122
  if (options.useGpu) gpuEncoder = await getCachedGpuEncoder();
26053
26123
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
26054
- const chunkResult = await new Promise((resolve36) => {
26124
+ const chunkResult = await new Promise((resolve37) => {
26055
26125
  const ffmpeg = spawn4("ffmpeg", args);
26056
26126
  let stderr = "";
26057
26127
  ffmpeg.stderr.on("data", (d) => {
26058
26128
  stderr += d.toString();
26059
26129
  });
26060
26130
  ffmpeg.on("close", (code) => {
26061
- if (code === 0) resolve36({ success: true });
26062
- else resolve36({ success: false, error: `Chunk ${i2} encode failed: ${stderr.slice(-400)}` });
26131
+ if (code === 0) resolve37({ success: true });
26132
+ else resolve37({ success: false, error: `Chunk ${i2} encode failed: ${stderr.slice(-400)}` });
26063
26133
  });
26064
26134
  ffmpeg.on("error", (err) => {
26065
- resolve36({ success: false, error: `Chunk ${i2} encode error: ${err.message}` });
26135
+ resolve37({ success: false, error: `Chunk ${i2} encode error: ${err.message}` });
26066
26136
  });
26067
26137
  });
26068
26138
  if (!chunkResult.success) {
@@ -26092,18 +26162,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26092
26162
  "-y",
26093
26163
  outputPath
26094
26164
  ];
26095
- const concatResult = await new Promise((resolve36) => {
26165
+ const concatResult = await new Promise((resolve37) => {
26096
26166
  const ffmpeg = spawn4("ffmpeg", concatArgs);
26097
26167
  let stderr = "";
26098
26168
  ffmpeg.stderr.on("data", (d) => {
26099
26169
  stderr += d.toString();
26100
26170
  });
26101
26171
  ffmpeg.on("close", (code) => {
26102
- if (code === 0) resolve36({ success: true });
26103
- else resolve36({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
26172
+ if (code === 0) resolve37({ success: true });
26173
+ else resolve37({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
26104
26174
  });
26105
26175
  ffmpeg.on("error", (err) => {
26106
- resolve36({ success: false, error: `Chunk concat error: ${err.message}` });
26176
+ resolve37({ success: false, error: `Chunk concat error: ${err.message}` });
26107
26177
  });
26108
26178
  });
26109
26179
  if (!concatResult.success) {
@@ -26185,6 +26255,7 @@ var init_chunkEncoder = __esm({
26185
26255
  "use strict";
26186
26256
  init_config2();
26187
26257
  init_gpuEncoder();
26258
+ init_hdr();
26188
26259
  init_runFfmpeg();
26189
26260
  init_gpuEncoder();
26190
26261
  ENCODER_PRESETS = {
@@ -26195,51 +26266,6 @@ var init_chunkEncoder = __esm({
26195
26266
  }
26196
26267
  });
26197
26268
 
26198
- // ../engine/src/utils/hdr.ts
26199
- function isHdrColorSpace(cs) {
26200
- if (!cs) return false;
26201
- return cs.colorPrimaries.includes("bt2020") || cs.colorSpace.includes("bt2020") || cs.colorTransfer === "smpte2084" || cs.colorTransfer === "arib-std-b67";
26202
- }
26203
- function detectTransfer(cs) {
26204
- if (cs?.colorTransfer === "smpte2084") return "pq";
26205
- return "hlg";
26206
- }
26207
- function getHdrEncoderColorParams(transfer, mastering = DEFAULT_HDR10_MASTERING) {
26208
- const colorTrc = transfer === "pq" ? "smpte2084" : "arib-std-b67";
26209
- const tagging = `colorprim=bt2020:transfer=${colorTrc}:colormatrix=bt2020nc`;
26210
- const metadata = `master-display=${mastering.masterDisplay}:max-cll=${mastering.maxCll}`;
26211
- return {
26212
- colorPrimaries: "bt2020",
26213
- colorTrc,
26214
- colorspace: "bt2020nc",
26215
- pixelFormat: "yuv420p10le",
26216
- x265ColorParams: `${tagging}:${metadata}`,
26217
- mastering
26218
- };
26219
- }
26220
- function analyzeCompositionHdr(colorSpaces) {
26221
- let hasPq = false;
26222
- let hasHdr = false;
26223
- for (const cs of colorSpaces) {
26224
- if (!isHdrColorSpace(cs)) continue;
26225
- hasHdr = true;
26226
- if (cs?.colorTransfer === "smpte2084") hasPq = true;
26227
- }
26228
- if (!hasHdr) return { hasHdr: false, dominantTransfer: null };
26229
- const dominantTransfer = hasPq ? "pq" : "hlg";
26230
- return { hasHdr: true, dominantTransfer };
26231
- }
26232
- var DEFAULT_HDR10_MASTERING;
26233
- var init_hdr = __esm({
26234
- "../engine/src/utils/hdr.ts"() {
26235
- "use strict";
26236
- DEFAULT_HDR10_MASTERING = {
26237
- masterDisplay: "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)",
26238
- maxCll: "1000,400"
26239
- };
26240
- }
26241
- });
26242
-
26243
26269
  // ../engine/src/services/streamingEncoder.ts
26244
26270
  import { spawn as spawn5 } from "child_process";
26245
26271
  import { existsSync as existsSync16, mkdirSync as mkdirSync10, statSync as statSync5 } from "fs";
@@ -26247,37 +26273,37 @@ import { dirname as dirname6 } from "path";
26247
26273
  function createFrameReorderBuffer(startFrame, endFrame) {
26248
26274
  let cursor = startFrame;
26249
26275
  const pending = /* @__PURE__ */ new Map();
26250
- const enqueueAt = (frame, resolve36) => {
26276
+ const enqueueAt = (frame, resolve37) => {
26251
26277
  const list = pending.get(frame);
26252
26278
  if (list === void 0) {
26253
- pending.set(frame, [resolve36]);
26279
+ pending.set(frame, [resolve37]);
26254
26280
  } else {
26255
- list.push(resolve36);
26281
+ list.push(resolve37);
26256
26282
  }
26257
26283
  };
26258
26284
  const flushAt = (frame) => {
26259
26285
  const list = pending.get(frame);
26260
26286
  if (list === void 0) return;
26261
26287
  pending.delete(frame);
26262
- for (const resolve36 of list) resolve36();
26288
+ for (const resolve37 of list) resolve37();
26263
26289
  };
26264
- const waitForFrame = (frame) => new Promise((resolve36) => {
26290
+ const waitForFrame = (frame) => new Promise((resolve37) => {
26265
26291
  if (frame === cursor) {
26266
- resolve36();
26292
+ resolve37();
26267
26293
  return;
26268
26294
  }
26269
- enqueueAt(frame, resolve36);
26295
+ enqueueAt(frame, resolve37);
26270
26296
  });
26271
26297
  const advanceTo = (frame) => {
26272
26298
  cursor = frame;
26273
26299
  flushAt(frame);
26274
26300
  };
26275
- const waitForAllDone = () => new Promise((resolve36) => {
26301
+ const waitForAllDone = () => new Promise((resolve37) => {
26276
26302
  if (cursor >= endFrame) {
26277
- resolve36();
26303
+ resolve37();
26278
26304
  return;
26279
26305
  }
26280
- enqueueAt(endFrame, resolve36);
26306
+ enqueueAt(endFrame, resolve37);
26281
26307
  });
26282
26308
  return { waitForFrame, advanceTo, waitForAllDone };
26283
26309
  }
@@ -26439,7 +26465,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config) {
26439
26465
  let stderr = "";
26440
26466
  let exitCode = null;
26441
26467
  let exitPromiseResolve = null;
26442
- const exitPromise = new Promise((resolve36) => exitPromiseResolve = resolve36);
26468
+ const exitPromise = new Promise((resolve37) => exitPromiseResolve = resolve37);
26443
26469
  ffmpeg.stderr?.on("data", (data) => {
26444
26470
  stderr += data.toString();
26445
26471
  });
@@ -26485,8 +26511,8 @@ Process error: ${err.message}`;
26485
26511
  if (signal) signal.removeEventListener("abort", onAbort);
26486
26512
  const stdin = ffmpeg.stdin;
26487
26513
  if (stdin && !stdin.destroyed) {
26488
- await new Promise((resolve36) => {
26489
- stdin.end(() => resolve36());
26514
+ await new Promise((resolve37) => {
26515
+ stdin.end(() => resolve37());
26490
26516
  });
26491
26517
  }
26492
26518
  await exitPromise;
@@ -26528,7 +26554,7 @@ import { spawn as spawn6 } from "child_process";
26528
26554
  import { readFileSync as readFileSync14 } from "fs";
26529
26555
  import { extname as extname4 } from "path";
26530
26556
  function runFfprobe(args) {
26531
- return new Promise((resolve36, reject) => {
26557
+ return new Promise((resolve37, reject) => {
26532
26558
  const proc = spawn6("ffprobe", args);
26533
26559
  let stdout2 = "";
26534
26560
  let stderr = "";
@@ -26542,7 +26568,7 @@ function runFfprobe(args) {
26542
26568
  if (code !== 0) {
26543
26569
  reject(new Error(`[FFmpeg] ffprobe exited with code ${code}: ${stderr}`));
26544
26570
  } else {
26545
- resolve36(stdout2);
26571
+ resolve37(stdout2);
26546
26572
  }
26547
26573
  });
26548
26574
  proc.on("error", (err) => {
@@ -26956,7 +26982,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
26956
26982
  args.push("-q:v", format === "jpg" ? String(Math.ceil((100 - quality) / 3)) : "0");
26957
26983
  if (format === "png") args.push("-compression_level", "6");
26958
26984
  args.push("-y", outputPattern);
26959
- return new Promise((resolve36, reject) => {
26985
+ return new Promise((resolve37, reject) => {
26960
26986
  const ffmpeg = spawn7("ffmpeg", args);
26961
26987
  let stderr = "";
26962
26988
  const onAbort = () => {
@@ -26991,7 +27017,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
26991
27017
  files.forEach((file, index) => {
26992
27018
  framePaths.set(index, join21(videoOutputDir, file));
26993
27019
  });
26994
- resolve36({
27020
+ resolve37({
26995
27021
  videoId,
26996
27022
  srcPath: videoPath,
26997
27023
  outputDir: videoOutputDir,
@@ -27013,8 +27039,9 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
27013
27039
  });
27014
27040
  });
27015
27041
  }
27016
- async function convertSdrToHdr(inputPath, outputPath, signal, config) {
27042
+ async function convertSdrToHdr(inputPath, outputPath, targetTransfer, signal, config) {
27017
27043
  const timeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
27044
+ const colorTrc = targetTransfer === "pq" ? "smpte2084" : "arib-std-b67";
27018
27045
  const args = [
27019
27046
  "-i",
27020
27047
  inputPath,
@@ -27023,7 +27050,7 @@ async function convertSdrToHdr(inputPath, outputPath, signal, config) {
27023
27050
  "-color_primaries",
27024
27051
  "bt2020",
27025
27052
  "-color_trc",
27026
- "arib-std-b67",
27053
+ colorTrc,
27027
27054
  "-colorspace",
27028
27055
  "bt2020nc",
27029
27056
  "-c:v",
@@ -27109,8 +27136,9 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27109
27136
  return metadata.colorSpace;
27110
27137
  })
27111
27138
  );
27112
- const hasAnyHdr = videoColorSpaces.some(isHdrColorSpace);
27113
- if (hasAnyHdr) {
27139
+ const hdrInfo = analyzeCompositionHdr(videoColorSpaces);
27140
+ if (hdrInfo.hasHdr && hdrInfo.dominantTransfer) {
27141
+ const targetTransfer = hdrInfo.dominantTransfer;
27114
27142
  const convertDir = join21(options.outputDir, "_hdr_normalized");
27115
27143
  mkdirSync12(convertDir, { recursive: true });
27116
27144
  for (let i2 = 0; i2 < resolvedVideos.length; i2++) {
@@ -27121,7 +27149,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27121
27149
  if (!entry) continue;
27122
27150
  const convertedPath = join21(convertDir, `${entry.video.id}_hdr.mp4`);
27123
27151
  try {
27124
- await convertSdrToHdr(entry.videoPath, convertedPath, signal, config);
27152
+ await convertSdrToHdr(entry.videoPath, convertedPath, targetTransfer, signal, config);
27125
27153
  entry.videoPath = convertedPath;
27126
27154
  } catch (err) {
27127
27155
  errors.push({
@@ -27424,7 +27452,6 @@ async function hideVideoElements(page, videoIds) {
27424
27452
  const el = document.getElementById(id);
27425
27453
  if (el) {
27426
27454
  el.style.setProperty("visibility", "hidden", "important");
27427
- el.style.setProperty("opacity", "0", "important");
27428
27455
  const img = document.getElementById(`__render_frame_${id}__`);
27429
27456
  if (img) img.style.setProperty("visibility", "hidden", "important");
27430
27457
  }
@@ -27438,7 +27465,6 @@ async function showVideoElements(page, videoIds) {
27438
27465
  const el = document.getElementById(id);
27439
27466
  if (el) {
27440
27467
  el.style.removeProperty("visibility");
27441
- el.style.removeProperty("opacity");
27442
27468
  const img = document.getElementById(`__render_frame_${id}__`);
27443
27469
  if (img) img.style.removeProperty("visibility");
27444
27470
  }
@@ -27465,8 +27491,10 @@ async function queryVideoElementBounds(page, videoIds) {
27465
27491
  }
27466
27492
  const rect = el.getBoundingClientRect();
27467
27493
  const style = window.getComputedStyle(el);
27468
- const zIndex = parseInt(style.zIndex) || 0;
27469
- const opacity = parseFloat(style.opacity) || 1;
27494
+ const zIndexParsed = parseInt(style.zIndex);
27495
+ const zIndex = Number.isNaN(zIndexParsed) ? 0 : zIndexParsed;
27496
+ const opacityParsed = parseFloat(style.opacity);
27497
+ const opacity = Number.isNaN(opacityParsed) ? 1 : opacityParsed;
27470
27498
  const transform = style.transform || "none";
27471
27499
  const visible = style.visibility !== "hidden" && style.display !== "none" && rect.width > 0 && rect.height > 0;
27472
27500
  return {
@@ -27504,12 +27532,12 @@ async function queryElementStacking(page, nativeHdrIds) {
27504
27532
  function resolveRadius(value, el) {
27505
27533
  if (value.includes("%")) {
27506
27534
  const pct = parseFloat(value) / 100;
27507
- const htmlEl = el;
27508
- const w = htmlEl.offsetWidth || 0;
27509
- const h3 = htmlEl.offsetHeight || 0;
27535
+ const w = el instanceof HTMLElement ? el.offsetWidth : 0;
27536
+ const h3 = el instanceof HTMLElement ? el.offsetHeight : 0;
27510
27537
  return pct * Math.min(w, h3);
27511
27538
  }
27512
- return parseFloat(value) || 0;
27539
+ const parsed = parseFloat(value);
27540
+ return Number.isNaN(parsed) ? 0 : parsed;
27513
27541
  }
27514
27542
  const selfCs = window.getComputedStyle(node);
27515
27543
  const selfRadii = [
@@ -27593,8 +27621,7 @@ async function queryElementStacking(page, nativeHdrIds) {
27593
27621
  const style = window.getComputedStyle(el);
27594
27622
  const zIndex = getEffectiveZIndex(el);
27595
27623
  const isHdrEl = hdrSet.has(id);
27596
- const opacityStartNode = isHdrEl ? el.parentElement : el;
27597
- const opacity = opacityStartNode ? getEffectiveOpacity(opacityStartNode) : 1;
27624
+ const opacity = getEffectiveOpacity(el);
27598
27625
  const visible = style.visibility !== "hidden" && style.display !== "none" && rect.width > 0 && rect.height > 0;
27599
27626
  const htmlEl = el instanceof HTMLElement ? el : null;
27600
27627
  results.push({
@@ -28237,11 +28264,11 @@ function createFileServer(options) {
28237
28264
  headers: { "Content-Type": contentType }
28238
28265
  });
28239
28266
  });
28240
- return new Promise((resolve36) => {
28267
+ return new Promise((resolve37) => {
28241
28268
  const server = serve({ fetch: app.fetch, port }, (info) => {
28242
28269
  const actualPort = info.port;
28243
28270
  const url = `http://localhost:${actualPort}`;
28244
- resolve36({
28271
+ resolve37({
28245
28272
  url,
28246
28273
  port: actualPort,
28247
28274
  close: () => server.close()
@@ -30502,8 +30529,20 @@ var init_hyperframeRuntimeLoader = __esm({
30502
30529
  // ../producer/src/services/fileServer.ts
30503
30530
  import { Hono as Hono3 } from "hono";
30504
30531
  import { serve as serve2 } from "@hono/node-server";
30505
- import { readFileSync as readFileSync18, existsSync as existsSync25, statSync as statSync7 } from "fs";
30506
- import { join as join27, extname as extname7 } from "path";
30532
+ import { readFileSync as readFileSync18, existsSync as existsSync25, realpathSync, statSync as statSync7 } from "fs";
30533
+ import { join as join27, extname as extname7, resolve as resolve13, sep as sep3 } from "path";
30534
+ function isPathInside(child, parent, options = {}) {
30535
+ const { resolveSymlinks = false, pathModule } = options;
30536
+ const resolveFn = pathModule?.resolve ?? resolve13;
30537
+ const separator = pathModule?.sep ?? sep3;
30538
+ const resolvedChild = resolveFn(child);
30539
+ const resolvedParent = resolveFn(parent);
30540
+ const normalizedChild = resolveSymlinks && existsSync25(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
30541
+ const normalizedParent = resolveSymlinks && existsSync25(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
30542
+ if (normalizedChild === normalizedParent) return true;
30543
+ const parentWithSep = normalizedParent.endsWith(separator) ? normalizedParent : normalizedParent + separator;
30544
+ return normalizedChild.startsWith(parentWithSep);
30545
+ }
30507
30546
  function stripEmbeddedRuntimeScripts3(html) {
30508
30547
  if (!html) return html;
30509
30548
  const scriptRe = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
@@ -30586,12 +30625,20 @@ function createFileServer2(options) {
30586
30625
  let requestPath = c2.req.path;
30587
30626
  if (requestPath === "/") requestPath = "/index.html";
30588
30627
  const relativePath = requestPath.replace(/^\//, "");
30589
- const compiledPath = compiledDir ? join27(compiledDir, relativePath) : null;
30590
- const hasCompiledFile = Boolean(
30591
- compiledPath && existsSync25(compiledPath) && statSync7(compiledPath).isFile()
30592
- );
30593
- const filePath = hasCompiledFile ? compiledPath : join27(projectDir, relativePath);
30594
- if (!existsSync25(filePath) || !statSync7(filePath).isFile()) {
30628
+ let filePath = null;
30629
+ if (compiledDir) {
30630
+ const candidate = join27(compiledDir, relativePath);
30631
+ if (existsSync25(candidate) && isPathInside(candidate, compiledDir, { resolveSymlinks: true }) && statSync7(candidate).isFile()) {
30632
+ filePath = candidate;
30633
+ }
30634
+ }
30635
+ if (!filePath) {
30636
+ const candidate = join27(projectDir, relativePath);
30637
+ if (existsSync25(candidate) && isPathInside(candidate, projectDir, { resolveSymlinks: true }) && statSync7(candidate).isFile()) {
30638
+ filePath = candidate;
30639
+ }
30640
+ }
30641
+ if (!filePath) {
30595
30642
  if (!/favicon\.ico$/i.test(requestPath)) {
30596
30643
  console.warn(`[FileServer] 404 Not Found: ${requestPath}`);
30597
30644
  }
@@ -30615,10 +30662,10 @@ function createFileServer2(options) {
30615
30662
  headers: { "Content-Type": contentType }
30616
30663
  });
30617
30664
  });
30618
- return new Promise((resolve36) => {
30665
+ return new Promise((resolve37) => {
30619
30666
  const connections = /* @__PURE__ */ new Set();
30620
30667
  const server = serve2({ fetch: app.fetch, port }, (info) => {
30621
- resolve36({
30668
+ resolve37({
30622
30669
  url: `http://localhost:${info.port}`,
30623
30670
  port: info.port,
30624
30671
  close: () => {
@@ -30961,10 +31008,10 @@ var init_ffprobe2 = __esm({
30961
31008
  });
30962
31009
 
30963
31010
  // ../producer/src/utils/paths.ts
30964
- import { resolve as resolve13, basename, join as join28, relative as relative2, isAbsolute as isAbsolute3 } from "path";
30965
- function isPathInside(childPath, parentPath) {
30966
- const absChild = resolve13(childPath);
30967
- const absParent = resolve13(parentPath);
31011
+ import { resolve as resolve14, basename, join as join28, relative as relative2, isAbsolute as isAbsolute3 } from "path";
31012
+ function isPathInside2(childPath, parentPath) {
31013
+ const absChild = resolve14(childPath);
31014
+ const absParent = resolve14(parentPath);
30968
31015
  if (absChild === absParent) return true;
30969
31016
  const rel = relative2(absParent, absChild);
30970
31017
  return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
@@ -30980,17 +31027,17 @@ function toExternalAssetKey(absPath) {
30980
31027
  return "hf-ext/" + normalised;
30981
31028
  }
30982
31029
  function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
30983
- const absoluteProjectDir = resolve13(projectDir);
31030
+ const absoluteProjectDir = resolve14(projectDir);
30984
31031
  const projectName = basename(absoluteProjectDir);
30985
31032
  const resolvedOutputPath = outputPath ?? join28(rendersDir, `${projectName}.mp4`);
30986
- const absoluteOutputPath = resolve13(resolvedOutputPath);
31033
+ const absoluteOutputPath = resolve14(resolvedOutputPath);
30987
31034
  return { absoluteProjectDir, absoluteOutputPath };
30988
31035
  }
30989
31036
  var DEFAULT_RENDERS_DIR;
30990
31037
  var init_paths = __esm({
30991
31038
  "../producer/src/utils/paths.ts"() {
30992
31039
  "use strict";
30993
- DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve13(new URL(import.meta.url).pathname, "../../..", "renders");
31040
+ DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve14(new URL(import.meta.url).pathname, "../../..", "renders");
30994
31041
  }
30995
31042
  });
30996
31043
 
@@ -31394,7 +31441,7 @@ var init_deterministicFonts = __esm({
31394
31441
 
31395
31442
  // ../producer/src/services/htmlCompiler.ts
31396
31443
  import { readFileSync as readFileSync20, existsSync as existsSync27, mkdirSync as mkdirSync16 } from "fs";
31397
- import { join as join30, dirname as dirname9, resolve as resolve14 } from "path";
31444
+ import { join as join30, dirname as dirname9, resolve as resolve15 } from "path";
31398
31445
  import postcss from "postcss";
31399
31446
  function dedupeElementsById(elements) {
31400
31447
  const deduped = /* @__PURE__ */ new Map();
@@ -31519,7 +31566,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
31519
31566
  const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
31520
31567
  const absoluteStart = parentOffset + elStart;
31521
31568
  const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
31522
- const filePath = resolve14(projectDir, srcPath);
31569
+ const filePath = resolve15(projectDir, srcPath);
31523
31570
  if (visited.has(filePath)) {
31524
31571
  continue;
31525
31572
  }
@@ -31732,7 +31779,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
31732
31779
  if (!srcPath) continue;
31733
31780
  let compHtml = subCompositions.get(srcPath) || null;
31734
31781
  if (!compHtml) {
31735
- const filePath = resolve14(projectDir, srcPath);
31782
+ const filePath = resolve15(projectDir, srcPath);
31736
31783
  if (existsSync27(filePath)) {
31737
31784
  compHtml = readFileSync20(filePath, "utf-8");
31738
31785
  }
@@ -31949,7 +31996,7 @@ ${safeText}
31949
31996
  return wrappedFragment ? document2.body.innerHTML || "" : document2.toString();
31950
31997
  }
31951
31998
  function collectExternalAssets(html, projectDir) {
31952
- const absProjectDir = resolve14(projectDir);
31999
+ const absProjectDir = resolve15(projectDir);
31953
32000
  const externalAssets = /* @__PURE__ */ new Map();
31954
32001
  const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
31955
32002
  function processPath(rawPath) {
@@ -31957,8 +32004,8 @@ function collectExternalAssets(html, projectDir) {
31957
32004
  if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
31958
32005
  return null;
31959
32006
  }
31960
- const absPath = resolve14(absProjectDir, trimmed);
31961
- if (isPathInside(absPath, absProjectDir)) {
32007
+ const absPath = resolve15(absProjectDir, trimmed);
32008
+ if (isPathInside2(absPath, absProjectDir)) {
31962
32009
  return null;
31963
32010
  }
31964
32011
  if (!existsSync27(absPath)) return null;
@@ -32038,7 +32085,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
32038
32085
  const images = dedupeElementsById([...mainImages, ...subImages]);
32039
32086
  for (const video of videos) {
32040
32087
  if (isHttpUrl(video.src)) continue;
32041
- const videoPath = resolve14(projectDir, video.src);
32088
+ const videoPath = resolve15(projectDir, video.src);
32042
32089
  const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
32043
32090
  Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
32044
32091
  if (analysis.isProblematic) {
@@ -32244,7 +32291,7 @@ import {
32244
32291
  copyFileSync as copyFileSync2,
32245
32292
  appendFileSync
32246
32293
  } from "fs";
32247
- import { join as join31, dirname as dirname10, resolve as resolve15 } from "path";
32294
+ import { join as join31, dirname as dirname10, resolve as resolve16 } from "path";
32248
32295
  import { randomUUID as randomUUID2 } from "crypto";
32249
32296
  import { freemem as freemem2 } from "os";
32250
32297
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -32325,8 +32372,8 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
32325
32372
  writeFileSync10(outPath, html, "utf-8");
32326
32373
  }
32327
32374
  for (const [relativePath, absolutePath] of compiled.externalAssets) {
32328
- const outPath = resolve15(join31(compileDir, relativePath));
32329
- if (!isPathInside(outPath, compileDir)) {
32375
+ const outPath = resolve16(join31(compileDir, relativePath));
32376
+ if (!isPathInside2(outPath, compileDir)) {
32330
32377
  console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
32331
32378
  continue;
32332
32379
  }
@@ -32513,7 +32560,7 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
32513
32560
  }
32514
32561
  async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
32515
32562
  const moduleDir = dirname10(fileURLToPath3(import.meta.url));
32516
- const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve15(process.env.PRODUCER_RENDERS_DIR, "..") : resolve15(moduleDir, "../..");
32563
+ const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve16(process.env.PRODUCER_RENDERS_DIR, "..") : resolve16(moduleDir, "../..");
32517
32564
  const debugDir = join31(producerRoot, ".debug");
32518
32565
  const workDir = job.config.debug ? join31(debugDir, job.id) : join31(dirname10(outputPath), `work-${job.id}`);
32519
32566
  const pipelineStart = Date.now();
@@ -32957,6 +33004,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
32957
33004
  const hasHdrContent = effectiveHdr && nativeHdrIds.size > 0;
32958
33005
  const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
32959
33006
  const preset = getEncoderPreset(job.config.quality, outputFormat, encoderHdr);
33007
+ if (job.config.crf != null && job.config.videoBitrate) {
33008
+ log2.warn(
33009
+ `[Render] Both crf=${job.config.crf} and videoBitrate=${job.config.videoBitrate} were set. These are mutually exclusive; honoring crf and ignoring videoBitrate. Set only one to silence this warning.`
33010
+ );
33011
+ }
33012
+ const effectiveQuality = job.config.crf ?? preset.quality;
33013
+ const effectiveBitrate = job.config.crf != null ? void 0 : job.config.videoBitrate;
32960
33014
  job.framesRendered = 0;
32961
33015
  if (hasHdrContent) {
32962
33016
  log2.info("[Render] HDR layered composite: z-ordered DOM + native HLG video layers");
@@ -32980,411 +33034,251 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
32980
33034
  createVideoFrameInjector(frameLookup),
32981
33035
  cfg
32982
33036
  );
32983
- await initializeSession(domSession);
32984
- assertNotAborted();
32985
- lastBrowserConsole = domSession.browserConsoleBuffer;
32986
- await initTransparentBackground(domSession.page);
32987
- const transitionMeta = await domSession.page.evaluate(() => {
32988
- return window.__hf?.transitions ?? [];
32989
- });
32990
- const sceneElements = await domSession.page.evaluate(() => {
32991
- const scenes = document.querySelectorAll(".scene");
32992
- const map = {};
32993
- for (const scene of scenes) {
32994
- const els = scene.querySelectorAll("[data-start]");
32995
- map[scene.id] = Array.from(els).map((e2) => e2.id);
32996
- }
32997
- return map;
32998
- });
32999
- const transitionRanges = transitionMeta.map((t3) => ({
33000
- ...t3,
33001
- startFrame: Math.floor(t3.time * job.config.fps),
33002
- endFrame: Math.ceil((t3.time + t3.duration) * job.config.fps)
33003
- }));
33004
- if (transitionRanges.length > 0) {
33005
- log2.info("[Render] Detected shader transitions for HDR compositing", {
33006
- count: transitionRanges.length,
33007
- transitions: transitionRanges.map((t3) => ({
33008
- shader: t3.shader,
33009
- from: t3.fromScene,
33010
- to: t3.toScene,
33011
- frames: `${t3.startFrame}-${t3.endFrame}`
33012
- }))
33013
- });
33014
- }
33015
- const hdrEncoder = await spawnStreamingEncoder(
33016
- videoOnlyPath,
33017
- {
33018
- fps: job.config.fps,
33019
- width,
33020
- height,
33021
- codec: preset.codec,
33022
- preset: preset.preset,
33023
- quality: preset.quality,
33024
- pixelFormat: preset.pixelFormat,
33025
- hdr: preset.hdr,
33026
- rawInputFormat: "rgb48le"
33027
- },
33028
- abortSignal,
33029
- { ffmpegStreamingTimeout: 36e5 }
33030
- );
33031
- assertNotAborted();
33032
- const hdrExtractionDims = /* @__PURE__ */ new Map();
33033
- const hdrImageFitInfo = /* @__PURE__ */ new Map();
33034
- const hdrVideoStartTimes = /* @__PURE__ */ new Map();
33035
- for (const v of composition.videos) {
33036
- if (hdrVideoIds.includes(v.id)) {
33037
- hdrVideoStartTimes.set(v.id, v.start);
33038
- }
33039
- }
33040
- const hdrImageStartTimes = /* @__PURE__ */ new Map();
33041
- for (const img of composition.images) {
33042
- if (nativeHdrImageIds.has(img.id)) {
33043
- hdrImageStartTimes.set(img.id, img.start);
33044
- }
33045
- }
33046
- const uniqueStartTimes = [
33047
- .../* @__PURE__ */ new Set([...hdrVideoStartTimes.values(), ...hdrImageStartTimes.values()])
33048
- ].sort((a, b) => a - b);
33049
- for (const seekTime of uniqueStartTimes) {
33050
- await domSession.page.evaluate((t3) => {
33051
- if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33052
- }, seekTime);
33053
- if (domSession.onBeforeCapture) {
33054
- await domSession.onBeforeCapture(domSession.page, seekTime);
33055
- }
33056
- const stacking = await queryElementStacking(domSession.page, nativeHdrIds);
33057
- for (const el of stacking) {
33058
- if (el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0 && !hdrExtractionDims.has(el.id)) {
33059
- hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
33060
- }
33061
- if (el.isHdr && nativeHdrImageIds.has(el.id) && !hdrImageFitInfo.has(el.id)) {
33062
- hdrImageFitInfo.set(el.id, {
33063
- fit: el.objectFit,
33064
- position: el.objectPosition
33065
- });
33066
- }
33067
- }
33068
- }
33037
+ let hdrEncoder = null;
33038
+ let hdrEncoderClosed = false;
33039
+ let domSessionClosed = false;
33069
33040
  const hdrFrameDirs = /* @__PURE__ */ new Map();
33070
- for (const [videoId, srcPath] of hdrVideoSrcPaths) {
33071
- const video = composition.videos.find((v) => v.id === videoId);
33072
- if (!video) continue;
33073
- const frameDir = join31(framesDir, `hdr_${videoId}`);
33074
- mkdirSync17(frameDir, { recursive: true });
33075
- const duration = video.end - video.start;
33076
- const dims = hdrExtractionDims.get(videoId) ?? { width, height };
33077
- const ffmpegArgs = [
33078
- "-ss",
33079
- String(video.mediaStart),
33080
- "-i",
33081
- srcPath,
33082
- "-t",
33083
- String(duration),
33084
- "-r",
33085
- String(job.config.fps),
33086
- "-vf",
33087
- `scale=${dims.width}:${dims.height}:force_original_aspect_ratio=increase,crop=${dims.width}:${dims.height}`,
33088
- "-pix_fmt",
33089
- "rgb48le",
33090
- "-c:v",
33091
- "png",
33092
- "-y",
33093
- join31(frameDir, "frame_%04d.png")
33094
- ];
33095
- const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
33096
- if (!result.success) {
33097
- hdrDiagnostics.videoExtractionFailures += 1;
33098
- log2.error("HDR frame pre-extraction failed; aborting render", {
33099
- videoId,
33100
- srcPath,
33101
- stderr: result.stderr.slice(-400)
33041
+ try {
33042
+ await initializeSession(domSession);
33043
+ assertNotAborted();
33044
+ lastBrowserConsole = domSession.browserConsoleBuffer;
33045
+ await initTransparentBackground(domSession.page);
33046
+ const transitionMeta = await domSession.page.evaluate(() => {
33047
+ return window.__hf?.transitions ?? [];
33048
+ });
33049
+ const sceneElements = await domSession.page.evaluate(() => {
33050
+ const scenes = document.querySelectorAll(".scene");
33051
+ const map = {};
33052
+ for (const scene of scenes) {
33053
+ const els = scene.querySelectorAll("[data-start]");
33054
+ map[scene.id] = Array.from(els).map((e2) => e2.id);
33055
+ }
33056
+ return map;
33057
+ });
33058
+ const transitionRanges = transitionMeta.map((t3) => ({
33059
+ ...t3,
33060
+ startFrame: Math.floor(t3.time * job.config.fps),
33061
+ endFrame: Math.ceil((t3.time + t3.duration) * job.config.fps)
33062
+ }));
33063
+ if (transitionRanges.length > 0) {
33064
+ log2.info("[Render] Detected shader transitions for HDR compositing", {
33065
+ count: transitionRanges.length,
33066
+ transitions: transitionRanges.map((t3) => ({
33067
+ shader: t3.shader,
33068
+ from: t3.fromScene,
33069
+ to: t3.toScene,
33070
+ frames: `${t3.startFrame}-${t3.endFrame}`
33071
+ }))
33102
33072
  });
33103
- throw new Error(
33104
- `HDR frame extraction failed for video "${videoId}". Aborting render to avoid shipping black HDR layers.`
33105
- );
33106
33073
  }
33107
- hdrFrameDirs.set(videoId, frameDir);
33108
- }
33109
- const hdrImageBuffers = /* @__PURE__ */ new Map();
33110
- for (const [imageId, srcPath] of hdrImageSrcPaths) {
33111
- try {
33112
- const decoded = decodePngToRgb48le(readFileSync21(srcPath));
33113
- const layout2 = hdrExtractionDims.get(imageId);
33114
- const fitInfo = hdrImageFitInfo.get(imageId);
33115
- if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
33116
- const fit = normalizeObjectFit(fitInfo?.fit);
33117
- const resampled = resampleRgb48leObjectFit(
33118
- decoded.data,
33119
- decoded.width,
33120
- decoded.height,
33121
- layout2.width,
33122
- layout2.height,
33123
- fit,
33124
- fitInfo?.position
33125
- );
33126
- hdrImageBuffers.set(imageId, {
33127
- data: resampled,
33128
- width: layout2.width,
33129
- height: layout2.height
33130
- });
33131
- } else {
33132
- hdrImageBuffers.set(imageId, {
33133
- data: Buffer.from(decoded.data),
33134
- width: decoded.width,
33135
- height: decoded.height
33136
- });
33074
+ hdrEncoder = await spawnStreamingEncoder(
33075
+ videoOnlyPath,
33076
+ {
33077
+ fps: job.config.fps,
33078
+ width,
33079
+ height,
33080
+ codec: preset.codec,
33081
+ preset: preset.preset,
33082
+ quality: effectiveQuality,
33083
+ bitrate: effectiveBitrate,
33084
+ pixelFormat: preset.pixelFormat,
33085
+ hdr: preset.hdr,
33086
+ rawInputFormat: "rgb48le"
33087
+ },
33088
+ abortSignal,
33089
+ { ffmpegStreamingTimeout: 36e5 }
33090
+ );
33091
+ assertNotAborted();
33092
+ const hdrExtractionDims = /* @__PURE__ */ new Map();
33093
+ const hdrImageFitInfo = /* @__PURE__ */ new Map();
33094
+ const hdrVideoStartTimes = /* @__PURE__ */ new Map();
33095
+ for (const v of composition.videos) {
33096
+ if (hdrVideoIds.includes(v.id)) {
33097
+ hdrVideoStartTimes.set(v.id, v.start);
33137
33098
  }
33138
- } catch (err) {
33139
- hdrDiagnostics.imageDecodeFailures += 1;
33140
- log2.error("HDR image decode failed; aborting render", {
33141
- imageId,
33142
- srcPath,
33143
- error: err instanceof Error ? err.message : String(err)
33144
- });
33145
- throw new Error(
33146
- `HDR image decode failed for image "${imageId}". Aborting render to avoid shipping missing HDR image layers.`
33147
- );
33148
33099
  }
33149
- }
33150
- assertNotAborted();
33151
- try {
33152
- let countNonZeroAlpha2 = function(rgba) {
33153
- let n = 0;
33154
- for (let p = 3; p < rgba.length; p += 4) {
33155
- if (rgba[p] !== 0) n++;
33100
+ const hdrImageStartTimes = /* @__PURE__ */ new Map();
33101
+ for (const img of composition.images) {
33102
+ if (nativeHdrImageIds.has(img.id)) {
33103
+ hdrImageStartTimes.set(img.id, img.start);
33156
33104
  }
33157
- return n;
33158
- }, countNonZeroRgb482 = function(buf) {
33159
- let n = 0;
33160
- for (let p = 0; p < buf.length; p += 6) {
33161
- if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0) n++;
33105
+ }
33106
+ const uniqueStartTimes = [
33107
+ .../* @__PURE__ */ new Set([...hdrVideoStartTimes.values(), ...hdrImageStartTimes.values()])
33108
+ ].sort((a, b) => a - b);
33109
+ for (const seekTime of uniqueStartTimes) {
33110
+ await domSession.page.evaluate((t3) => {
33111
+ if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33112
+ }, seekTime);
33113
+ if (domSession.onBeforeCapture) {
33114
+ await domSession.onBeforeCapture(domSession.page, seekTime);
33115
+ }
33116
+ const stacking = await queryElementStacking(domSession.page, nativeHdrIds);
33117
+ for (const el of stacking) {
33118
+ if (el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0 && !hdrExtractionDims.has(el.id)) {
33119
+ hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
33120
+ }
33121
+ if (el.isHdr && nativeHdrImageIds.has(el.id) && !hdrImageFitInfo.has(el.id)) {
33122
+ hdrImageFitInfo.set(el.id, {
33123
+ fit: el.objectFit,
33124
+ position: el.objectPosition
33125
+ });
33126
+ }
33162
33127
  }
33163
- return n;
33164
- };
33165
- var countNonZeroAlpha = countNonZeroAlpha2, countNonZeroRgb48 = countNonZeroRgb482;
33166
- const beforeCaptureHook = domSession.onBeforeCapture;
33167
- const cleanedUpVideos = /* @__PURE__ */ new Set();
33168
- const hdrVideoEndTimes = /* @__PURE__ */ new Map();
33169
- for (const v of composition.videos) {
33170
- if (hdrFrameDirs.has(v.id)) {
33171
- hdrVideoEndTimes.set(v.id, v.end);
33172
- }
33173
- }
33174
- const debugDumpEnabled = process.env.KEEP_TEMP === "1";
33175
- const debugDumpDir = debugDumpEnabled ? join31(framesDir, "debug-composite") : null;
33176
- if (debugDumpDir && !existsSync28(debugDumpDir)) {
33177
- mkdirSync17(debugDumpDir, { recursive: true });
33178
- }
33179
- async function compositeToBuffer(canvas, time, fullStacking, elementFilter, debugFrameIndex = -1) {
33180
- const filteredStacking = elementFilter ? fullStacking.filter((e2) => elementFilter.has(e2.id)) : fullStacking;
33181
- const layers = groupIntoLayers(filteredStacking);
33182
- const shouldLog = debugDumpEnabled && debugFrameIndex >= 0;
33183
- if (shouldLog) {
33184
- log2.info("[diag] compositeToBuffer plan", {
33185
- frame: debugFrameIndex,
33186
- time: time.toFixed(3),
33187
- filterSize: elementFilter?.size,
33188
- fullStackingCount: fullStacking.length,
33189
- filteredCount: filteredStacking.length,
33190
- layerCount: layers.length,
33191
- layers: layers.map(
33192
- (l) => l.type === "hdr" ? {
33193
- type: "hdr",
33194
- id: l.element.id,
33195
- z: l.element.zIndex,
33196
- visible: l.element.visible,
33197
- opacity: l.element.opacity,
33198
- bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
33199
- } : { type: "dom", ids: l.elementIds }
33200
- )
33128
+ }
33129
+ for (const [videoId, srcPath] of hdrVideoSrcPaths) {
33130
+ const video = composition.videos.find((v) => v.id === videoId);
33131
+ if (!video) continue;
33132
+ const frameDir = join31(framesDir, `hdr_${videoId}`);
33133
+ mkdirSync17(frameDir, { recursive: true });
33134
+ const duration = video.end - video.start;
33135
+ const dims = hdrExtractionDims.get(videoId) ?? { width, height };
33136
+ const ffmpegArgs = [
33137
+ "-ss",
33138
+ String(video.mediaStart),
33139
+ "-i",
33140
+ srcPath,
33141
+ "-t",
33142
+ String(duration),
33143
+ "-r",
33144
+ String(job.config.fps),
33145
+ "-vf",
33146
+ `scale=${dims.width}:${dims.height}:force_original_aspect_ratio=increase,crop=${dims.width}:${dims.height}`,
33147
+ "-pix_fmt",
33148
+ "rgb48le",
33149
+ "-c:v",
33150
+ "png",
33151
+ "-y",
33152
+ join31(frameDir, "frame_%04d.png")
33153
+ ];
33154
+ const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
33155
+ if (!result.success) {
33156
+ hdrDiagnostics.videoExtractionFailures += 1;
33157
+ log2.error("HDR frame pre-extraction failed; aborting render", {
33158
+ videoId,
33159
+ srcPath,
33160
+ stderr: result.stderr.slice(-400)
33201
33161
  });
33162
+ throw new Error(
33163
+ `HDR frame extraction failed for video "${videoId}". Aborting render to avoid shipping black HDR layers.`
33164
+ );
33202
33165
  }
33203
- for (const [layerIdx, layer] of layers.entries()) {
33204
- if (layer.type === "hdr") {
33205
- const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
33206
- const isHdrImage = nativeHdrImageIds.has(layer.element.id);
33207
- if (isHdrImage) {
33208
- blitHdrImageLayer(
33209
- canvas,
33210
- layer.element,
33211
- hdrImageBuffers,
33212
- width,
33213
- height,
33214
- log2,
33215
- imageTransfers.get(layer.element.id),
33216
- effectiveHdr?.transfer
33217
- );
33218
- } else {
33219
- blitHdrVideoLayer(
33220
- canvas,
33221
- layer.element,
33222
- time,
33223
- job.config.fps,
33224
- hdrFrameDirs,
33225
- hdrVideoStartTimes,
33226
- width,
33227
- height,
33228
- log2,
33229
- videoTransfers.get(layer.element.id),
33230
- effectiveHdr?.transfer
33231
- );
33232
- }
33233
- if (shouldLog) {
33234
- const after2 = countNonZeroRgb482(canvas);
33235
- if (isHdrImage) {
33236
- const buf = hdrImageBuffers.get(layer.element.id);
33237
- log2.info("[diag] hdr layer blit", {
33238
- frame: debugFrameIndex,
33239
- layerIdx,
33240
- id: layer.element.id,
33241
- kind: "image",
33242
- pixelsAdded: after2 - before2,
33243
- totalNonZero: after2,
33244
- bufferDecoded: !!buf,
33245
- bufferDims: buf ? `${buf.width}x${buf.height}` : null
33246
- });
33247
- } else {
33248
- const frameDir = hdrFrameDirs.get(layer.element.id);
33249
- const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
33250
- const localTime = time - startTime;
33251
- const frameNum = Math.floor(localTime * job.config.fps) + 1;
33252
- const expectedFrame = frameDir ? join31(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
33253
- log2.info("[diag] hdr layer blit", {
33254
- frame: debugFrameIndex,
33255
- layerIdx,
33256
- id: layer.element.id,
33257
- kind: "video",
33258
- pixelsAdded: after2 - before2,
33259
- totalNonZero: after2,
33260
- startTime,
33261
- localTime: localTime.toFixed(3),
33262
- hdrFrameNum: frameNum,
33263
- expectedFrame,
33264
- expectedFrameExists: expectedFrame ? existsSync28(expectedFrame) : false
33265
- });
33266
- }
33267
- }
33166
+ hdrFrameDirs.set(videoId, frameDir);
33167
+ }
33168
+ const hdrImageBuffers = /* @__PURE__ */ new Map();
33169
+ for (const [imageId, srcPath] of hdrImageSrcPaths) {
33170
+ try {
33171
+ const decoded = decodePngToRgb48le(readFileSync21(srcPath));
33172
+ const layout2 = hdrExtractionDims.get(imageId);
33173
+ const fitInfo = hdrImageFitInfo.get(imageId);
33174
+ if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
33175
+ const fit = normalizeObjectFit(fitInfo?.fit);
33176
+ const resampled = resampleRgb48leObjectFit(
33177
+ decoded.data,
33178
+ decoded.width,
33179
+ decoded.height,
33180
+ layout2.width,
33181
+ layout2.height,
33182
+ fit,
33183
+ fitInfo?.position
33184
+ );
33185
+ hdrImageBuffers.set(imageId, {
33186
+ data: resampled,
33187
+ width: layout2.width,
33188
+ height: layout2.height
33189
+ });
33268
33190
  } else {
33269
- const allElementIds = fullStacking.map((e2) => e2.id);
33270
- const layerIds = new Set(layer.elementIds);
33271
- const hideIds = allElementIds.filter((id) => !layerIds.has(id));
33272
- await domSession.page.evaluate((t3) => {
33273
- if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33274
- }, time);
33275
- if (beforeCaptureHook) {
33276
- await beforeCaptureHook(domSession.page, time);
33277
- }
33278
- await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
33279
- const domPng = await captureAlphaPng(domSession.page, width, height);
33280
- await removeDomLayerMask(domSession.page, hideIds);
33281
- try {
33282
- const { data: domRgba } = decodePng(domPng);
33283
- if (!effectiveHdr) {
33284
- throw new Error(
33285
- "Invariant violation: effectiveHdr is undefined inside HDR layer branch"
33286
- );
33287
- }
33288
- const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
33289
- const alphaPixels = shouldLog ? countNonZeroAlpha2(domRgba) : 0;
33290
- blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
33291
- if (shouldLog && debugDumpDir) {
33292
- const after2 = countNonZeroRgb482(canvas);
33293
- const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
33294
- const dumpPath = join31(debugDumpDir, dumpName);
33295
- writeFileSync10(dumpPath, domPng);
33296
- log2.info("[diag] dom layer blit", {
33297
- frame: debugFrameIndex,
33298
- layerIdx,
33299
- layerIds: layer.elementIds,
33300
- hideCount: hideIds.length,
33301
- pngBytes: domPng.length,
33302
- alphaPixels,
33303
- pixelsAdded: after2 - before2,
33304
- totalNonZero: after2,
33305
- dumpPath
33306
- });
33307
- }
33308
- } catch (err) {
33309
- log2.warn("DOM layer decode/blit failed; skipping overlay", {
33310
- layerIds: layer.elementIds,
33311
- error: err instanceof Error ? err.message : String(err)
33312
- });
33313
- }
33191
+ hdrImageBuffers.set(imageId, {
33192
+ data: Buffer.from(decoded.data),
33193
+ width: decoded.width,
33194
+ height: decoded.height
33195
+ });
33314
33196
  }
33315
- }
33316
- if (shouldLog && debugDumpDir) {
33317
- const finalNonZero = countNonZeroRgb482(canvas);
33318
- log2.info("[diag] compositeToBuffer end", {
33319
- frame: debugFrameIndex,
33320
- finalNonZeroPixels: finalNonZero,
33321
- totalPixels: width * height,
33322
- coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
33197
+ } catch (err) {
33198
+ hdrDiagnostics.imageDecodeFailures += 1;
33199
+ log2.error("HDR image decode failed; aborting render", {
33200
+ imageId,
33201
+ srcPath,
33202
+ error: err instanceof Error ? err.message : String(err)
33323
33203
  });
33204
+ throw new Error(
33205
+ `HDR image decode failed for image "${imageId}". Aborting render to avoid shipping missing HDR image layers.`
33206
+ );
33324
33207
  }
33325
33208
  }
33326
- const bufSize = width * height * 6;
33327
- const hasTransitions = transitionRanges.length > 0;
33328
- const transBufferA = hasTransitions ? Buffer.alloc(bufSize) : null;
33329
- const transBufferB = hasTransitions ? Buffer.alloc(bufSize) : null;
33330
- const transOutput = hasTransitions ? Buffer.alloc(bufSize) : null;
33331
- const normalCanvas = Buffer.alloc(bufSize);
33332
- for (let i2 = 0; i2 < totalFrames; i2++) {
33333
- assertNotAborted();
33334
- const time = i2 / job.config.fps;
33335
- await domSession.page.evaluate((t3) => {
33336
- if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33337
- }, time);
33338
- if (beforeCaptureHook) {
33339
- await beforeCaptureHook(domSession.page, time);
33340
- }
33341
- const stackingInfo = await queryElementStacking(domSession.page, nativeHdrIds);
33342
- const activeTransition = transitionRanges.find(
33343
- (t3) => i2 >= t3.startFrame && i2 <= t3.endFrame
33344
- );
33345
- if (i2 % 30 === 0) {
33346
- const hdrEl = stackingInfo.find((e2) => e2.isHdr);
33347
- log2.debug("[Render] HDR layer composite frame", {
33348
- frame: i2,
33349
- time: time.toFixed(2),
33350
- hdrElement: hdrEl ? { z: hdrEl.zIndex, visible: hdrEl.visible, width: hdrEl.width } : null,
33351
- stackingCount: stackingInfo.length,
33352
- activeTransition: activeTransition?.shader
33353
- });
33209
+ assertNotAborted();
33210
+ try {
33211
+ let countNonZeroAlpha2 = function(rgba) {
33212
+ let n = 0;
33213
+ for (let p = 3; p < rgba.length; p += 4) {
33214
+ if (rgba[p] !== 0) n++;
33215
+ }
33216
+ return n;
33217
+ }, countNonZeroRgb482 = function(buf) {
33218
+ let n = 0;
33219
+ for (let p = 0; p < buf.length; p += 6) {
33220
+ if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0 || buf[p + 3] !== 0 || buf[p + 4] !== 0 || buf[p + 5] !== 0)
33221
+ n++;
33222
+ }
33223
+ return n;
33224
+ };
33225
+ var countNonZeroAlpha = countNonZeroAlpha2, countNonZeroRgb48 = countNonZeroRgb482;
33226
+ const beforeCaptureHook = domSession.onBeforeCapture;
33227
+ const cleanedUpVideos = /* @__PURE__ */ new Set();
33228
+ const hdrVideoEndTimes = /* @__PURE__ */ new Map();
33229
+ for (const v of composition.videos) {
33230
+ if (hdrFrameDirs.has(v.id)) {
33231
+ hdrVideoEndTimes.set(v.id, v.end);
33232
+ }
33354
33233
  }
33355
- if (activeTransition && transBufferA && transBufferB && transOutput) {
33356
- const progress = activeTransition.endFrame === activeTransition.startFrame ? 1 : (i2 - activeTransition.startFrame) / (activeTransition.endFrame - activeTransition.startFrame);
33357
- const sceneAIds = new Set(sceneElements[activeTransition.fromScene] ?? []);
33358
- const sceneBIds = new Set(sceneElements[activeTransition.toScene] ?? []);
33359
- transBufferA.fill(0);
33360
- transBufferB.fill(0);
33361
- for (const [sceneBuf, sceneIds] of [
33362
- [transBufferA, sceneAIds],
33363
- [transBufferB, sceneBIds]
33364
- ]) {
33365
- await domSession.page.evaluate((t3) => {
33366
- if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33367
- }, time);
33368
- if (beforeCaptureHook) {
33369
- await beforeCaptureHook(domSession.page, time);
33370
- }
33371
- for (const el of stackingInfo) {
33372
- if (!el.isHdr || !sceneIds.has(el.id)) continue;
33373
- if (nativeHdrImageIds.has(el.id)) {
33234
+ const debugDumpEnabled = process.env.KEEP_TEMP === "1";
33235
+ const debugDumpDir = debugDumpEnabled ? join31(framesDir, "debug-composite") : null;
33236
+ if (debugDumpDir && !existsSync28(debugDumpDir)) {
33237
+ mkdirSync17(debugDumpDir, { recursive: true });
33238
+ }
33239
+ async function compositeToBuffer(canvas, time, fullStacking, elementFilter, debugFrameIndex = -1) {
33240
+ const filteredStacking = elementFilter ? fullStacking.filter((e2) => elementFilter.has(e2.id)) : fullStacking;
33241
+ const layers = groupIntoLayers(filteredStacking);
33242
+ const shouldLog = debugDumpEnabled && debugFrameIndex >= 0;
33243
+ if (shouldLog) {
33244
+ log2.info("[diag] compositeToBuffer plan", {
33245
+ frame: debugFrameIndex,
33246
+ time: time.toFixed(3),
33247
+ filterSize: elementFilter?.size,
33248
+ fullStackingCount: fullStacking.length,
33249
+ filteredCount: filteredStacking.length,
33250
+ layerCount: layers.length,
33251
+ layers: layers.map(
33252
+ (l) => l.type === "hdr" ? {
33253
+ type: "hdr",
33254
+ id: l.element.id,
33255
+ z: l.element.zIndex,
33256
+ visible: l.element.visible,
33257
+ opacity: l.element.opacity,
33258
+ bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
33259
+ } : { type: "dom", ids: l.elementIds }
33260
+ )
33261
+ });
33262
+ }
33263
+ for (const [layerIdx, layer] of layers.entries()) {
33264
+ if (layer.type === "hdr") {
33265
+ const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
33266
+ const isHdrImage = nativeHdrImageIds.has(layer.element.id);
33267
+ if (isHdrImage) {
33374
33268
  blitHdrImageLayer(
33375
- sceneBuf,
33376
- el,
33269
+ canvas,
33270
+ layer.element,
33377
33271
  hdrImageBuffers,
33378
33272
  width,
33379
33273
  height,
33380
33274
  log2,
33381
- imageTransfers.get(el.id),
33275
+ imageTransfers.get(layer.element.id),
33382
33276
  effectiveHdr?.transfer
33383
33277
  );
33384
33278
  } else {
33385
33279
  blitHdrVideoLayer(
33386
- sceneBuf,
33387
- el,
33280
+ canvas,
33281
+ layer.element,
33388
33282
  time,
33389
33283
  job.config.fps,
33390
33284
  hdrFrameDirs,
@@ -33392,100 +33286,294 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33392
33286
  width,
33393
33287
  height,
33394
33288
  log2,
33395
- videoTransfers.get(el.id),
33289
+ videoTransfers.get(layer.element.id),
33396
33290
  effectiveHdr?.transfer
33397
33291
  );
33398
33292
  }
33293
+ if (shouldLog) {
33294
+ const after2 = countNonZeroRgb482(canvas);
33295
+ if (isHdrImage) {
33296
+ const buf = hdrImageBuffers.get(layer.element.id);
33297
+ log2.info("[diag] hdr layer blit", {
33298
+ frame: debugFrameIndex,
33299
+ layerIdx,
33300
+ id: layer.element.id,
33301
+ kind: "image",
33302
+ pixelsAdded: after2 - before2,
33303
+ totalNonZero: after2,
33304
+ bufferDecoded: !!buf,
33305
+ bufferDims: buf ? `${buf.width}x${buf.height}` : null
33306
+ });
33307
+ } else {
33308
+ const frameDir = hdrFrameDirs.get(layer.element.id);
33309
+ const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
33310
+ const localTime = time - startTime;
33311
+ const frameNum = Math.floor(localTime * job.config.fps) + 1;
33312
+ const expectedFrame = frameDir ? join31(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
33313
+ log2.info("[diag] hdr layer blit", {
33314
+ frame: debugFrameIndex,
33315
+ layerIdx,
33316
+ id: layer.element.id,
33317
+ kind: "video",
33318
+ pixelsAdded: after2 - before2,
33319
+ totalNonZero: after2,
33320
+ startTime,
33321
+ localTime: localTime.toFixed(3),
33322
+ hdrFrameNum: frameNum,
33323
+ expectedFrame,
33324
+ expectedFrameExists: expectedFrame ? existsSync28(expectedFrame) : false
33325
+ });
33326
+ }
33327
+ }
33328
+ } else {
33329
+ const allElementIds = fullStacking.map((e2) => e2.id);
33330
+ const layerIds = new Set(layer.elementIds);
33331
+ const hideIds = allElementIds.filter((id) => !layerIds.has(id));
33332
+ await domSession.page.evaluate((t3) => {
33333
+ if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33334
+ }, time);
33335
+ if (beforeCaptureHook) {
33336
+ await beforeCaptureHook(domSession.page, time);
33337
+ }
33338
+ await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
33339
+ const domPng = await captureAlphaPng(domSession.page, width, height);
33340
+ await removeDomLayerMask(domSession.page, hideIds);
33341
+ try {
33342
+ const { data: domRgba } = decodePng(domPng);
33343
+ if (!effectiveHdr) {
33344
+ throw new Error(
33345
+ "Invariant violation: effectiveHdr is undefined inside HDR layer branch"
33346
+ );
33347
+ }
33348
+ const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
33349
+ const alphaPixels = shouldLog ? countNonZeroAlpha2(domRgba) : 0;
33350
+ blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
33351
+ if (shouldLog && debugDumpDir) {
33352
+ const after2 = countNonZeroRgb482(canvas);
33353
+ const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
33354
+ const dumpPath = join31(debugDumpDir, dumpName);
33355
+ writeFileSync10(dumpPath, domPng);
33356
+ log2.info("[diag] dom layer blit", {
33357
+ frame: debugFrameIndex,
33358
+ layerIdx,
33359
+ layerIds: layer.elementIds,
33360
+ hideCount: hideIds.length,
33361
+ pngBytes: domPng.length,
33362
+ alphaPixels,
33363
+ pixelsAdded: after2 - before2,
33364
+ totalNonZero: after2,
33365
+ dumpPath
33366
+ });
33367
+ }
33368
+ } catch (err) {
33369
+ log2.warn("DOM layer decode/blit failed; skipping overlay", {
33370
+ layerIds: layer.elementIds,
33371
+ error: err instanceof Error ? err.message : String(err)
33372
+ });
33373
+ }
33399
33374
  }
33400
- const showIds = Array.from(sceneIds);
33401
- const hideIds = stackingInfo.map((e2) => e2.id).filter((id) => !sceneIds.has(id) || nativeHdrIds.has(id));
33402
- await applyDomLayerMask(domSession.page, showIds, hideIds);
33403
- const domPng = await captureAlphaPng(domSession.page, width, height);
33404
- await removeDomLayerMask(domSession.page, hideIds);
33405
- try {
33406
- const { data: domRgba } = decodePng(domPng);
33407
- if (!effectiveHdr) {
33408
- throw new Error(
33409
- "Invariant violation: effectiveHdr is undefined inside hasHdrVideo branch"
33375
+ }
33376
+ if (shouldLog && debugDumpDir) {
33377
+ const finalNonZero = countNonZeroRgb482(canvas);
33378
+ log2.info("[diag] compositeToBuffer end", {
33379
+ frame: debugFrameIndex,
33380
+ finalNonZeroPixels: finalNonZero,
33381
+ totalPixels: width * height,
33382
+ coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
33383
+ });
33384
+ }
33385
+ }
33386
+ const bufSize = width * height * 6;
33387
+ const hasTransitions = transitionRanges.length > 0;
33388
+ const transBufferA = hasTransitions ? Buffer.alloc(bufSize) : null;
33389
+ const transBufferB = hasTransitions ? Buffer.alloc(bufSize) : null;
33390
+ const transOutput = hasTransitions ? Buffer.alloc(bufSize) : null;
33391
+ const normalCanvas = Buffer.alloc(bufSize);
33392
+ for (let i2 = 0; i2 < totalFrames; i2++) {
33393
+ assertNotAborted();
33394
+ const time = i2 / job.config.fps;
33395
+ await domSession.page.evaluate((t3) => {
33396
+ if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33397
+ }, time);
33398
+ if (beforeCaptureHook) {
33399
+ await beforeCaptureHook(domSession.page, time);
33400
+ }
33401
+ const stackingInfo = await queryElementStacking(domSession.page, nativeHdrIds);
33402
+ const activeTransition = transitionRanges.find(
33403
+ (t3) => i2 >= t3.startFrame && i2 <= t3.endFrame
33404
+ );
33405
+ if (i2 % 30 === 0) {
33406
+ const hdrEl = stackingInfo.find((e2) => e2.isHdr);
33407
+ log2.debug("[Render] HDR layer composite frame", {
33408
+ frame: i2,
33409
+ time: time.toFixed(2),
33410
+ hdrElement: hdrEl ? { z: hdrEl.zIndex, visible: hdrEl.visible, width: hdrEl.width } : null,
33411
+ stackingCount: stackingInfo.length,
33412
+ activeTransition: activeTransition?.shader
33413
+ });
33414
+ }
33415
+ if (activeTransition && transBufferA && transBufferB && transOutput) {
33416
+ const progress = activeTransition.endFrame === activeTransition.startFrame ? 1 : (i2 - activeTransition.startFrame) / (activeTransition.endFrame - activeTransition.startFrame);
33417
+ const sceneAIds = new Set(sceneElements[activeTransition.fromScene] ?? []);
33418
+ const sceneBIds = new Set(sceneElements[activeTransition.toScene] ?? []);
33419
+ transBufferA.fill(0);
33420
+ transBufferB.fill(0);
33421
+ for (const [sceneBuf, sceneIds] of [
33422
+ [transBufferA, sceneAIds],
33423
+ [transBufferB, sceneBIds]
33424
+ ]) {
33425
+ assertNotAborted();
33426
+ await domSession.page.evaluate((t3) => {
33427
+ if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t3);
33428
+ }, time);
33429
+ if (beforeCaptureHook) {
33430
+ await beforeCaptureHook(domSession.page, time);
33431
+ }
33432
+ for (const el of stackingInfo) {
33433
+ if (!el.isHdr || !sceneIds.has(el.id)) continue;
33434
+ if (nativeHdrImageIds.has(el.id)) {
33435
+ blitHdrImageLayer(
33436
+ sceneBuf,
33437
+ el,
33438
+ hdrImageBuffers,
33439
+ width,
33440
+ height,
33441
+ log2,
33442
+ imageTransfers.get(el.id),
33443
+ effectiveHdr?.transfer
33444
+ );
33445
+ } else {
33446
+ blitHdrVideoLayer(
33447
+ sceneBuf,
33448
+ el,
33449
+ time,
33450
+ job.config.fps,
33451
+ hdrFrameDirs,
33452
+ hdrVideoStartTimes,
33453
+ width,
33454
+ height,
33455
+ log2,
33456
+ videoTransfers.get(el.id),
33457
+ effectiveHdr?.transfer
33458
+ );
33459
+ }
33460
+ }
33461
+ const showIds = Array.from(sceneIds);
33462
+ const hideIds = stackingInfo.map((e2) => e2.id).filter((id) => !sceneIds.has(id) || nativeHdrIds.has(id));
33463
+ await applyDomLayerMask(domSession.page, showIds, hideIds);
33464
+ const domPng = await captureAlphaPng(domSession.page, width, height);
33465
+ await removeDomLayerMask(domSession.page, hideIds);
33466
+ try {
33467
+ const { data: domRgba } = decodePng(domPng);
33468
+ if (!effectiveHdr) {
33469
+ throw new Error(
33470
+ "Invariant violation: effectiveHdr is undefined inside hasHdrVideo branch"
33471
+ );
33472
+ }
33473
+ blitRgba8OverRgb48le(
33474
+ domRgba,
33475
+ sceneBuf,
33476
+ width,
33477
+ height,
33478
+ effectiveHdr.transfer
33410
33479
  );
33480
+ } catch (err) {
33481
+ log2.warn("DOM layer decode/blit failed; skipping overlay for transition scene", {
33482
+ frameIndex: i2,
33483
+ sceneIds: Array.from(sceneIds),
33484
+ error: err instanceof Error ? err.message : String(err)
33485
+ });
33411
33486
  }
33412
- blitRgba8OverRgb48le(
33413
- domRgba,
33414
- sceneBuf,
33415
- width,
33416
- height,
33417
- effectiveHdr.transfer
33487
+ }
33488
+ const transitionFn = TRANSITIONS[activeTransition.shader] ?? crossfade;
33489
+ transitionFn(transBufferA, transBufferB, transOutput, width, height, progress);
33490
+ hdrEncoder.writeFrame(transOutput);
33491
+ } else {
33492
+ normalCanvas.fill(0);
33493
+ await compositeToBuffer(normalCanvas, time, stackingInfo, void 0, i2);
33494
+ if (debugDumpEnabled && debugDumpDir && i2 % 30 === 0) {
33495
+ const previewPath = join31(
33496
+ debugDumpDir,
33497
+ `frame_${String(i2).padStart(4, "0")}_final_rgb48le.bin`
33418
33498
  );
33419
- } catch (err) {
33420
- log2.warn("DOM layer decode/blit failed; skipping overlay for transition scene", {
33421
- frameIndex: i2,
33422
- sceneIds: Array.from(sceneIds),
33423
- error: err instanceof Error ? err.message : String(err)
33424
- });
33499
+ writeFileSync10(previewPath, normalCanvas);
33425
33500
  }
33501
+ hdrEncoder.writeFrame(normalCanvas);
33426
33502
  }
33427
- const transitionFn = TRANSITIONS[activeTransition.shader] ?? crossfade;
33428
- transitionFn(transBufferA, transBufferB, transOutput, width, height, progress);
33429
- hdrEncoder.writeFrame(transOutput);
33430
- } else {
33431
- normalCanvas.fill(0);
33432
- await compositeToBuffer(normalCanvas, time, stackingInfo, void 0, i2);
33433
- if (debugDumpEnabled && debugDumpDir && i2 % 30 === 0) {
33434
- const previewPath = join31(
33435
- debugDumpDir,
33436
- `frame_${String(i2).padStart(4, "0")}_final_rgb48le.bin`
33437
- );
33438
- writeFileSync10(previewPath, normalCanvas);
33439
- }
33440
- hdrEncoder.writeFrame(normalCanvas);
33441
- }
33442
- if (process.env.KEEP_TEMP !== "1") {
33443
- for (const [videoId, endTime] of hdrVideoEndTimes) {
33444
- if (time > endTime && !cleanedUpVideos.has(videoId)) {
33445
- const stillNeeded = activeTransition && (sceneElements[activeTransition.fromScene]?.includes(videoId) || sceneElements[activeTransition.toScene]?.includes(videoId));
33446
- if (!stillNeeded) {
33447
- const frameDir = hdrFrameDirs.get(videoId);
33448
- if (frameDir) {
33449
- try {
33450
- rmSync6(frameDir, { recursive: true, force: true });
33451
- } catch (err) {
33452
- log2.warn("Failed to clean up HDR frame directory", {
33453
- videoId,
33454
- frameDir,
33455
- error: err instanceof Error ? err.message : String(err)
33456
- });
33503
+ if (process.env.KEEP_TEMP !== "1") {
33504
+ for (const [videoId, endTime] of hdrVideoEndTimes) {
33505
+ if (time > endTime && !cleanedUpVideos.has(videoId)) {
33506
+ const stillNeeded = activeTransition && (sceneElements[activeTransition.fromScene]?.includes(videoId) || sceneElements[activeTransition.toScene]?.includes(videoId));
33507
+ if (!stillNeeded) {
33508
+ const frameDir = hdrFrameDirs.get(videoId);
33509
+ if (frameDir) {
33510
+ try {
33511
+ rmSync6(frameDir, { recursive: true, force: true });
33512
+ } catch (err) {
33513
+ log2.warn("Failed to clean up HDR frame directory", {
33514
+ videoId,
33515
+ frameDir,
33516
+ error: err instanceof Error ? err.message : String(err)
33517
+ });
33518
+ }
33519
+ frameDirMaxIndexCache.delete(frameDir);
33520
+ hdrFrameDirs.delete(videoId);
33457
33521
  }
33522
+ cleanedUpVideos.add(videoId);
33458
33523
  }
33459
- cleanedUpVideos.add(videoId);
33460
33524
  }
33461
33525
  }
33462
33526
  }
33527
+ job.framesRendered = i2 + 1;
33528
+ if ((i2 + 1) % 10 === 0 || i2 + 1 === totalFrames) {
33529
+ const frameProgress = (i2 + 1) / totalFrames;
33530
+ updateJobStatus(
33531
+ job,
33532
+ "rendering",
33533
+ `HDR composite frame ${i2 + 1}/${job.totalFrames}`,
33534
+ Math.round(25 + frameProgress * 55),
33535
+ onProgress
33536
+ );
33537
+ }
33463
33538
  }
33464
- job.framesRendered = i2 + 1;
33465
- if ((i2 + 1) % 10 === 0 || i2 + 1 === totalFrames) {
33466
- const frameProgress = (i2 + 1) / totalFrames;
33467
- updateJobStatus(
33468
- job,
33469
- "rendering",
33470
- `HDR composite frame ${i2 + 1}/${job.totalFrames}`,
33471
- Math.round(25 + frameProgress * 55),
33472
- onProgress
33473
- );
33474
- }
33539
+ } finally {
33540
+ lastBrowserConsole = domSession.browserConsoleBuffer;
33541
+ await closeCaptureSession(domSession);
33542
+ domSessionClosed = true;
33475
33543
  }
33544
+ const hdrEncodeResult = await hdrEncoder.close();
33545
+ hdrEncoderClosed = true;
33546
+ assertNotAborted();
33547
+ if (!hdrEncodeResult.success) {
33548
+ throw new Error(`HDR encode failed: ${hdrEncodeResult.error}`);
33549
+ }
33550
+ perfStages.captureMs = Date.now() - stage4Start;
33551
+ perfStages.encodeMs = hdrEncodeResult.durationMs;
33476
33552
  } finally {
33477
- lastBrowserConsole = domSession.browserConsoleBuffer;
33478
- await closeCaptureSession(domSession);
33479
- }
33480
- const hdrEncodeResult = await hdrEncoder.close();
33481
- assertNotAborted();
33482
- if (!hdrEncodeResult.success) {
33483
- throw new Error(`HDR encode failed: ${hdrEncodeResult.error}`);
33553
+ if (hdrEncoder && !hdrEncoderClosed) {
33554
+ try {
33555
+ await hdrEncoder.close();
33556
+ } catch (err) {
33557
+ log2.warn("hdrEncoder defensive close failed", {
33558
+ err: err instanceof Error ? err.message : String(err)
33559
+ });
33560
+ }
33561
+ }
33562
+ if (!domSessionClosed) {
33563
+ await closeCaptureSession(domSession).catch((err) => {
33564
+ log2.warn("closeCaptureSession defensive close failed", {
33565
+ err: err instanceof Error ? err.message : String(err)
33566
+ });
33567
+ });
33568
+ }
33569
+ for (const frameDir of hdrFrameDirs.values()) {
33570
+ frameDirMaxIndexCache.delete(frameDir);
33571
+ }
33572
+ hdrFrameDirs.clear();
33484
33573
  }
33485
- perfStages.captureMs = Date.now() - stage4Start;
33486
- perfStages.encodeMs = hdrEncodeResult.durationMs;
33487
33574
  } else {
33488
33575
  let streamingEncoder = null;
33576
+ let streamingEncoderClosed = false;
33489
33577
  if (enableStreamingEncode) {
33490
33578
  streamingEncoder = await spawnStreamingEncoder(
33491
33579
  videoOnlyPath,
@@ -33495,7 +33583,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33495
33583
  height,
33496
33584
  codec: preset.codec,
33497
33585
  preset: preset.preset,
33498
- quality: preset.quality,
33586
+ quality: effectiveQuality,
33587
+ bitrate: effectiveBitrate,
33499
33588
  pixelFormat: preset.pixelFormat,
33500
33589
  useGpu: job.config.useGpu,
33501
33590
  imageFormat: captureOptions.format || "jpeg",
@@ -33505,201 +33594,215 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33505
33594
  );
33506
33595
  assertNotAborted();
33507
33596
  }
33508
- if (enableStreamingEncode && streamingEncoder) {
33509
- const reorderBuffer = createFrameReorderBuffer(0, totalFrames);
33510
- const currentEncoder = streamingEncoder;
33511
- if (workerCount > 1) {
33512
- const tasks = distributeFrames(job.totalFrames, workerCount, workDir);
33513
- const onFrameBuffer = async (frameIndex, buffer) => {
33514
- await reorderBuffer.waitForFrame(frameIndex);
33515
- currentEncoder.writeFrame(buffer);
33516
- reorderBuffer.advanceTo(frameIndex + 1);
33517
- };
33518
- await executeParallelCapture(
33519
- fileServer.url,
33520
- workDir,
33521
- tasks,
33522
- { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33523
- () => createVideoFrameInjector(frameLookup),
33524
- abortSignal,
33525
- (progress) => {
33526
- job.framesRendered = progress.capturedFrames;
33527
- const frameProgress = progress.capturedFrames / progress.totalFrames;
33528
- const progressPct = 25 + frameProgress * 55;
33529
- if (progress.capturedFrames % 30 === 0 || progress.capturedFrames === progress.totalFrames) {
33597
+ try {
33598
+ if (enableStreamingEncode && streamingEncoder) {
33599
+ const reorderBuffer = createFrameReorderBuffer(0, totalFrames);
33600
+ const currentEncoder = streamingEncoder;
33601
+ if (workerCount > 1) {
33602
+ const tasks = distributeFrames(job.totalFrames, workerCount, workDir);
33603
+ const onFrameBuffer = async (frameIndex, buffer) => {
33604
+ await reorderBuffer.waitForFrame(frameIndex);
33605
+ currentEncoder.writeFrame(buffer);
33606
+ reorderBuffer.advanceTo(frameIndex + 1);
33607
+ };
33608
+ await executeParallelCapture(
33609
+ fileServer.url,
33610
+ workDir,
33611
+ tasks,
33612
+ { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33613
+ () => createVideoFrameInjector(frameLookup),
33614
+ abortSignal,
33615
+ (progress) => {
33616
+ job.framesRendered = progress.capturedFrames;
33617
+ const frameProgress = progress.capturedFrames / progress.totalFrames;
33618
+ const progressPct = 25 + frameProgress * 55;
33619
+ if (progress.capturedFrames % 30 === 0 || progress.capturedFrames === progress.totalFrames) {
33620
+ updateJobStatus(
33621
+ job,
33622
+ "rendering",
33623
+ `Streaming frame ${progress.capturedFrames}/${progress.totalFrames} (${workerCount} workers)`,
33624
+ Math.round(progressPct),
33625
+ onProgress
33626
+ );
33627
+ }
33628
+ },
33629
+ onFrameBuffer,
33630
+ cfg
33631
+ );
33632
+ if (probeSession) {
33633
+ lastBrowserConsole = probeSession.browserConsoleBuffer;
33634
+ await closeCaptureSession(probeSession);
33635
+ probeSession = null;
33636
+ }
33637
+ } else {
33638
+ const videoInjector = createVideoFrameInjector(frameLookup);
33639
+ const session = probeSession ?? await createCaptureSession(
33640
+ fileServer.url,
33641
+ framesDir,
33642
+ { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33643
+ videoInjector,
33644
+ cfg
33645
+ );
33646
+ if (probeSession) {
33647
+ prepareCaptureSessionForReuse(session, framesDir, videoInjector);
33648
+ probeSession = null;
33649
+ }
33650
+ try {
33651
+ if (!session.isInitialized) {
33652
+ await initializeSession(session);
33653
+ }
33654
+ assertNotAborted();
33655
+ lastBrowserConsole = session.browserConsoleBuffer;
33656
+ for (let i2 = 0; i2 < totalFrames; i2++) {
33657
+ assertNotAborted();
33658
+ const time = i2 / job.config.fps;
33659
+ const { buffer } = await captureFrameToBuffer(session, i2, time);
33660
+ await reorderBuffer.waitForFrame(i2);
33661
+ currentEncoder.writeFrame(buffer);
33662
+ reorderBuffer.advanceTo(i2 + 1);
33663
+ job.framesRendered = i2 + 1;
33664
+ const frameProgress = (i2 + 1) / totalFrames;
33665
+ const progress = 25 + frameProgress * 55;
33530
33666
  updateJobStatus(
33531
33667
  job,
33532
33668
  "rendering",
33533
- `Streaming frame ${progress.capturedFrames}/${progress.totalFrames} (${workerCount} workers)`,
33534
- Math.round(progressPct),
33669
+ `Streaming frame ${i2 + 1}/${job.totalFrames}`,
33670
+ Math.round(progress),
33535
33671
  onProgress
33536
33672
  );
33537
33673
  }
33538
- },
33539
- onFrameBuffer,
33540
- cfg
33541
- );
33542
- if (probeSession) {
33543
- lastBrowserConsole = probeSession.browserConsoleBuffer;
33544
- await closeCaptureSession(probeSession);
33545
- probeSession = null;
33674
+ } finally {
33675
+ lastBrowserConsole = session.browserConsoleBuffer;
33676
+ await closeCaptureSession(session);
33677
+ }
33546
33678
  }
33547
- } else {
33548
- const videoInjector = createVideoFrameInjector(frameLookup);
33549
- const session = probeSession ?? await createCaptureSession(
33550
- fileServer.url,
33551
- framesDir,
33552
- { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33553
- videoInjector,
33554
- cfg
33555
- );
33556
- if (probeSession) {
33557
- prepareCaptureSessionForReuse(session, framesDir, videoInjector);
33558
- probeSession = null;
33679
+ const encodeResult = await currentEncoder.close();
33680
+ streamingEncoderClosed = true;
33681
+ assertNotAborted();
33682
+ if (!encodeResult.success) {
33683
+ throw new Error(`Streaming encode failed: ${encodeResult.error}`);
33559
33684
  }
33560
- try {
33561
- if (!session.isInitialized) {
33562
- await initializeSession(session);
33685
+ perfStages.captureMs = Date.now() - stage4Start;
33686
+ perfStages.encodeMs = encodeResult.durationMs;
33687
+ } else {
33688
+ if (workerCount > 1) {
33689
+ const tasks = distributeFrames(job.totalFrames, workerCount, workDir);
33690
+ await executeParallelCapture(
33691
+ fileServer.url,
33692
+ workDir,
33693
+ tasks,
33694
+ { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33695
+ () => createVideoFrameInjector(frameLookup),
33696
+ abortSignal,
33697
+ (progress) => {
33698
+ job.framesRendered = progress.capturedFrames;
33699
+ const frameProgress = progress.capturedFrames / progress.totalFrames;
33700
+ const progressPct = 25 + frameProgress * 45;
33701
+ if (progress.capturedFrames % 30 === 0 || progress.capturedFrames === progress.totalFrames) {
33702
+ updateJobStatus(
33703
+ job,
33704
+ "rendering",
33705
+ `Capturing frame ${progress.capturedFrames}/${progress.totalFrames} (${workerCount} workers)`,
33706
+ Math.round(progressPct),
33707
+ onProgress
33708
+ );
33709
+ }
33710
+ },
33711
+ void 0,
33712
+ cfg
33713
+ );
33714
+ await mergeWorkerFrames(workDir, tasks, framesDir);
33715
+ if (probeSession) {
33716
+ lastBrowserConsole = probeSession.browserConsoleBuffer;
33717
+ await closeCaptureSession(probeSession);
33718
+ probeSession = null;
33563
33719
  }
33564
- assertNotAborted();
33565
- lastBrowserConsole = session.browserConsoleBuffer;
33566
- for (let i2 = 0; i2 < totalFrames; i2++) {
33567
- assertNotAborted();
33568
- const time = i2 / job.config.fps;
33569
- const { buffer } = await captureFrameToBuffer(session, i2, time);
33570
- await reorderBuffer.waitForFrame(i2);
33571
- currentEncoder.writeFrame(buffer);
33572
- reorderBuffer.advanceTo(i2 + 1);
33573
- job.framesRendered = i2 + 1;
33574
- const frameProgress = (i2 + 1) / totalFrames;
33575
- const progress = 25 + frameProgress * 55;
33576
- updateJobStatus(
33577
- job,
33578
- "rendering",
33579
- `Streaming frame ${i2 + 1}/${job.totalFrames}`,
33580
- Math.round(progress),
33581
- onProgress
33582
- );
33720
+ } else {
33721
+ const videoInjector = createVideoFrameInjector(frameLookup);
33722
+ const session = probeSession ?? await createCaptureSession(
33723
+ fileServer.url,
33724
+ framesDir,
33725
+ { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33726
+ videoInjector,
33727
+ cfg
33728
+ );
33729
+ if (probeSession) {
33730
+ prepareCaptureSessionForReuse(session, framesDir, videoInjector);
33731
+ probeSession = null;
33583
33732
  }
33584
- } finally {
33585
- lastBrowserConsole = session.browserConsoleBuffer;
33586
- await closeCaptureSession(session);
33587
- }
33588
- }
33589
- const encodeResult = await currentEncoder.close();
33590
- assertNotAborted();
33591
- if (!encodeResult.success) {
33592
- throw new Error(`Streaming encode failed: ${encodeResult.error}`);
33593
- }
33594
- perfStages.captureMs = Date.now() - stage4Start;
33595
- perfStages.encodeMs = encodeResult.durationMs;
33596
- } else {
33597
- if (workerCount > 1) {
33598
- const tasks = distributeFrames(job.totalFrames, workerCount, workDir);
33599
- await executeParallelCapture(
33600
- fileServer.url,
33601
- workDir,
33602
- tasks,
33603
- { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33604
- () => createVideoFrameInjector(frameLookup),
33605
- abortSignal,
33606
- (progress) => {
33607
- job.framesRendered = progress.capturedFrames;
33608
- const frameProgress = progress.capturedFrames / progress.totalFrames;
33609
- const progressPct = 25 + frameProgress * 45;
33610
- if (progress.capturedFrames % 30 === 0 || progress.capturedFrames === progress.totalFrames) {
33733
+ try {
33734
+ if (!session.isInitialized) {
33735
+ await initializeSession(session);
33736
+ }
33737
+ assertNotAborted();
33738
+ lastBrowserConsole = session.browserConsoleBuffer;
33739
+ for (let i2 = 0; i2 < job.totalFrames; i2++) {
33740
+ assertNotAborted();
33741
+ const time = i2 / job.config.fps;
33742
+ await captureFrame(session, i2, time);
33743
+ job.framesRendered = i2 + 1;
33744
+ const frameProgress = (i2 + 1) / job.totalFrames;
33745
+ const progress = 25 + frameProgress * 45;
33611
33746
  updateJobStatus(
33612
33747
  job,
33613
33748
  "rendering",
33614
- `Capturing frame ${progress.capturedFrames}/${progress.totalFrames} (${workerCount} workers)`,
33615
- Math.round(progressPct),
33749
+ `Capturing frame ${i2 + 1}/${job.totalFrames}`,
33750
+ Math.round(progress),
33616
33751
  onProgress
33617
33752
  );
33618
33753
  }
33619
- },
33620
- void 0,
33621
- cfg
33622
- );
33623
- await mergeWorkerFrames(workDir, tasks, framesDir);
33624
- if (probeSession) {
33625
- lastBrowserConsole = probeSession.browserConsoleBuffer;
33626
- await closeCaptureSession(probeSession);
33627
- probeSession = null;
33754
+ } finally {
33755
+ lastBrowserConsole = session.browserConsoleBuffer;
33756
+ await closeCaptureSession(session);
33757
+ }
33628
33758
  }
33629
- } else {
33630
- const videoInjector = createVideoFrameInjector(frameLookup);
33631
- const session = probeSession ?? await createCaptureSession(
33632
- fileServer.url,
33759
+ perfStages.captureMs = Date.now() - stage4Start;
33760
+ const stage5Start = Date.now();
33761
+ updateJobStatus(job, "encoding", "Encoding video", 75, onProgress);
33762
+ const frameExt = needsAlpha ? "png" : "jpg";
33763
+ const framePattern = `frame_%06d.${frameExt}`;
33764
+ const encoderOpts = {
33765
+ fps: job.config.fps,
33766
+ width,
33767
+ height,
33768
+ codec: preset.codec,
33769
+ preset: preset.preset,
33770
+ quality: effectiveQuality,
33771
+ bitrate: effectiveBitrate,
33772
+ pixelFormat: preset.pixelFormat,
33773
+ useGpu: job.config.useGpu,
33774
+ hdr: preset.hdr
33775
+ };
33776
+ const encodeResult = enableChunkedEncode ? await encodeFramesChunkedConcat(
33777
+ framesDir,
33778
+ framePattern,
33779
+ videoOnlyPath,
33780
+ encoderOpts,
33781
+ chunkedEncodeSize,
33782
+ abortSignal
33783
+ ) : await encodeFramesFromDir(
33633
33784
  framesDir,
33634
- { ...captureOptions, skipReadinessVideoIds: Array.from(nativeHdrVideoIds) },
33635
- videoInjector,
33636
- cfg
33785
+ framePattern,
33786
+ videoOnlyPath,
33787
+ encoderOpts,
33788
+ abortSignal
33637
33789
  );
33638
- if (probeSession) {
33639
- prepareCaptureSessionForReuse(session, framesDir, videoInjector);
33640
- probeSession = null;
33790
+ assertNotAborted();
33791
+ if (!encodeResult.success) {
33792
+ throw new Error(`Encoding failed: ${encodeResult.error}`);
33641
33793
  }
33794
+ perfStages.encodeMs = Date.now() - stage5Start;
33795
+ }
33796
+ } finally {
33797
+ if (streamingEncoder && !streamingEncoderClosed) {
33642
33798
  try {
33643
- if (!session.isInitialized) {
33644
- await initializeSession(session);
33645
- }
33646
- assertNotAborted();
33647
- lastBrowserConsole = session.browserConsoleBuffer;
33648
- for (let i2 = 0; i2 < job.totalFrames; i2++) {
33649
- assertNotAborted();
33650
- const time = i2 / job.config.fps;
33651
- await captureFrame(session, i2, time);
33652
- job.framesRendered = i2 + 1;
33653
- const frameProgress = (i2 + 1) / job.totalFrames;
33654
- const progress = 25 + frameProgress * 45;
33655
- updateJobStatus(
33656
- job,
33657
- "rendering",
33658
- `Capturing frame ${i2 + 1}/${job.totalFrames}`,
33659
- Math.round(progress),
33660
- onProgress
33661
- );
33662
- }
33663
- } finally {
33664
- lastBrowserConsole = session.browserConsoleBuffer;
33665
- await closeCaptureSession(session);
33799
+ await streamingEncoder.close();
33800
+ } catch (err) {
33801
+ log2.warn("streamingEncoder defensive close failed", {
33802
+ err: err instanceof Error ? err.message : String(err)
33803
+ });
33666
33804
  }
33667
33805
  }
33668
- perfStages.captureMs = Date.now() - stage4Start;
33669
- const stage5Start = Date.now();
33670
- updateJobStatus(job, "encoding", "Encoding video", 75, onProgress);
33671
- const frameExt = needsAlpha ? "png" : "jpg";
33672
- const framePattern = `frame_%06d.${frameExt}`;
33673
- const encoderOpts = {
33674
- fps: job.config.fps,
33675
- width,
33676
- height,
33677
- codec: preset.codec,
33678
- preset: preset.preset,
33679
- quality: preset.quality,
33680
- pixelFormat: preset.pixelFormat,
33681
- useGpu: job.config.useGpu,
33682
- hdr: preset.hdr
33683
- };
33684
- const encodeResult = enableChunkedEncode ? await encodeFramesChunkedConcat(
33685
- framesDir,
33686
- framePattern,
33687
- videoOnlyPath,
33688
- encoderOpts,
33689
- chunkedEncodeSize,
33690
- abortSignal
33691
- ) : await encodeFramesFromDir(
33692
- framesDir,
33693
- framePattern,
33694
- videoOnlyPath,
33695
- encoderOpts,
33696
- abortSignal
33697
- );
33698
- assertNotAborted();
33699
- if (!encodeResult.success) {
33700
- throw new Error(`Encoding failed: ${encodeResult.error}`);
33701
- }
33702
- perfStages.encodeMs = Date.now() - stage5Start;
33703
33806
  }
33704
33807
  }
33705
33808
  if (probeSession !== null) {
@@ -33909,7 +34012,7 @@ var init_config3 = __esm({
33909
34012
 
33910
34013
  // ../producer/src/services/hyperframeLint.ts
33911
34014
  import { existsSync as existsSync29, readFileSync as readFileSync22, statSync as statSync8 } from "fs";
33912
- import { resolve as resolve16, join as join32 } from "path";
34015
+ import { resolve as resolve17, join as join32 } from "path";
33913
34016
  function isStringRecord(value) {
33914
34017
  if (!value || typeof value !== "object" || Array.isArray(value)) {
33915
34018
  return false;
@@ -33936,7 +34039,7 @@ function pickEntryFile(files, preferredEntryFile) {
33936
34039
  return null;
33937
34040
  }
33938
34041
  function readProjectEntryFile(projectDir, preferredEntryFile) {
33939
- const absProjectDir = resolve16(projectDir);
34042
+ const absProjectDir = resolve17(projectDir);
33940
34043
  if (!existsSync29(absProjectDir) || !statSync8(absProjectDir).isDirectory()) {
33941
34044
  return { error: `Project directory not found: ${absProjectDir}` };
33942
34045
  }
@@ -33944,7 +34047,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
33944
34047
  (value) => typeof value === "string" && value.trim().length > 0
33945
34048
  );
33946
34049
  for (const entryFile of entryCandidates) {
33947
- const absoluteEntryPath = resolve16(absProjectDir, entryFile);
34050
+ const absoluteEntryPath = resolve17(absProjectDir, entryFile);
33948
34051
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
33949
34052
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
33950
34053
  }
@@ -34019,10 +34122,10 @@ var init_semaphore = __esm({
34019
34122
  this.active++;
34020
34123
  return () => this.release();
34021
34124
  }
34022
- return new Promise((resolve36) => {
34125
+ return new Promise((resolve37) => {
34023
34126
  this.queue.push(() => {
34024
34127
  this.active++;
34025
- resolve36(() => this.release());
34128
+ resolve37(() => this.release());
34026
34129
  });
34027
34130
  });
34028
34131
  }
@@ -34053,7 +34156,7 @@ import {
34053
34156
  rmSync as rmSync7,
34054
34157
  createReadStream
34055
34158
  } from "fs";
34056
- import { resolve as resolve17, dirname as dirname11, join as join33 } from "path";
34159
+ import { resolve as resolve18, dirname as dirname11, join as join33 } from "path";
34057
34160
  import { tmpdir as tmpdir2 } from "os";
34058
34161
  import { parseArgs as parseArgs2 } from "util";
34059
34162
  import crypto2 from "crypto";
@@ -34075,12 +34178,12 @@ async function prepareRenderBody(body) {
34075
34178
  const options = parseRenderOptions(body);
34076
34179
  const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
34077
34180
  if (projectDir) {
34078
- const absProjectDir = resolve17(projectDir);
34181
+ const absProjectDir = resolve18(projectDir);
34079
34182
  if (!existsSync30(absProjectDir) || !statSync9(absProjectDir).isDirectory()) {
34080
34183
  return { error: `Project directory not found: ${absProjectDir}` };
34081
34184
  }
34082
34185
  const entry = options.entryFile || "index.html";
34083
- if (!existsSync30(resolve17(absProjectDir, entry))) {
34186
+ if (!existsSync30(resolve18(absProjectDir, entry))) {
34084
34187
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
34085
34188
  }
34086
34189
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -34121,7 +34224,7 @@ function resolveOutputPath(projectDir, outputCandidate, rendersDir, log2) {
34121
34224
  try {
34122
34225
  return resolveRenderPaths(projectDir, outputCandidate, rendersDir).absoluteOutputPath;
34123
34226
  } catch (error) {
34124
- const fallbackPath = resolve17(rendersDir, `producer-fallback-${Date.now()}.mp4`);
34227
+ const fallbackPath = resolve18(rendersDir, `producer-fallback-${Date.now()}.mp4`);
34125
34228
  log2.warn("Failed to resolve output path, using fallback", {
34126
34229
  fallback: fallbackPath,
34127
34230
  error: error instanceof Error ? error.message : String(error)
@@ -34509,7 +34612,7 @@ var init_server = __esm({
34509
34612
  init_paths();
34510
34613
  init_logger();
34511
34614
  init_semaphore();
34512
- entryScript = process.argv[1] ? resolve17(process.argv[1]) : "";
34615
+ entryScript = process.argv[1] ? resolve18(process.argv[1]) : "";
34513
34616
  isPublicServerEntry = entryScript.endsWith("/public-server.js") || entryScript.endsWith("/src/server.ts");
34514
34617
  if (isPublicServerEntry) {
34515
34618
  const { values } = parseArgs2({
@@ -34582,18 +34685,18 @@ __export(studioServer_exports, {
34582
34685
  import { Hono as Hono5 } from "hono";
34583
34686
  import { streamSSE as streamSSE3 } from "hono/streaming";
34584
34687
  import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as writeFileSync12, statSync as statSync10 } from "fs";
34585
- import { resolve as resolve18, join as join34, basename as basename2 } from "path";
34688
+ import { resolve as resolve19, join as join34, basename as basename2 } from "path";
34586
34689
  function resolveDistDir() {
34587
- const builtPath = resolve18(__dirname, "studio");
34588
- if (existsSync31(resolve18(builtPath, "index.html"))) return builtPath;
34589
- const devPath = resolve18(__dirname, "..", "..", "..", "studio", "dist");
34590
- if (existsSync31(resolve18(devPath, "index.html"))) return devPath;
34690
+ const builtPath = resolve19(__dirname, "studio");
34691
+ if (existsSync31(resolve19(builtPath, "index.html"))) return builtPath;
34692
+ const devPath = resolve19(__dirname, "..", "..", "..", "studio", "dist");
34693
+ if (existsSync31(resolve19(devPath, "index.html"))) return devPath;
34591
34694
  return builtPath;
34592
34695
  }
34593
34696
  function resolveRuntimePath() {
34594
- const builtPath = resolve18(__dirname, "hyperframe-runtime.js");
34697
+ const builtPath = resolve19(__dirname, "hyperframe-runtime.js");
34595
34698
  if (existsSync31(builtPath)) return builtPath;
34596
- const devPath = resolve18(
34699
+ const devPath = resolve19(
34597
34700
  __dirname,
34598
34701
  "..",
34599
34702
  "..",
@@ -34814,7 +34917,7 @@ function createStudioServer(options) {
34814
34917
  return api.fetch(forwardReq);
34815
34918
  });
34816
34919
  app.get("/assets/*", (c2) => {
34817
- const filePath = resolve18(studioDir, c2.req.path.slice(1));
34920
+ const filePath = resolve19(studioDir, c2.req.path.slice(1));
34818
34921
  if (!existsSync31(filePath) || !statSync10(filePath).isFile()) return c2.text("not found", 404);
34819
34922
  const content = readFileSync23(filePath);
34820
34923
  return new Response(content, {
@@ -34822,7 +34925,7 @@ function createStudioServer(options) {
34822
34925
  });
34823
34926
  });
34824
34927
  app.get("/icons/*", (c2) => {
34825
- const filePath = resolve18(studioDir, c2.req.path.slice(1));
34928
+ const filePath = resolve19(studioDir, c2.req.path.slice(1));
34826
34929
  if (!existsSync31(filePath) || !statSync10(filePath).isFile()) return c2.text("not found", 404);
34827
34930
  const content = readFileSync23(filePath);
34828
34931
  return new Response(content, {
@@ -34830,7 +34933,7 @@ function createStudioServer(options) {
34830
34933
  });
34831
34934
  });
34832
34935
  app.get("*", (c2) => {
34833
- const indexPath = resolve18(studioDir, "index.html");
34936
+ const indexPath = resolve19(studioDir, "index.html");
34834
34937
  if (!existsSync31(indexPath)) {
34835
34938
  return c2.text("Studio not found. Rebuild with: pnpm run build", 500);
34836
34939
  }
@@ -34859,12 +34962,12 @@ __export(preview_exports, {
34859
34962
  });
34860
34963
  import { spawn as spawn8 } from "child_process";
34861
34964
  import { existsSync as existsSync32, lstatSync, symlinkSync, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync19 } from "fs";
34862
- import { resolve as resolve19, dirname as dirname12, basename as basename3, join as join35 } from "path";
34965
+ import { resolve as resolve20, dirname as dirname12, basename as basename3, join as join35 } from "path";
34863
34966
  import { fileURLToPath as fileURLToPath4 } from "url";
34864
34967
  import { createRequire } from "module";
34865
34968
  async function runDevMode(dir, projectName) {
34866
34969
  const thisFile = fileURLToPath4(import.meta.url);
34867
- const repoRoot = resolve19(dirname12(thisFile), "..", "..", "..", "..");
34970
+ const repoRoot = resolve20(dirname12(thisFile), "..", "..", "..", "..");
34868
34971
  const projectsDir = join35(repoRoot, "packages", "studio", "data", "projects");
34869
34972
  const pName = projectName ?? basename3(dir);
34870
34973
  const symlinkPath = join35(projectsDir, pName);
@@ -34876,7 +34979,7 @@ async function runDevMode(dir, projectName) {
34876
34979
  const stat3 = lstatSync(symlinkPath);
34877
34980
  if (stat3.isSymbolicLink()) {
34878
34981
  const target = readlinkSync(symlinkPath);
34879
- if (resolve19(target) !== resolve19(dir)) {
34982
+ if (resolve20(target) !== resolve20(dir)) {
34880
34983
  unlinkSync5(symlinkPath);
34881
34984
  }
34882
34985
  }
@@ -34930,8 +35033,8 @@ async function runDevMode(dir, projectName) {
34930
35033
  }
34931
35034
  });
34932
35035
  }
34933
- return new Promise((resolve36) => {
34934
- child.on("close", () => resolve36());
35036
+ return new Promise((resolve37) => {
35037
+ child.on("close", () => resolve37());
34935
35038
  });
34936
35039
  }
34937
35040
  function hasLocalStudio(dir) {
@@ -34953,7 +35056,7 @@ async function runLocalStudioMode(dir, projectName) {
34953
35056
  let createdSymlink = false;
34954
35057
  if (dir !== symlinkPath) {
34955
35058
  if (existsSync32(symlinkPath) && lstatSync(symlinkPath).isSymbolicLink()) {
34956
- if (resolve19(readlinkSync(symlinkPath)) !== resolve19(dir)) {
35059
+ if (resolve20(readlinkSync(symlinkPath)) !== resolve20(dir)) {
34957
35060
  unlinkSync5(symlinkPath);
34958
35061
  }
34959
35062
  }
@@ -35001,8 +35104,8 @@ async function runLocalStudioMode(dir, projectName) {
35001
35104
  }
35002
35105
  });
35003
35106
  }
35004
- return new Promise((resolve36) => {
35005
- child.on("close", () => resolve36());
35107
+ return new Promise((resolve37) => {
35108
+ child.on("close", () => resolve37());
35006
35109
  });
35007
35110
  }
35008
35111
  async function runEmbeddedMode(dir, startPort, projectName, forceNew = false) {
@@ -35133,7 +35236,7 @@ var init_preview2 = __esm({
35133
35236
  return;
35134
35237
  }
35135
35238
  const rawArg = args.dir;
35136
- const dir = resolve19(rawArg ?? ".");
35239
+ const dir = resolve20(rawArg ?? ".");
35137
35240
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
35138
35241
  const projectName = isImplicitCwd ? basename3(process.env.PWD ?? dir) : basename3(dir);
35139
35242
  const indexPath = join35(dir, "index.html");
@@ -35174,7 +35277,7 @@ import {
35174
35277
  readFileSync as readFileSync24,
35175
35278
  readdirSync as readdirSync12
35176
35279
  } from "fs";
35177
- import { resolve as resolve20, basename as basename4, join as join36, dirname as dirname13 } from "path";
35280
+ import { resolve as resolve21, basename as basename4, join as join36, dirname as dirname13 } from "path";
35178
35281
  import { fileURLToPath as fileURLToPath5 } from "url";
35179
35282
  import { execFileSync as execFileSync4, spawn as spawn9 } from "child_process";
35180
35283
  function probeVideo(filePath) {
@@ -35244,8 +35347,8 @@ function transcodeToMp4(inputPath, outputPath) {
35244
35347
  }
35245
35348
  function resolveAssetDir(devSegments, builtSegments) {
35246
35349
  const base = dirname13(fileURLToPath5(import.meta.url));
35247
- const devPath = resolve20(base, ...devSegments);
35248
- const builtPath = resolve20(base, ...builtSegments);
35350
+ const devPath = resolve21(base, ...devSegments);
35351
+ const builtPath = resolve21(base, ...builtSegments);
35249
35352
  return existsSync33(devPath) ? devPath : builtPath;
35250
35353
  }
35251
35354
  function getStaticTemplateDir(templateId) {
@@ -35330,7 +35433,7 @@ async function handleVideoFile(videoPath, destDir, interactive) {
35330
35433
  }
35331
35434
  if (shouldTranscode) {
35332
35435
  const mp4Name = localVideoName.replace(/\.[^.]+$/, ".mp4");
35333
- const mp4Path = resolve20(destDir, mp4Name);
35436
+ const mp4Path = resolve21(destDir, mp4Name);
35334
35437
  const spin = be();
35335
35438
  spin.start("Transcoding to H.264 MP4...");
35336
35439
  const ok = await transcodeToMp4(videoPath, mp4Path);
@@ -35339,10 +35442,10 @@ async function handleVideoFile(videoPath, destDir, interactive) {
35339
35442
  localVideoName = mp4Name;
35340
35443
  } else {
35341
35444
  spin.stop(c.warn("Transcode failed \u2014 copying original file"));
35342
- copyFileSync3(videoPath, resolve20(destDir, localVideoName));
35445
+ copyFileSync3(videoPath, resolve21(destDir, localVideoName));
35343
35446
  }
35344
35447
  } else {
35345
- copyFileSync3(videoPath, resolve20(destDir, localVideoName));
35448
+ copyFileSync3(videoPath, resolve21(destDir, localVideoName));
35346
35449
  }
35347
35450
  } else {
35348
35451
  if (interactive) {
@@ -35352,10 +35455,10 @@ async function handleVideoFile(videoPath, destDir, interactive) {
35352
35455
  console.log(c.warn("ffmpeg not installed \u2014 cannot transcode. Copying original."));
35353
35456
  console.log(c.dim("Install: ") + c.accent("brew install ffmpeg"));
35354
35457
  }
35355
- copyFileSync3(videoPath, resolve20(destDir, localVideoName));
35458
+ copyFileSync3(videoPath, resolve21(destDir, localVideoName));
35356
35459
  }
35357
35460
  } else {
35358
- copyFileSync3(videoPath, resolve20(destDir, localVideoName));
35461
+ copyFileSync3(videoPath, resolve21(destDir, localVideoName));
35359
35462
  }
35360
35463
  return { meta, localVideoName };
35361
35464
  }
@@ -35369,7 +35472,7 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
35369
35472
  }
35370
35473
  patchVideoSrc(destDir, localVideoName, durationSeconds);
35371
35474
  writeFileSync13(
35372
- resolve20(destDir, "meta.json"),
35475
+ resolve21(destDir, "meta.json"),
35373
35476
  JSON.stringify(
35374
35477
  {
35375
35478
  id: name,
@@ -35381,7 +35484,7 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
35381
35484
  ),
35382
35485
  "utf-8"
35383
35486
  );
35384
- if (!existsSync33(resolve20(destDir, "hyperframes.json"))) {
35487
+ if (!existsSync33(resolve21(destDir, "hyperframes.json"))) {
35385
35488
  const { writeProjectConfig: writeProjectConfig2, DEFAULT_PROJECT_CONFIG: DEFAULT_PROJECT_CONFIG2 } = await Promise.resolve().then(() => (init_projectConfig(), projectConfig_exports));
35386
35489
  writeProjectConfig2(destDir, DEFAULT_PROJECT_CONFIG2);
35387
35490
  }
@@ -35389,7 +35492,7 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
35389
35492
  if (existsSync33(sharedDir)) {
35390
35493
  for (const entry of readdirSync12(sharedDir, { withFileTypes: true })) {
35391
35494
  const src = join36(sharedDir, entry.name);
35392
- const dest = resolve20(destDir, entry.name);
35495
+ const dest = resolve21(destDir, entry.name);
35393
35496
  if (entry.isFile() || entry.isSymbolicLink()) {
35394
35497
  copyFileSync3(src, dest);
35395
35498
  }
@@ -35501,7 +35604,7 @@ var init_init = __esm({
35501
35604
  if (!interactive) {
35502
35605
  const templateId2 = exampleFlag ?? "blank";
35503
35606
  const name2 = args.name ?? "my-video";
35504
- const destDir2 = resolve20(name2);
35607
+ const destDir2 = resolve21(name2);
35505
35608
  if (existsSync33(destDir2) && readdirSync12(destDir2).length > 0) {
35506
35609
  console.error(c.error(`Directory already exists and is not empty: ${name2}`));
35507
35610
  process.exit(1);
@@ -35515,7 +35618,7 @@ var init_init = __esm({
35515
35618
  process.exit(1);
35516
35619
  }
35517
35620
  if (videoFlag) {
35518
- const videoPath = resolve20(videoFlag);
35621
+ const videoPath = resolve21(videoFlag);
35519
35622
  if (!existsSync33(videoPath)) {
35520
35623
  console.error(c.error(`Video file not found: ${videoFlag}`));
35521
35624
  process.exit(1);
@@ -35529,13 +35632,13 @@ var init_init = __esm({
35529
35632
  );
35530
35633
  }
35531
35634
  if (audioFlag) {
35532
- const audioPath = resolve20(audioFlag);
35635
+ const audioPath = resolve21(audioFlag);
35533
35636
  if (!existsSync33(audioPath)) {
35534
35637
  console.error(c.error(`Audio file not found: ${audioFlag}`));
35535
35638
  process.exit(1);
35536
35639
  }
35537
35640
  sourceFilePath2 = audioPath;
35538
- copyFileSync3(audioPath, resolve20(destDir2, basename4(audioPath)));
35641
+ copyFileSync3(audioPath, resolve21(destDir2, basename4(audioPath)));
35539
35642
  console.log(`Audio: ${basename4(audioPath)}`);
35540
35643
  }
35541
35644
  if (sourceFilePath2 && !skipTranscribe) {
@@ -35575,7 +35678,7 @@ var init_init = __esm({
35575
35678
  process.exit(1);
35576
35679
  }
35577
35680
  trackInitTemplate(templateId2);
35578
- const transcriptFile2 = resolve20(destDir2, "transcript.json");
35681
+ const transcriptFile2 = resolve21(destDir2, "transcript.json");
35579
35682
  if (existsSync33(transcriptFile2)) {
35580
35683
  await patchTranscript(destDir2, transcriptFile2);
35581
35684
  }
@@ -35627,7 +35730,7 @@ var init_init = __esm({
35627
35730
  }
35628
35731
  name = nameResult;
35629
35732
  }
35630
- const destDir = resolve20(name);
35733
+ const destDir = resolve21(name);
35631
35734
  if (existsSync33(destDir) && readdirSync12(destDir).length > 0) {
35632
35735
  const overwrite = await Rt({
35633
35736
  message: `Directory ${c.accent(name)} already exists and is not empty. Overwrite?`,
@@ -35642,7 +35745,7 @@ var init_init = __esm({
35642
35745
  let sourceFilePath;
35643
35746
  let videoDuration;
35644
35747
  if (videoFlag) {
35645
- const videoPath = resolve20(videoFlag);
35748
+ const videoPath = resolve21(videoFlag);
35646
35749
  if (!existsSync33(videoPath)) {
35647
35750
  R2.error(`File not found: ${videoFlag}`);
35648
35751
  Nt("Setup cancelled.");
@@ -35654,7 +35757,7 @@ var init_init = __esm({
35654
35757
  localVideoName = result.localVideoName;
35655
35758
  videoDuration = result.meta.durationSeconds;
35656
35759
  } else if (audioFlag) {
35657
- const audioPath = resolve20(audioFlag);
35760
+ const audioPath = resolve21(audioFlag);
35658
35761
  if (!existsSync33(audioPath)) {
35659
35762
  R2.error(`File not found: ${audioFlag}`);
35660
35763
  Nt("Setup cancelled.");
@@ -35662,7 +35765,7 @@ var init_init = __esm({
35662
35765
  }
35663
35766
  mkdirSync20(destDir, { recursive: true });
35664
35767
  sourceFilePath = audioPath;
35665
- copyFileSync3(audioPath, resolve20(destDir, basename4(audioPath)));
35768
+ copyFileSync3(audioPath, resolve21(destDir, basename4(audioPath)));
35666
35769
  R2.info(`Audio copied to ${c.accent(basename4(audioPath))}`);
35667
35770
  }
35668
35771
  if (sourceFilePath) {
@@ -35747,7 +35850,7 @@ ${c.dim("Use --example blank for offline use.")}`
35747
35850
  process.exit(1);
35748
35851
  }
35749
35852
  trackInitTemplate(templateId);
35750
- const transcriptFile = resolve20(destDir, "transcript.json");
35853
+ const transcriptFile = resolve21(destDir, "transcript.json");
35751
35854
  if (existsSync33(transcriptFile)) {
35752
35855
  await patchTranscript(destDir, transcriptFile);
35753
35856
  }
@@ -35835,7 +35938,7 @@ __export(add_exports, {
35835
35938
  runAdd: () => runAdd
35836
35939
  });
35837
35940
  import { existsSync as existsSync34 } from "fs";
35838
- import { resolve as resolve21, relative as relative3 } from "path";
35941
+ import { resolve as resolve22, relative as relative3 } from "path";
35839
35942
  function remapTarget(item, originalTarget, paths) {
35840
35943
  if (item.type === "hyperframes:block") {
35841
35944
  const blocksDir = paths.blocks.replace(/\/+$/, "");
@@ -35858,10 +35961,10 @@ function buildSnippet(item, relativeTarget) {
35858
35961
  return "";
35859
35962
  }
35860
35963
  async function runAdd(opts) {
35861
- const projectDir = resolve21(opts.projectDir);
35964
+ const projectDir = resolve22(opts.projectDir);
35862
35965
  let config = loadProjectConfig(projectDir);
35863
35966
  const hasConfig = existsSync34(projectConfigPath(projectDir));
35864
- if (!hasConfig && existsSync34(resolve21(projectDir, "index.html"))) {
35967
+ if (!hasConfig && existsSync34(resolve22(projectDir, "index.html"))) {
35865
35968
  writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
35866
35969
  config = DEFAULT_PROJECT_CONFIG;
35867
35970
  }
@@ -35957,7 +36060,7 @@ var init_add = __esm({
35957
36060
  }
35958
36061
  },
35959
36062
  async run({ args }) {
35960
- const projectDir = resolve21(args.dir ?? process.cwd());
36063
+ const projectDir = resolve22(args.dir ?? process.cwd());
35961
36064
  const json = args.json === true;
35962
36065
  const skipClipboard = args["no-clipboard"] === true;
35963
36066
  const hasConfigBefore = existsSync34(projectConfigPath(projectDir));
@@ -36005,7 +36108,7 @@ __export(catalog_exports, {
36005
36108
  default: () => catalog_default,
36006
36109
  examples: () => examples4
36007
36110
  });
36008
- import { resolve as resolve22 } from "path";
36111
+ import { resolve as resolve23 } from "path";
36009
36112
  var examples4, catalog_default;
36010
36113
  var init_catalog = __esm({
36011
36114
  "src/commands/catalog.ts"() {
@@ -36049,7 +36152,7 @@ var init_catalog = __esm({
36049
36152
  async run({ args }) {
36050
36153
  const json = args.json === true;
36051
36154
  const interactive = args["human-friendly"] === true;
36052
- const dir = resolve22(process.cwd());
36155
+ const dir = resolve23(process.cwd());
36053
36156
  const config = loadProjectConfig(dir) ?? DEFAULT_PROJECT_CONFIG;
36054
36157
  let typeFilter;
36055
36158
  if (args.type === "block") typeFilter = "hyperframes:block";
@@ -36174,11 +36277,11 @@ var init_format = __esm({
36174
36277
 
36175
36278
  // src/utils/project.ts
36176
36279
  import { existsSync as existsSync35, statSync as statSync11 } from "fs";
36177
- import { resolve as resolve23, basename as basename5 } from "path";
36280
+ import { resolve as resolve24, basename as basename5 } from "path";
36178
36281
  function resolveProject(dirArg) {
36179
- const dir = resolve23(dirArg ?? ".");
36282
+ const dir = resolve24(dirArg ?? ".");
36180
36283
  const name = basename5(dir);
36181
- const indexPath = resolve23(dir, "index.html");
36284
+ const indexPath = resolve24(dir, "index.html");
36182
36285
  if (!existsSync35(dir) || !statSync11(dir).isDirectory()) {
36183
36286
  errorBox("Not a directory: " + dir);
36184
36287
  process.exit(1);
@@ -36207,7 +36310,7 @@ __export(play_exports, {
36207
36310
  examples: () => examples5
36208
36311
  });
36209
36312
  import { existsSync as existsSync36, readFileSync as readFileSync25 } from "fs";
36210
- import { resolve as resolve24, dirname as dirname14 } from "path";
36313
+ import { resolve as resolve25, dirname as dirname14 } from "path";
36211
36314
  function commandDir() {
36212
36315
  return dirname14(new URL(import.meta.url).pathname);
36213
36316
  }
@@ -36215,10 +36318,10 @@ function resolveRuntimePath2() {
36215
36318
  const d = commandDir();
36216
36319
  const candidates = [
36217
36320
  // Bundled with CLI dist
36218
- resolve24(d, "hyperframe-runtime.js"),
36219
- resolve24(d, "..", "hyperframe-runtime.js"),
36321
+ resolve25(d, "hyperframe-runtime.js"),
36322
+ resolve25(d, "..", "hyperframe-runtime.js"),
36220
36323
  // Monorepo dev: commands/ → src/ → cli/ → packages/ then into core/dist/
36221
- resolve24(d, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
36324
+ resolve25(d, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
36222
36325
  ];
36223
36326
  for (const p of candidates) {
36224
36327
  if (existsSync36(p)) return p;
@@ -36229,10 +36332,10 @@ function resolvePlayerPath() {
36229
36332
  const d = commandDir();
36230
36333
  const candidates = [
36231
36334
  // Monorepo dev: commands/ → src/ → cli/ → packages/ then into player/dist/
36232
- resolve24(d, "..", "..", "..", "player", "dist", "hyperframes-player.global.js"),
36335
+ resolve25(d, "..", "..", "..", "player", "dist", "hyperframes-player.global.js"),
36233
36336
  // Bundled with CLI dist
36234
- resolve24(d, "hyperframes-player.global.js"),
36235
- resolve24(d, "..", "hyperframes-player.global.js")
36337
+ resolve25(d, "hyperframes-player.global.js"),
36338
+ resolve25(d, "..", "hyperframes-player.global.js")
36236
36339
  ];
36237
36340
  for (const p of candidates) {
36238
36341
  if (existsSync36(p)) return p;
@@ -36335,7 +36438,7 @@ var init_play = __esm({
36335
36438
  });
36336
36439
  app.get("/composition/*", async (ctx) => {
36337
36440
  const reqPath = ctx.req.path.replace("/composition/", "");
36338
- const filePath = resolve24(project.dir, reqPath);
36441
+ const filePath = resolve25(project.dir, reqPath);
36339
36442
  if (!filePath.startsWith(project.dir)) return ctx.text("Forbidden", 403);
36340
36443
  if (!existsSync36(filePath)) return ctx.text("Not found", 404);
36341
36444
  const content = readFileSync25(filePath, "utf-8");
@@ -36496,7 +36599,7 @@ __export(publish_exports, {
36496
36599
  default: () => publish_default,
36497
36600
  examples: () => examples6
36498
36601
  });
36499
- import { basename as basename7, resolve as resolve25 } from "path";
36602
+ import { basename as basename7, resolve as resolve26 } from "path";
36500
36603
  import { existsSync as existsSync37 } from "fs";
36501
36604
  import { join as join38 } from "path";
36502
36605
  var examples6, publish_default;
@@ -36530,7 +36633,7 @@ var init_publish = __esm({
36530
36633
  },
36531
36634
  async run({ args }) {
36532
36635
  const rawArg = args.dir;
36533
- const dir = resolve25(rawArg ?? ".");
36636
+ const dir = resolve26(rawArg ?? ".");
36534
36637
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
36535
36638
  const projectName = isImplicitCwd ? basename7(process.env["PWD"] ?? dir) : basename7(dir);
36536
36639
  const indexPath = join38(dir, "index.html");
@@ -36707,7 +36810,7 @@ __export(render_exports, {
36707
36810
  });
36708
36811
  import { mkdirSync as mkdirSync21, readFileSync as readFileSync27, statSync as statSync13, writeFileSync as writeFileSync14, rmSync as rmSync8 } from "fs";
36709
36812
  import { cpus as cpus3, freemem as freemem3, tmpdir as tmpdir3 } from "os";
36710
- import { resolve as resolve26, dirname as dirname15, join as join39, basename as basename8 } from "path";
36813
+ import { resolve as resolve27, dirname as dirname15, join as join39, basename as basename8 } from "path";
36711
36814
  import { execFileSync as execFileSync5, spawn as spawn10 } from "child_process";
36712
36815
  function defaultWorkerCount() {
36713
36816
  return Math.max(1, Math.min(Math.floor(CPU_CORE_COUNT * 3 / 4), 8));
@@ -36716,8 +36819,8 @@ function dockerImageTag(version) {
36716
36819
  return `${DOCKER_IMAGE_PREFIX}:${version}`;
36717
36820
  }
36718
36821
  function resolveDockerfilePath() {
36719
- const builtPath = resolve26(__dirname, "docker", "Dockerfile.render");
36720
- const devPath = resolve26(__dirname, "..", "src", "docker", "Dockerfile.render");
36822
+ const builtPath = resolve27(__dirname, "docker", "Dockerfile.render");
36823
+ const devPath = resolve27(__dirname, "..", "src", "docker", "Dockerfile.render");
36721
36824
  for (const p of [builtPath, devPath]) {
36722
36825
  try {
36723
36826
  statSync13(p);
@@ -36794,8 +36897,8 @@ async function renderDocker(projectDir, outputPath, options) {
36794
36897
  const outputFilename = basename8(outputPath);
36795
36898
  const dockerArgs = buildDockerRunArgs({
36796
36899
  imageTag,
36797
- projectDir: resolve26(projectDir),
36798
- outputDir: resolve26(outputDir),
36900
+ projectDir: resolve27(projectDir),
36901
+ outputDir: resolve27(outputDir),
36799
36902
  outputFilename,
36800
36903
  options: {
36801
36904
  fps: options.fps,
@@ -37070,12 +37173,12 @@ var init_render2 = __esm({
37070
37173
  }
37071
37174
  process.env.PRODUCER_MAX_CONCURRENT_RENDERS = String(parsed);
37072
37175
  }
37073
- const rendersDir = resolve26("renders");
37176
+ const rendersDir = resolve27("renders");
37074
37177
  const ext = FORMAT_EXT[format] ?? ".mp4";
37075
37178
  const now = /* @__PURE__ */ new Date();
37076
37179
  const datePart = now.toISOString().slice(0, 10);
37077
37180
  const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
37078
- const outputPath = args.output ? resolve26(args.output) : join39(rendersDir, `${project.name}_${datePart}_${timePart}${ext}`);
37181
+ const outputPath = args.output ? resolve27(args.output) : join39(rendersDir, `${project.name}_${datePart}_${timePart}${ext}`);
37079
37182
  mkdirSync21(dirname15(outputPath), { recursive: true });
37080
37183
  const useDocker = args.docker ?? false;
37081
37184
  const useGpu = args.gpu ?? false;
@@ -37517,7 +37620,7 @@ __export(compositions_exports, {
37517
37620
  examples: () => examples10
37518
37621
  });
37519
37622
  import { existsSync as existsSync38, readFileSync as readFileSync29 } from "fs";
37520
- import { resolve as resolve27, dirname as dirname16 } from "path";
37623
+ import { resolve as resolve28, dirname as dirname16 } from "path";
37521
37624
  function parseCompositions(html, baseDir) {
37522
37625
  const parser = new DOMParser();
37523
37626
  const doc = parser.parseFromString(html, "text/html");
@@ -37529,7 +37632,7 @@ function parseCompositions(html, baseDir) {
37529
37632
  const height = parseInt(div.getAttribute("data-height") ?? "1080", 10);
37530
37633
  const compositionSrc = div.getAttribute("data-composition-src");
37531
37634
  if (compositionSrc) {
37532
- const subPath = resolve27(baseDir, compositionSrc);
37635
+ const subPath = resolve28(baseDir, compositionSrc);
37533
37636
  if (existsSync38(subPath)) {
37534
37637
  const subHtml = readFileSync29(subPath, "utf-8");
37535
37638
  const subInfo = parseSubComposition(subHtml, id, width, height);
@@ -37664,7 +37767,7 @@ __export(benchmark_exports, {
37664
37767
  examples: () => examples11
37665
37768
  });
37666
37769
  import { existsSync as existsSync39, statSync as statSync15 } from "fs";
37667
- import { resolve as resolve28, join as join41 } from "path";
37770
+ import { resolve as resolve29, join as join41 } from "path";
37668
37771
  var examples11, DEFAULT_CONFIGS, benchmark_default;
37669
37772
  var init_benchmark = __esm({
37670
37773
  "src/commands/benchmark.ts"() {
@@ -37706,7 +37809,7 @@ var init_benchmark = __esm({
37706
37809
  process.exit(1);
37707
37810
  }
37708
37811
  const jsonOutput = args.json ?? false;
37709
- const benchDir = resolve28("renders", ".benchmark");
37812
+ const benchDir = resolve29("renders", ".benchmark");
37710
37813
  let producer = null;
37711
37814
  try {
37712
37815
  producer = await loadProducer();
@@ -37970,7 +38073,7 @@ __export(transcribe_exports2, {
37970
38073
  examples: () => examples13
37971
38074
  });
37972
38075
  import { existsSync as existsSync40, writeFileSync as writeFileSync15 } from "fs";
37973
- import { resolve as resolve29, join as join42, extname as extname8 } from "path";
38076
+ import { resolve as resolve30, join as join42, extname as extname8 } from "path";
37974
38077
  async function importTranscript(inputPath, dir, json) {
37975
38078
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
37976
38079
  const { words, format } = loadTranscript2(inputPath);
@@ -38094,12 +38197,12 @@ var init_transcribe2 = __esm({
38094
38197
  }
38095
38198
  },
38096
38199
  async run({ args }) {
38097
- const inputPath = resolve29(args.input);
38200
+ const inputPath = resolve30(args.input);
38098
38201
  if (!existsSync40(inputPath)) {
38099
38202
  console.error(c.error(`File not found: ${args.input}`));
38100
38203
  process.exit(1);
38101
38204
  }
38102
- const dir = resolve29(args.dir ?? ".");
38205
+ const dir = resolve30(args.dir ?? ".");
38103
38206
  const ext = extname8(inputPath).toLowerCase();
38104
38207
  const isImport = ext === ".json" || ext === ".srt" || ext === ".vtt";
38105
38208
  if (isImport) {
@@ -38389,7 +38492,7 @@ __export(tts_exports, {
38389
38492
  examples: () => examples14
38390
38493
  });
38391
38494
  import { existsSync as existsSync43, readFileSync as readFileSync30 } from "fs";
38392
- import { resolve as resolve30, extname as extname9 } from "path";
38495
+ import { resolve as resolve31, extname as extname9 } from "path";
38393
38496
  function listVoices(json) {
38394
38497
  const rows = BUNDLED_VOICES.map((v) => ({ ...v, defaultLang: inferLangFromVoiceId(v.id) }));
38395
38498
  if (json) {
@@ -38497,7 +38600,7 @@ var init_tts = __esm({
38497
38600
  process.exit(1);
38498
38601
  }
38499
38602
  let text;
38500
- const maybeFile = resolve30(args.input);
38603
+ const maybeFile = resolve31(args.input);
38501
38604
  if (existsSync43(maybeFile) && extname9(maybeFile).toLowerCase() === ".txt") {
38502
38605
  text = readFileSync30(maybeFile, "utf-8").trim();
38503
38606
  if (!text) {
@@ -38511,7 +38614,7 @@ var init_tts = __esm({
38511
38614
  console.error(c.error("No text provided."));
38512
38615
  process.exit(1);
38513
38616
  }
38514
- const output = resolve30(args.output ?? "speech.wav");
38617
+ const output = resolve31(args.output ?? "speech.wav");
38515
38618
  const voice = args.voice ?? DEFAULT_VOICE;
38516
38619
  const speed = args.speed ? parseFloat(args.speed) : 1;
38517
38620
  if (isNaN(speed) || speed <= 0 || speed > 3) {
@@ -38592,13 +38695,13 @@ __export(docs_exports, {
38592
38695
  examples: () => examples15
38593
38696
  });
38594
38697
  import { readFileSync as readFileSync31, existsSync as existsSync44 } from "fs";
38595
- import { resolve as resolve31, dirname as dirname18, join as join45 } from "path";
38698
+ import { resolve as resolve32, dirname as dirname18, join as join45 } from "path";
38596
38699
  import { fileURLToPath as fileURLToPath6 } from "url";
38597
38700
  function docsDir() {
38598
38701
  const thisFile = fileURLToPath6(import.meta.url);
38599
38702
  const dir = dirname18(thisFile);
38600
- const devPath = resolve31(dir, "..", "docs");
38601
- const builtPath = resolve31(dir, "docs");
38703
+ const devPath = resolve32(dir, "..", "docs");
38704
+ const builtPath = resolve32(dir, "docs");
38602
38705
  return existsSync44(devPath) ? devPath : builtPath;
38603
38706
  }
38604
38707
  function formatInlineCode(line) {
@@ -39128,7 +39231,7 @@ __export(validate_exports, {
39128
39231
  default: () => validate_default
39129
39232
  });
39130
39233
  import { existsSync as existsSync45, readFileSync as readFileSync32 } from "fs";
39131
- import { resolve as resolve32, join as join46, dirname as dirname19 } from "path";
39234
+ import { resolve as resolve33, join as join46, dirname as dirname19 } from "path";
39132
39235
  import { fileURLToPath as fileURLToPath7 } from "url";
39133
39236
  async function getCompositionDuration2(page) {
39134
39237
  return page.evaluate(() => {
@@ -39174,7 +39277,7 @@ async function validateInBrowser(projectDir, opts) {
39174
39277
  const { bundleToSingleHtml: bundleToSingleHtml2 } = await Promise.resolve().then(() => (init_compiler(), compiler_exports));
39175
39278
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
39176
39279
  let html = await bundleToSingleHtml2(projectDir);
39177
- const runtimePath = resolve32(
39280
+ const runtimePath = resolve33(
39178
39281
  __dirname2,
39179
39282
  "..",
39180
39283
  "..",
@@ -39395,7 +39498,7 @@ __export(snapshot_exports, {
39395
39498
  import { spawn as spawn11 } from "child_process";
39396
39499
  import { existsSync as existsSync46, mkdtempSync as mkdtempSync2, readFileSync as readFileSync33, mkdirSync as mkdirSync24, rmSync as rmSync9 } from "fs";
39397
39500
  import { tmpdir as tmpdir4 } from "os";
39398
- import { resolve as resolve33, join as join47, dirname as dirname20, relative as relative5, isAbsolute as isAbsolute4 } from "path";
39501
+ import { resolve as resolve34, join as join47, dirname as dirname20, relative as relative5, isAbsolute as isAbsolute4 } from "path";
39399
39502
  import { fileURLToPath as fileURLToPath8 } from "url";
39400
39503
  async function extractVideoFrameToBuffer(videoPath, timeSeconds) {
39401
39504
  const tmp = mkdtempSync2(join47(tmpdir4(), "hf-snapshot-frame-"));
@@ -39451,7 +39554,7 @@ async function captureSnapshots(projectDir, opts) {
39451
39554
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
39452
39555
  const numFrames = opts.frames ?? 5;
39453
39556
  let html = await bundleToSingleHtml2(projectDir);
39454
- const runtimePath = resolve33(
39557
+ const runtimePath = resolve34(
39455
39558
  __dirname3,
39456
39559
  "..",
39457
39560
  "..",
@@ -39476,7 +39579,7 @@ async function captureSnapshots(projectDir, opts) {
39476
39579
  res.end(html);
39477
39580
  return;
39478
39581
  }
39479
- const filePath = resolve33(projectDir, decodeURIComponent(url).replace(/^\//, ""));
39582
+ const filePath = resolve34(projectDir, decodeURIComponent(url).replace(/^\//, ""));
39480
39583
  const rel = relative5(projectDir, filePath);
39481
39584
  if (rel.startsWith("..") || isAbsolute4(rel)) {
39482
39585
  res.writeHead(403);
@@ -39617,7 +39720,7 @@ async function captureSnapshots(projectDir, opts) {
39617
39720
  try {
39618
39721
  const url = new URL(v.src);
39619
39722
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
39620
- const candidate = resolve33(projectDir, decodedPath);
39723
+ const candidate = resolve34(projectDir, decodedPath);
39621
39724
  const rel = relative5(projectDir, candidate);
39622
39725
  if (!rel.startsWith("..") && !isAbsolute4(rel) && existsSync46(candidate)) {
39623
39726
  filePath = candidate;
@@ -40109,7 +40212,7 @@ async function extractHtml(page, opts = {}) {
40109
40212
  (_match, pre, urls, post) => {
40110
40213
  const fixed = urls.replace(/&amp;/g, "&").replace(
40111
40214
  /(^|,\s*)(\/[^\s,]+)/g,
40112
- (_m, sep3, path2) => sep3 + pageOrigin + path2
40215
+ (_m, sep4, path2) => sep4 + pageOrigin + path2
40113
40216
  );
40114
40217
  return pre + fixed + post;
40115
40218
  }
@@ -41206,7 +41309,7 @@ var require_p_retry = __commonJS({
41206
41309
  return error;
41207
41310
  };
41208
41311
  var isNetworkError = (errorMessage) => networkErrorMsgs.includes(errorMessage);
41209
- var pRetry2 = (input, options) => new Promise((resolve36, reject) => {
41312
+ var pRetry2 = (input, options) => new Promise((resolve37, reject) => {
41210
41313
  options = {
41211
41314
  onFailedAttempt: () => {
41212
41315
  },
@@ -41216,7 +41319,7 @@ var require_p_retry = __commonJS({
41216
41319
  const operation = retry.operation(options);
41217
41320
  operation.attempt(async (attemptNumber) => {
41218
41321
  try {
41219
- resolve36(await input(attemptNumber));
41322
+ resolve37(await input(attemptNumber));
41220
41323
  } catch (error) {
41221
41324
  if (!(error instanceof Error)) {
41222
41325
  reject(new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`));
@@ -41752,8 +41855,8 @@ var require_retry3 = __commonJS({
41752
41855
  }
41753
41856
  const delay = getNextRetryDelay(config);
41754
41857
  err.config.retryConfig.currentRetryAttempt += 1;
41755
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve36) => {
41756
- setTimeout(resolve36, delay);
41858
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay) : new Promise((resolve37) => {
41859
+ setTimeout(resolve37, delay);
41757
41860
  });
41758
41861
  if (config.onRetryAttempt) {
41759
41862
  await config.onRetryAttempt(err);
@@ -42661,8 +42764,8 @@ var require_helpers = __commonJS({
42661
42764
  function req(url, opts = {}) {
42662
42765
  const href = typeof url === "string" ? url : url.href;
42663
42766
  const req2 = (href.startsWith("https:") ? https2 : http4).request(url, opts);
42664
- const promise = new Promise((resolve36, reject) => {
42665
- req2.once("response", resolve36).once("error", reject).end();
42767
+ const promise = new Promise((resolve37, reject) => {
42768
+ req2.once("response", resolve37).once("error", reject).end();
42666
42769
  });
42667
42770
  req2.then = promise.then.bind(promise);
42668
42771
  return req2;
@@ -42839,7 +42942,7 @@ var require_parse_proxy_response = __commonJS({
42839
42942
  var debug_1 = __importDefault(require_src2());
42840
42943
  var debug = (0, debug_1.default)("https-proxy-agent:parse-proxy-response");
42841
42944
  function parseProxyResponse(socket) {
42842
- return new Promise((resolve36, reject) => {
42945
+ return new Promise((resolve37, reject) => {
42843
42946
  let buffersLength = 0;
42844
42947
  const buffers = [];
42845
42948
  function read() {
@@ -42905,7 +43008,7 @@ var require_parse_proxy_response = __commonJS({
42905
43008
  }
42906
43009
  debug("got proxy server response: %o %o", firstLine, headers);
42907
43010
  cleanup();
42908
- resolve36({
43011
+ resolve37({
42909
43012
  connect: {
42910
43013
  statusCode,
42911
43014
  statusText,
@@ -43149,7 +43252,7 @@ var require_ponyfill_es2018 = __commonJS({
43149
43252
  return new originalPromise(executor);
43150
43253
  }
43151
43254
  function promiseResolvedWith(value) {
43152
- return newPromise((resolve36) => resolve36(value));
43255
+ return newPromise((resolve37) => resolve37(value));
43153
43256
  }
43154
43257
  function promiseRejectedWith(reason) {
43155
43258
  return originalPromiseReject(reason);
@@ -43319,8 +43422,8 @@ var require_ponyfill_es2018 = __commonJS({
43319
43422
  return new TypeError("Cannot " + name + " a stream using a released reader");
43320
43423
  }
43321
43424
  function defaultReaderClosedPromiseInitialize(reader) {
43322
- reader._closedPromise = newPromise((resolve36, reject) => {
43323
- reader._closedPromise_resolve = resolve36;
43425
+ reader._closedPromise = newPromise((resolve37, reject) => {
43426
+ reader._closedPromise_resolve = resolve37;
43324
43427
  reader._closedPromise_reject = reject;
43325
43428
  });
43326
43429
  }
@@ -43494,8 +43597,8 @@ var require_ponyfill_es2018 = __commonJS({
43494
43597
  }
43495
43598
  let resolvePromise;
43496
43599
  let rejectPromise;
43497
- const promise = newPromise((resolve36, reject) => {
43498
- resolvePromise = resolve36;
43600
+ const promise = newPromise((resolve37, reject) => {
43601
+ resolvePromise = resolve37;
43499
43602
  rejectPromise = reject;
43500
43603
  });
43501
43604
  const readRequest = {
@@ -43600,8 +43703,8 @@ var require_ponyfill_es2018 = __commonJS({
43600
43703
  const reader = this._reader;
43601
43704
  let resolvePromise;
43602
43705
  let rejectPromise;
43603
- const promise = newPromise((resolve36, reject) => {
43604
- resolvePromise = resolve36;
43706
+ const promise = newPromise((resolve37, reject) => {
43707
+ resolvePromise = resolve37;
43605
43708
  rejectPromise = reject;
43606
43709
  });
43607
43710
  const readRequest = {
@@ -44620,8 +44723,8 @@ var require_ponyfill_es2018 = __commonJS({
44620
44723
  }
44621
44724
  let resolvePromise;
44622
44725
  let rejectPromise;
44623
- const promise = newPromise((resolve36, reject) => {
44624
- resolvePromise = resolve36;
44726
+ const promise = newPromise((resolve37, reject) => {
44727
+ resolvePromise = resolve37;
44625
44728
  rejectPromise = reject;
44626
44729
  });
44627
44730
  const readIntoRequest = {
@@ -44933,10 +45036,10 @@ var require_ponyfill_es2018 = __commonJS({
44933
45036
  wasAlreadyErroring = true;
44934
45037
  reason = void 0;
44935
45038
  }
44936
- const promise = newPromise((resolve36, reject) => {
45039
+ const promise = newPromise((resolve37, reject) => {
44937
45040
  stream._pendingAbortRequest = {
44938
45041
  _promise: void 0,
44939
- _resolve: resolve36,
45042
+ _resolve: resolve37,
44940
45043
  _reject: reject,
44941
45044
  _reason: reason,
44942
45045
  _wasAlreadyErroring: wasAlreadyErroring
@@ -44953,9 +45056,9 @@ var require_ponyfill_es2018 = __commonJS({
44953
45056
  if (state === "closed" || state === "errored") {
44954
45057
  return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`));
44955
45058
  }
44956
- const promise = newPromise((resolve36, reject) => {
45059
+ const promise = newPromise((resolve37, reject) => {
44957
45060
  const closeRequest = {
44958
- _resolve: resolve36,
45061
+ _resolve: resolve37,
44959
45062
  _reject: reject
44960
45063
  };
44961
45064
  stream._closeRequest = closeRequest;
@@ -44968,9 +45071,9 @@ var require_ponyfill_es2018 = __commonJS({
44968
45071
  return promise;
44969
45072
  }
44970
45073
  function WritableStreamAddWriteRequest(stream) {
44971
- const promise = newPromise((resolve36, reject) => {
45074
+ const promise = newPromise((resolve37, reject) => {
44972
45075
  const writeRequest = {
44973
- _resolve: resolve36,
45076
+ _resolve: resolve37,
44974
45077
  _reject: reject
44975
45078
  };
44976
45079
  stream._writeRequests.push(writeRequest);
@@ -45586,8 +45689,8 @@ var require_ponyfill_es2018 = __commonJS({
45586
45689
  return new TypeError("Cannot " + name + " a stream using a released writer");
45587
45690
  }
45588
45691
  function defaultWriterClosedPromiseInitialize(writer) {
45589
- writer._closedPromise = newPromise((resolve36, reject) => {
45590
- writer._closedPromise_resolve = resolve36;
45692
+ writer._closedPromise = newPromise((resolve37, reject) => {
45693
+ writer._closedPromise_resolve = resolve37;
45591
45694
  writer._closedPromise_reject = reject;
45592
45695
  writer._closedPromiseState = "pending";
45593
45696
  });
@@ -45623,8 +45726,8 @@ var require_ponyfill_es2018 = __commonJS({
45623
45726
  writer._closedPromiseState = "resolved";
45624
45727
  }
45625
45728
  function defaultWriterReadyPromiseInitialize(writer) {
45626
- writer._readyPromise = newPromise((resolve36, reject) => {
45627
- writer._readyPromise_resolve = resolve36;
45729
+ writer._readyPromise = newPromise((resolve37, reject) => {
45730
+ writer._readyPromise_resolve = resolve37;
45628
45731
  writer._readyPromise_reject = reject;
45629
45732
  });
45630
45733
  writer._readyPromiseState = "pending";
@@ -45711,7 +45814,7 @@ var require_ponyfill_es2018 = __commonJS({
45711
45814
  source._disturbed = true;
45712
45815
  let shuttingDown = false;
45713
45816
  let currentWrite = promiseResolvedWith(void 0);
45714
- return newPromise((resolve36, reject) => {
45817
+ return newPromise((resolve37, reject) => {
45715
45818
  let abortAlgorithm;
45716
45819
  if (signal !== void 0) {
45717
45820
  abortAlgorithm = () => {
@@ -45856,7 +45959,7 @@ var require_ponyfill_es2018 = __commonJS({
45856
45959
  if (isError) {
45857
45960
  reject(error);
45858
45961
  } else {
45859
- resolve36(void 0);
45962
+ resolve37(void 0);
45860
45963
  }
45861
45964
  return null;
45862
45965
  }
@@ -46137,8 +46240,8 @@ var require_ponyfill_es2018 = __commonJS({
46137
46240
  let branch1;
46138
46241
  let branch2;
46139
46242
  let resolveCancelPromise;
46140
- const cancelPromise = newPromise((resolve36) => {
46141
- resolveCancelPromise = resolve36;
46243
+ const cancelPromise = newPromise((resolve37) => {
46244
+ resolveCancelPromise = resolve37;
46142
46245
  });
46143
46246
  function pullAlgorithm() {
46144
46247
  if (reading) {
@@ -46229,8 +46332,8 @@ var require_ponyfill_es2018 = __commonJS({
46229
46332
  let branch1;
46230
46333
  let branch2;
46231
46334
  let resolveCancelPromise;
46232
- const cancelPromise = newPromise((resolve36) => {
46233
- resolveCancelPromise = resolve36;
46335
+ const cancelPromise = newPromise((resolve37) => {
46336
+ resolveCancelPromise = resolve37;
46234
46337
  });
46235
46338
  function forwardReaderError(thisReader) {
46236
46339
  uponRejection(thisReader._closedPromise, (r2) => {
@@ -47010,8 +47113,8 @@ var require_ponyfill_es2018 = __commonJS({
47010
47113
  const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1);
47011
47114
  const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy);
47012
47115
  let startPromise_resolve;
47013
- const startPromise = newPromise((resolve36) => {
47014
- startPromise_resolve = resolve36;
47116
+ const startPromise = newPromise((resolve37) => {
47117
+ startPromise_resolve = resolve37;
47015
47118
  });
47016
47119
  InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm);
47017
47120
  SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
@@ -47104,8 +47207,8 @@ var require_ponyfill_es2018 = __commonJS({
47104
47207
  if (stream._backpressureChangePromise !== void 0) {
47105
47208
  stream._backpressureChangePromise_resolve();
47106
47209
  }
47107
- stream._backpressureChangePromise = newPromise((resolve36) => {
47108
- stream._backpressureChangePromise_resolve = resolve36;
47210
+ stream._backpressureChangePromise = newPromise((resolve37) => {
47211
+ stream._backpressureChangePromise_resolve = resolve37;
47109
47212
  });
47110
47213
  stream._backpressure = backpressure;
47111
47214
  }
@@ -47273,8 +47376,8 @@ var require_ponyfill_es2018 = __commonJS({
47273
47376
  return controller._finishPromise;
47274
47377
  }
47275
47378
  const readable = stream._readable;
47276
- controller._finishPromise = newPromise((resolve36, reject) => {
47277
- controller._finishPromise_resolve = resolve36;
47379
+ controller._finishPromise = newPromise((resolve37, reject) => {
47380
+ controller._finishPromise_resolve = resolve37;
47278
47381
  controller._finishPromise_reject = reject;
47279
47382
  });
47280
47383
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -47300,8 +47403,8 @@ var require_ponyfill_es2018 = __commonJS({
47300
47403
  return controller._finishPromise;
47301
47404
  }
47302
47405
  const readable = stream._readable;
47303
- controller._finishPromise = newPromise((resolve36, reject) => {
47304
- controller._finishPromise_resolve = resolve36;
47406
+ controller._finishPromise = newPromise((resolve37, reject) => {
47407
+ controller._finishPromise_resolve = resolve37;
47305
47408
  controller._finishPromise_reject = reject;
47306
47409
  });
47307
47410
  const flushPromise = controller._flushAlgorithm();
@@ -47331,8 +47434,8 @@ var require_ponyfill_es2018 = __commonJS({
47331
47434
  return controller._finishPromise;
47332
47435
  }
47333
47436
  const writable = stream._writable;
47334
- controller._finishPromise = newPromise((resolve36, reject) => {
47335
- controller._finishPromise_resolve = resolve36;
47437
+ controller._finishPromise = newPromise((resolve37, reject) => {
47438
+ controller._finishPromise_resolve = resolve37;
47336
47439
  controller._finishPromise_reject = reject;
47337
47440
  });
47338
47441
  const cancelPromise = controller._cancelAlgorithm(reason);
@@ -49301,7 +49404,7 @@ import zlib from "zlib";
49301
49404
  import Stream2, { PassThrough as PassThrough2, pipeline as pump } from "stream";
49302
49405
  import { Buffer as Buffer3 } from "buffer";
49303
49406
  async function fetch3(url, options_) {
49304
- return new Promise((resolve36, reject) => {
49407
+ return new Promise((resolve37, reject) => {
49305
49408
  const request = new Request2(url, options_);
49306
49409
  const { parsedURL, options } = getNodeRequestOptions(request);
49307
49410
  if (!supportedSchemas.has(parsedURL.protocol)) {
@@ -49310,7 +49413,7 @@ async function fetch3(url, options_) {
49310
49413
  if (parsedURL.protocol === "data:") {
49311
49414
  const data = dist_default(request.url);
49312
49415
  const response2 = new Response2(data, { headers: { "Content-Type": data.typeFull } });
49313
- resolve36(response2);
49416
+ resolve37(response2);
49314
49417
  return;
49315
49418
  }
49316
49419
  const send = (parsedURL.protocol === "https:" ? https : http3).request;
@@ -49432,7 +49535,7 @@ async function fetch3(url, options_) {
49432
49535
  if (responseReferrerPolicy) {
49433
49536
  requestOptions.referrerPolicy = responseReferrerPolicy;
49434
49537
  }
49435
- resolve36(fetch3(new Request2(locationURL, requestOptions)));
49538
+ resolve37(fetch3(new Request2(locationURL, requestOptions)));
49436
49539
  finalize();
49437
49540
  return;
49438
49541
  }
@@ -49465,7 +49568,7 @@ async function fetch3(url, options_) {
49465
49568
  const codings = headers.get("Content-Encoding");
49466
49569
  if (!request.compress || request.method === "HEAD" || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
49467
49570
  response = new Response2(body, responseOptions);
49468
- resolve36(response);
49571
+ resolve37(response);
49469
49572
  return;
49470
49573
  }
49471
49574
  const zlibOptions = {
@@ -49479,7 +49582,7 @@ async function fetch3(url, options_) {
49479
49582
  }
49480
49583
  });
49481
49584
  response = new Response2(body, responseOptions);
49482
- resolve36(response);
49585
+ resolve37(response);
49483
49586
  return;
49484
49587
  }
49485
49588
  if (codings === "deflate" || codings === "x-deflate") {
@@ -49503,12 +49606,12 @@ async function fetch3(url, options_) {
49503
49606
  });
49504
49607
  }
49505
49608
  response = new Response2(body, responseOptions);
49506
- resolve36(response);
49609
+ resolve37(response);
49507
49610
  });
49508
49611
  raw.once("end", () => {
49509
49612
  if (!response) {
49510
49613
  response = new Response2(body, responseOptions);
49511
- resolve36(response);
49614
+ resolve37(response);
49512
49615
  }
49513
49616
  });
49514
49617
  return;
@@ -49520,11 +49623,11 @@ async function fetch3(url, options_) {
49520
49623
  }
49521
49624
  });
49522
49625
  response = new Response2(body, responseOptions);
49523
- resolve36(response);
49626
+ resolve37(response);
49524
49627
  return;
49525
49628
  }
49526
49629
  response = new Response2(body, responseOptions);
49527
- resolve36(response);
49630
+ resolve37(response);
49528
49631
  });
49529
49632
  writeToStream(request_, request).catch(reject);
49530
49633
  });
@@ -55606,7 +55709,7 @@ var require_jwtaccess = __commonJS({
55606
55709
  }
55607
55710
  }
55608
55711
  fromStreamAsync(inputStream) {
55609
- return new Promise((resolve36, reject) => {
55712
+ return new Promise((resolve37, reject) => {
55610
55713
  if (!inputStream) {
55611
55714
  reject(new Error("Must pass in a stream containing the service account auth settings."));
55612
55715
  }
@@ -55615,7 +55718,7 @@ var require_jwtaccess = __commonJS({
55615
55718
  try {
55616
55719
  const data = JSON.parse(s2);
55617
55720
  this.fromJSON(data);
55618
- resolve36();
55721
+ resolve37();
55619
55722
  } catch (err) {
55620
55723
  reject(err);
55621
55724
  }
@@ -55854,7 +55957,7 @@ var require_jwtclient = __commonJS({
55854
55957
  }
55855
55958
  }
55856
55959
  fromStreamAsync(inputStream) {
55857
- return new Promise((resolve36, reject) => {
55960
+ return new Promise((resolve37, reject) => {
55858
55961
  if (!inputStream) {
55859
55962
  throw new Error("Must pass in a stream containing the service account auth settings.");
55860
55963
  }
@@ -55863,7 +55966,7 @@ var require_jwtclient = __commonJS({
55863
55966
  try {
55864
55967
  const data = JSON.parse(s2);
55865
55968
  this.fromJSON(data);
55866
- resolve36();
55969
+ resolve37();
55867
55970
  } catch (e2) {
55868
55971
  reject(e2);
55869
55972
  }
@@ -55996,7 +56099,7 @@ var require_refreshclient = __commonJS({
55996
56099
  }
55997
56100
  }
55998
56101
  async fromStreamAsync(inputStream) {
55999
- return new Promise((resolve36, reject) => {
56102
+ return new Promise((resolve37, reject) => {
56000
56103
  if (!inputStream) {
56001
56104
  return reject(new Error("Must pass in a stream containing the user refresh token."));
56002
56105
  }
@@ -56005,7 +56108,7 @@ var require_refreshclient = __commonJS({
56005
56108
  try {
56006
56109
  const data = JSON.parse(s2);
56007
56110
  this.fromJSON(data);
56008
- return resolve36();
56111
+ return resolve37();
56009
56112
  } catch (err) {
56010
56113
  return reject(err);
56011
56114
  }
@@ -57838,7 +57941,7 @@ var require_pluggable_auth_handler = __commonJS({
57838
57941
  * @return A promise that resolves with the executable response.
57839
57942
  */
57840
57943
  retrieveResponseFromExecutable(envMap) {
57841
- return new Promise((resolve36, reject) => {
57944
+ return new Promise((resolve37, reject) => {
57842
57945
  const child = childProcess.spawn(this.commandComponents[0], this.commandComponents.slice(1), {
57843
57946
  env: { ...process.env, ...Object.fromEntries(envMap) }
57844
57947
  });
@@ -57860,7 +57963,7 @@ var require_pluggable_auth_handler = __commonJS({
57860
57963
  try {
57861
57964
  const responseJson = JSON.parse(output);
57862
57965
  const response = new executable_response_1.ExecutableResponse(responseJson);
57863
- return resolve36(response);
57966
+ return resolve37(response);
57864
57967
  } catch (error) {
57865
57968
  if (error instanceof executable_response_1.ExecutableResponseError) {
57866
57969
  return reject(error);
@@ -58763,7 +58866,7 @@ var require_googleauth = __commonJS({
58763
58866
  }
58764
58867
  }
58765
58868
  fromStreamAsync(inputStream, options) {
58766
- return new Promise((resolve36, reject) => {
58869
+ return new Promise((resolve37, reject) => {
58767
58870
  if (!inputStream) {
58768
58871
  throw new Error("Must pass in a stream containing the Google auth settings.");
58769
58872
  }
@@ -58773,7 +58876,7 @@ var require_googleauth = __commonJS({
58773
58876
  try {
58774
58877
  const data = JSON.parse(chunks.join(""));
58775
58878
  const r2 = this._cacheClientFromJSON(data, options);
58776
- return resolve36(r2);
58879
+ return resolve37(r2);
58777
58880
  } catch (err) {
58778
58881
  if (!this.keyFilename)
58779
58882
  throw err;
@@ -58783,7 +58886,7 @@ var require_googleauth = __commonJS({
58783
58886
  });
58784
58887
  this.cachedCredential = client;
58785
58888
  this.setGapicJWTValues(client);
58786
- return resolve36(client);
58889
+ return resolve37(client);
58787
58890
  }
58788
58891
  } catch (err) {
58789
58892
  return reject(err);
@@ -58819,17 +58922,17 @@ var require_googleauth = __commonJS({
58819
58922
  * Run the Google Cloud SDK command that prints the default project ID
58820
58923
  */
58821
58924
  async getDefaultServiceProjectId() {
58822
- return new Promise((resolve36) => {
58925
+ return new Promise((resolve37) => {
58823
58926
  (0, child_process_1.exec)("gcloud config config-helper --format json", (err, stdout2) => {
58824
58927
  if (!err && stdout2) {
58825
58928
  try {
58826
58929
  const projectId = JSON.parse(stdout2).configuration.properties.core.project;
58827
- resolve36(projectId);
58930
+ resolve37(projectId);
58828
58931
  return;
58829
58932
  } catch (e2) {
58830
58933
  }
58831
58934
  }
58832
- resolve36(null);
58935
+ resolve37(null);
58833
58936
  });
58834
58937
  });
58835
58938
  }
@@ -66601,14 +66704,14 @@ function __asyncValues(o) {
66601
66704
  }, i2);
66602
66705
  function verb(n) {
66603
66706
  i2[n] = o[n] && function(v) {
66604
- return new Promise(function(resolve36, reject) {
66605
- v = o[n](v), settle(resolve36, reject, v.done, v.value);
66707
+ return new Promise(function(resolve37, reject) {
66708
+ v = o[n](v), settle(resolve37, reject, v.done, v.value);
66606
66709
  });
66607
66710
  };
66608
66711
  }
66609
- function settle(resolve36, reject, d, v) {
66712
+ function settle(resolve37, reject, d, v) {
66610
66713
  Promise.resolve(v).then(function(v2) {
66611
- resolve36({ value: v2, done: d });
66714
+ resolve37({ value: v2, done: d });
66612
66715
  }, reject);
66613
66716
  }
66614
66717
  }
@@ -77111,8 +77214,8 @@ var init_node4 = __esm({
77111
77214
  const url = `${websocketBaseUrl}/ws/google.ai.generativelanguage.${apiVersion}.GenerativeService.BidiGenerateMusic?key=${apiKey}`;
77112
77215
  let onopenResolve = () => {
77113
77216
  };
77114
- const onopenPromise = new Promise((resolve36) => {
77115
- onopenResolve = resolve36;
77217
+ const onopenPromise = new Promise((resolve37) => {
77218
+ onopenResolve = resolve37;
77116
77219
  });
77117
77220
  const callbacks = params.callbacks;
77118
77221
  const onopenAwaitedCallback = function() {
@@ -77318,8 +77421,8 @@ var init_node4 = __esm({
77318
77421
  }
77319
77422
  let onopenResolve = () => {
77320
77423
  };
77321
- const onopenPromise = new Promise((resolve36) => {
77322
- onopenResolve = resolve36;
77424
+ const onopenPromise = new Promise((resolve37) => {
77425
+ onopenResolve = resolve37;
77323
77426
  });
77324
77427
  const callbacks = params.callbacks;
77325
77428
  const onopenAwaitedCallback = function() {
@@ -79628,7 +79731,7 @@ var init_node4 = __esm({
79628
79731
  return void 0;
79629
79732
  }
79630
79733
  };
79631
- sleep$1 = (ms) => new Promise((resolve36) => setTimeout(resolve36, ms));
79734
+ sleep$1 = (ms) => new Promise((resolve37) => setTimeout(resolve37, ms));
79632
79735
  FallbackEncoder = ({ headers, body }) => {
79633
79736
  return {
79634
79737
  bodyHeaders: {
@@ -80137,8 +80240,8 @@ ${underline2}`);
80137
80240
  };
80138
80241
  APIPromise = class _APIPromise extends Promise {
80139
80242
  constructor(client, responsePromise, parseResponse = defaultParseResponse) {
80140
- super((resolve36) => {
80141
- resolve36(null);
80243
+ super((resolve37) => {
80244
+ resolve37(null);
80142
80245
  });
80143
80246
  this.responsePromise = responsePromise;
80144
80247
  this.parseResponse = parseResponse;
@@ -81699,12 +81802,12 @@ var init_agentPromptGenerator = __esm({
81699
81802
 
81700
81803
  // src/capture/scaffolding.ts
81701
81804
  import { existsSync as existsSync47, writeFileSync as writeFileSync20, readFileSync as readFileSync36 } from "fs";
81702
- import { join as join52, resolve as resolve34 } from "path";
81805
+ import { join as join52, resolve as resolve35 } from "path";
81703
81806
  function loadEnvFile(startDir) {
81704
81807
  try {
81705
- let dir = resolve34(startDir);
81808
+ let dir = resolve35(startDir);
81706
81809
  for (let i2 = 0; i2 < 5; i2++) {
81707
- const envPath = resolve34(dir, ".env");
81810
+ const envPath = resolve35(dir, ".env");
81708
81811
  try {
81709
81812
  const envContent = readFileSync36(envPath, "utf-8");
81710
81813
  for (const line of envContent.split("\n")) {
@@ -81718,7 +81821,7 @@ function loadEnvFile(startDir) {
81718
81821
  }
81719
81822
  break;
81720
81823
  } catch {
81721
- dir = resolve34(dir, "..");
81824
+ dir = resolve35(dir, "..");
81722
81825
  }
81723
81826
  }
81724
81827
  } catch {
@@ -82485,7 +82588,7 @@ __export(capture_exports2, {
82485
82588
  default: () => capture_default,
82486
82589
  examples: () => examples20
82487
82590
  });
82488
- import { resolve as resolve35 } from "path";
82591
+ import { resolve as resolve36 } from "path";
82489
82592
  var examples20, capture_default;
82490
82593
  var init_capture2 = __esm({
82491
82594
  "src/commands/capture.ts"() {
@@ -82544,7 +82647,7 @@ var init_capture2 = __esm({
82544
82647
  const hostname = new URL(url).hostname.replace(/^www\./, "");
82545
82648
  outputName = `captures/${hostname.replace(/\./g, "-")}`;
82546
82649
  }
82547
- const outputDir = resolve35(outputName);
82650
+ const outputDir = resolve36(outputName);
82548
82651
  const isJson = args.json;
82549
82652
  if (!isJson) {
82550
82653
  const { c: c2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
@@ -82691,13 +82794,13 @@ var init_telemetry2 = __esm({
82691
82794
  });
82692
82795
 
82693
82796
  // src/utils/installerDetection.ts
82694
- import { realpathSync } from "fs";
82797
+ import { realpathSync as realpathSync2 } from "fs";
82695
82798
  import { posix as posix2 } from "path";
82696
82799
  function resolveEntry() {
82697
82800
  const entry = process.argv[1];
82698
82801
  if (!entry) return null;
82699
82802
  try {
82700
- return realpathSync(entry);
82803
+ return realpathSync2(entry);
82701
82804
  } catch {
82702
82805
  return entry;
82703
82806
  }