@hyperframes/producer 0.4.3 → 0.4.5

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.
@@ -57866,7 +57866,7 @@ var require_util2 = __commonJS({
57866
57866
  }
57867
57867
  path12 = url.path;
57868
57868
  }
57869
- var isAbsolute2 = exports.isAbsolute(path12);
57869
+ var isAbsolute3 = exports.isAbsolute(path12);
57870
57870
  var parts = path12.split(/\/+/);
57871
57871
  for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
57872
57872
  part = parts[i];
@@ -57886,7 +57886,7 @@ var require_util2 = __commonJS({
57886
57886
  }
57887
57887
  path12 = parts.join("/");
57888
57888
  if (path12 === "") {
57889
- path12 = isAbsolute2 ? "/" : ".";
57889
+ path12 = isAbsolute3 ? "/" : ".";
57890
57890
  }
57891
57891
  if (url) {
57892
57892
  url.path = path12;
@@ -57931,7 +57931,7 @@ var require_util2 = __commonJS({
57931
57931
  exports.isAbsolute = function(aPath) {
57932
57932
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
57933
57933
  };
57934
- function relative2(aRoot, aPath) {
57934
+ function relative3(aRoot, aPath) {
57935
57935
  if (aRoot === "") {
57936
57936
  aRoot = ".";
57937
57937
  }
@@ -57950,7 +57950,7 @@ var require_util2 = __commonJS({
57950
57950
  }
57951
57951
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
57952
57952
  }
57953
- exports.relative = relative2;
57953
+ exports.relative = relative3;
57954
57954
  var supportsNullProto = (function() {
57955
57955
  var obj = /* @__PURE__ */ Object.create(null);
57956
57956
  return !("__proto__" in obj);
@@ -95503,10 +95503,10 @@ function compareDocumentPosition(nodeA, nodeB) {
95503
95503
  function uniqueSort(nodes) {
95504
95504
  nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
95505
95505
  nodes.sort((a, b) => {
95506
- const relative2 = compareDocumentPosition(a, b);
95507
- if (relative2 & DocumentPosition.PRECEDING) {
95506
+ const relative3 = compareDocumentPosition(a, b);
95507
+ if (relative3 & DocumentPosition.PRECEDING) {
95508
95508
  return -1;
95509
- } else if (relative2 & DocumentPosition.FOLLOWING) {
95509
+ } else if (relative3 & DocumentPosition.FOLLOWING) {
95510
95510
  return 1;
95511
95511
  }
95512
95512
  return 0;
@@ -103853,12 +103853,20 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
103853
103853
  config: config2
103854
103854
  };
103855
103855
  }
103856
+ function isFontResourceError(type, text, locationUrl) {
103857
+ if (type !== "error") return false;
103858
+ if (!text.startsWith("Failed to load resource")) return false;
103859
+ return /fonts\.googleapis|fonts\.gstatic|\.(woff2?|ttf|otf)(\b|$)/i.test(
103860
+ `${locationUrl} ${text}`
103861
+ );
103862
+ }
103856
103863
  async function initializeSession(session) {
103857
103864
  const { page, serverUrl } = session;
103858
103865
  page.on("console", (msg) => {
103859
103866
  const type = msg.type();
103860
103867
  const text = msg.text();
103861
- const isFontLoadError = type === "error" && text.startsWith("Failed to load resource") && /fonts\.googleapis|fonts\.gstatic|\.woff2?(\b|$)/i.test(text);
103868
+ const locationUrl = msg.location()?.url ?? "";
103869
+ const isFontLoadError = isFontResourceError(type, text, locationUrl);
103862
103870
  const isResourceLoadError = type === "error" && text.startsWith("Failed to load resource") && !isFontLoadError;
103863
103871
  const prefix = isResourceLoadError ? "[non-blocking]" : type === "error" ? "[Browser:ERROR]" : type === "warn" ? "[Browser:WARN]" : "[Browser]";
103864
103872
  if (!isFontLoadError) {
@@ -105923,7 +105931,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
105923
105931
  }
105924
105932
 
105925
105933
  // src/services/renderOrchestrator.ts
105926
- import { join as join14, dirname as dirname10, resolve as resolve9 } from "path";
105934
+ import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
105927
105935
  import { randomUUID } from "crypto";
105928
105936
  import { freemem as freemem2 } from "os";
105929
105937
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -106283,13 +106291,41 @@ function createFileServer2(options) {
106283
106291
 
106284
106292
  // src/services/htmlCompiler.ts
106285
106293
  import { readFileSync as readFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
106286
- import { join as join13, dirname as dirname9, resolve as resolve8 } from "path";
106294
+ import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
106287
106295
  import postcss from "postcss";
106288
106296
 
106297
+ // src/utils/paths.ts
106298
+ import { resolve as resolve8, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
106299
+ var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve8(new URL(import.meta.url).pathname, "../../..", "renders");
106300
+ function isPathInside(childPath, parentPath) {
106301
+ const absChild = resolve8(childPath);
106302
+ const absParent = resolve8(parentPath);
106303
+ if (absChild === absParent) return true;
106304
+ const rel = relative2(absParent, absChild);
106305
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
106306
+ }
106307
+ function toExternalAssetKey(absPath) {
106308
+ if (absPath.startsWith("hf-ext/")) return absPath;
106309
+ let normalised = absPath.replace(/\\/g, "/");
106310
+ normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
106311
+ normalised = normalised.replace(/^\/\/\?\//, "");
106312
+ normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
106313
+ normalised = normalised.replace(/^\/+/, "");
106314
+ normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
106315
+ return "hf-ext/" + normalised;
106316
+ }
106317
+ function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
106318
+ const absoluteProjectDir = resolve8(projectDir);
106319
+ const projectName = basename2(absoluteProjectDir);
106320
+ const resolvedOutputPath = outputPath ?? join12(rendersDir, `${projectName}.mp4`);
106321
+ const absoluteOutputPath = resolve8(resolvedOutputPath);
106322
+ return { absoluteProjectDir, absoluteOutputPath };
106323
+ }
106324
+
106289
106325
  // src/services/deterministicFonts.ts
106290
106326
  import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
106291
106327
  import { homedir as homedir2 } from "node:os";
106292
- import { join as join12 } from "node:path";
106328
+ import { join as join13 } from "node:path";
106293
106329
 
106294
106330
  // src/services/fontData.generated.ts
106295
106331
  var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
@@ -106567,20 +106603,20 @@ function warnUnresolvedFonts(unresolved) {
106567
106603
  Docs: https://hyperframes.heygen.com/docs/fonts`
106568
106604
  );
106569
106605
  }
106570
- var GOOGLE_FONTS_CACHE_DIR = join12(homedir2(), ".cache", "hyperframes", "fonts");
106606
+ var GOOGLE_FONTS_CACHE_DIR = join13(homedir2(), ".cache", "hyperframes", "fonts");
106571
106607
  var WOFF2_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
106572
106608
  function fontSlug(familyName) {
106573
106609
  return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
106574
106610
  }
106575
106611
  function fontCacheDir(slug) {
106576
- const dir = join12(GOOGLE_FONTS_CACHE_DIR, slug);
106612
+ const dir = join13(GOOGLE_FONTS_CACHE_DIR, slug);
106577
106613
  if (!existsSync13(dir)) {
106578
106614
  mkdirSync8(dir, { recursive: true });
106579
106615
  }
106580
106616
  return dir;
106581
106617
  }
106582
106618
  function cachedWoff2Path(slug, weight, style) {
106583
- return join12(fontCacheDir(slug), `${weight}-${style}.woff2`);
106619
+ return join13(fontCacheDir(slug), `${weight}-${style}.woff2`);
106584
106620
  }
106585
106621
  async function fetchGoogleFont(familyName) {
106586
106622
  const slug = fontSlug(familyName);
@@ -106682,7 +106718,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
106682
106718
  return { duration: 0, resolvedPath: src };
106683
106719
  }
106684
106720
  } else if (!filePath.startsWith("/")) {
106685
- filePath = join13(baseDir, filePath);
106721
+ filePath = join14(baseDir, filePath);
106686
106722
  }
106687
106723
  if (!existsSync14(filePath)) {
106688
106724
  return { duration: 0, resolvedPath: filePath };
@@ -106748,7 +106784,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
106748
106784
  const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
106749
106785
  const absoluteStart = parentOffset + elStart;
106750
106786
  const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
106751
- const filePath = resolve8(projectDir, srcPath);
106787
+ const filePath = resolve9(projectDir, srcPath);
106752
106788
  if (visited.has(filePath)) {
106753
106789
  continue;
106754
106790
  }
@@ -106948,7 +106984,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
106948
106984
  if (!srcPath) continue;
106949
106985
  let compHtml = subCompositions.get(srcPath) || null;
106950
106986
  if (!compHtml) {
106951
- const filePath = resolve8(projectDir, srcPath);
106987
+ const filePath = resolve9(projectDir, srcPath);
106952
106988
  if (existsSync14(filePath)) {
106953
106989
  compHtml = readFileSync8(filePath, "utf-8");
106954
106990
  }
@@ -107161,7 +107197,7 @@ ${safeText}
107161
107197
  return result;
107162
107198
  }
107163
107199
  function collectExternalAssets(html, projectDir) {
107164
- const absProjectDir = resolve8(projectDir);
107200
+ const absProjectDir = resolve9(projectDir);
107165
107201
  const externalAssets = /* @__PURE__ */ new Map();
107166
107202
  const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
107167
107203
  function processPath(rawPath) {
@@ -107169,12 +107205,12 @@ function collectExternalAssets(html, projectDir) {
107169
107205
  if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
107170
107206
  return null;
107171
107207
  }
107172
- const absPath = resolve8(absProjectDir, trimmed);
107173
- if (absPath.startsWith(absProjectDir + "/") || absPath === absProjectDir) {
107208
+ const absPath = resolve9(absProjectDir, trimmed);
107209
+ if (isPathInside(absPath, absProjectDir)) {
107174
107210
  return null;
107175
107211
  }
107176
107212
  if (!existsSync14(absPath)) return null;
107177
- const safeKey = "hf-ext/" + absPath.replace(/^\//, "");
107213
+ const safeKey = toExternalAssetKey(absPath);
107178
107214
  externalAssets.set(safeKey, absPath);
107179
107215
  return safeKey;
107180
107216
  }
@@ -107246,7 +107282,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
107246
107282
  const audios = dedupeElementsById([...mainAudios, ...subAudios]);
107247
107283
  for (const video of videos) {
107248
107284
  if (isHttpUrl(video.src)) continue;
107249
- const videoPath = resolve8(projectDir, video.src);
107285
+ const videoPath = resolve9(projectDir, video.src);
107250
107286
  const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
107251
107287
  Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
107252
107288
  if (analysis.isProblematic) {
@@ -107473,17 +107509,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
107473
107509
  };
107474
107510
  }
107475
107511
  function writeCompiledArtifacts(compiled, workDir, includeSummary) {
107476
- const compileDir = join14(workDir, "compiled");
107512
+ const compileDir = join15(workDir, "compiled");
107477
107513
  mkdirSync10(compileDir, { recursive: true });
107478
- writeFileSync4(join14(compileDir, "index.html"), compiled.html, "utf-8");
107514
+ writeFileSync4(join15(compileDir, "index.html"), compiled.html, "utf-8");
107479
107515
  for (const [srcPath, html] of compiled.subCompositions) {
107480
- const outPath = join14(compileDir, srcPath);
107516
+ const outPath = join15(compileDir, srcPath);
107481
107517
  mkdirSync10(dirname10(outPath), { recursive: true });
107482
107518
  writeFileSync4(outPath, html, "utf-8");
107483
107519
  }
107484
107520
  for (const [relativePath, absolutePath] of compiled.externalAssets) {
107485
- const outPath = resolve9(join14(compileDir, relativePath));
107486
- if (!outPath.startsWith(compileDir + "/")) {
107521
+ const outPath = resolve10(join15(compileDir, relativePath));
107522
+ if (!isPathInside(outPath, compileDir)) {
107487
107523
  console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
107488
107524
  continue;
107489
107525
  }
@@ -107511,7 +107547,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
107511
107547
  })),
107512
107548
  subCompositions: Array.from(compiled.subCompositions.keys())
107513
107549
  };
107514
- writeFileSync4(join14(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
107550
+ writeFileSync4(join15(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
107515
107551
  }
107516
107552
  }
107517
107553
  function createRenderJob(config2) {
@@ -107555,9 +107591,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
107555
107591
  }
107556
107592
  async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
107557
107593
  const moduleDir = dirname10(fileURLToPath3(import.meta.url));
107558
- const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve9(process.env.PRODUCER_RENDERS_DIR, "..") : resolve9(moduleDir, "../..");
107559
- const debugDir = join14(producerRoot, ".debug");
107560
- const workDir = job.config.debug ? join14(debugDir, job.id) : join14(dirname10(outputPath), `work-${job.id}`);
107594
+ const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve10(process.env.PRODUCER_RENDERS_DIR, "..") : resolve10(moduleDir, "../..");
107595
+ const debugDir = join15(producerRoot, ".debug");
107596
+ const workDir = job.config.debug ? join15(debugDir, job.id) : join15(dirname10(outputPath), `work-${job.id}`);
107561
107597
  const pipelineStart = Date.now();
107562
107598
  const log = job.config.logger ?? defaultLogger;
107563
107599
  let fileServer = null;
@@ -107565,7 +107601,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107565
107601
  let lastBrowserConsole = [];
107566
107602
  let restoreLogger = null;
107567
107603
  const perfStages = {};
107568
- const perfOutputPath = join14(workDir, "perf-summary.json");
107604
+ const perfOutputPath = join15(workDir, "perf-summary.json");
107569
107605
  const cfg = { ...job.config.producerConfig ?? resolveConfig() };
107570
107606
  const outputFormat = job.config.format ?? "mp4";
107571
107607
  const isWebm = outputFormat === "webm";
@@ -107587,19 +107623,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107587
107623
  assertNotAborted();
107588
107624
  if (!existsSync15(workDir)) mkdirSync10(workDir, { recursive: true });
107589
107625
  if (job.config.debug) {
107590
- const logPath = join14(workDir, "render.log");
107626
+ const logPath = join15(workDir, "render.log");
107591
107627
  restoreLogger = installDebugLogger(logPath, log);
107592
107628
  }
107593
107629
  const entryFile = job.config.entryFile || "index.html";
107594
- let htmlPath = join14(projectDir, entryFile);
107630
+ let htmlPath = join15(projectDir, entryFile);
107595
107631
  if (!existsSync15(htmlPath)) {
107596
107632
  throw new Error(`Entry file not found: ${htmlPath}`);
107597
107633
  }
107598
107634
  assertNotAborted();
107599
107635
  const rawEntry = readFileSync9(htmlPath, "utf-8");
107600
107636
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
107601
- const wrapperPath = join14(workDir, "standalone-entry.html");
107602
- const projectIndexPath = join14(projectDir, "index.html");
107637
+ const wrapperPath = join15(workDir, "standalone-entry.html");
107638
+ const projectIndexPath = join15(projectDir, "index.html");
107603
107639
  if (!existsSync15(projectIndexPath)) {
107604
107640
  throw new Error(
107605
107641
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
@@ -107623,7 +107659,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107623
107659
  const stage1Start = Date.now();
107624
107660
  updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
107625
107661
  const compileStart = Date.now();
107626
- let compiled = await compileForRender(projectDir, htmlPath, join14(workDir, "downloads"));
107662
+ let compiled = await compileForRender(projectDir, htmlPath, join15(workDir, "downloads"));
107627
107663
  assertNotAborted();
107628
107664
  perfStages.compileOnlyMs = Date.now() - compileStart;
107629
107665
  writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
@@ -107652,7 +107688,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107652
107688
  reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
107653
107689
  fileServer = await createFileServer2({
107654
107690
  projectDir,
107655
- compiledDir: join14(workDir, "compiled"),
107691
+ compiledDir: join15(workDir, "compiled"),
107656
107692
  port: 0
107657
107693
  });
107658
107694
  assertNotAborted();
@@ -107665,7 +107701,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107665
107701
  };
107666
107702
  probeSession = await createCaptureSession(
107667
107703
  fileServer.url,
107668
- join14(workDir, "probe"),
107704
+ join15(workDir, "probe"),
107669
107705
  captureOpts,
107670
107706
  null,
107671
107707
  cfg
@@ -107697,7 +107733,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107697
107733
  compiled,
107698
107734
  resolutions,
107699
107735
  projectDir,
107700
- join14(workDir, "downloads")
107736
+ join15(workDir, "downloads")
107701
107737
  );
107702
107738
  assertNotAborted();
107703
107739
  composition.videos = compiled.videos;
@@ -107832,12 +107868,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107832
107868
  const stage2Start = Date.now();
107833
107869
  updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
107834
107870
  let frameLookup = null;
107835
- const compiledDir = join14(workDir, "compiled");
107871
+ const compiledDir = join15(workDir, "compiled");
107836
107872
  if (composition.videos.length > 0) {
107837
107873
  const extractionResult = await extractAllVideoFrames(
107838
107874
  composition.videos,
107839
107875
  projectDir,
107840
- { fps: job.config.fps, outputDir: join14(workDir, "video-frames") },
107876
+ { fps: job.config.fps, outputDir: join15(workDir, "video-frames") },
107841
107877
  abortSignal,
107842
107878
  void 0,
107843
107879
  compiledDir
@@ -107871,13 +107907,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107871
107907
  }
107872
107908
  const stage3Start = Date.now();
107873
107909
  updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
107874
- const audioOutputPath = join14(workDir, "audio.aac");
107910
+ const audioOutputPath = join15(workDir, "audio.aac");
107875
107911
  let hasAudio = false;
107876
107912
  if (composition.audios.length > 0) {
107877
107913
  const audioResult = await processCompositionAudio(
107878
107914
  composition.audios,
107879
107915
  projectDir,
107880
- join14(workDir, "audio-work"),
107916
+ join15(workDir, "audio-work"),
107881
107917
  audioOutputPath,
107882
107918
  job.duration,
107883
107919
  abortSignal,
@@ -107895,12 +107931,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107895
107931
  if (!fileServer) {
107896
107932
  fileServer = await createFileServer2({
107897
107933
  projectDir,
107898
- compiledDir: join14(workDir, "compiled"),
107934
+ compiledDir: join15(workDir, "compiled"),
107899
107935
  port: 0
107900
107936
  });
107901
107937
  assertNotAborted();
107902
107938
  }
107903
- const framesDir = join14(workDir, "captured-frames");
107939
+ const framesDir = join15(workDir, "captured-frames");
107904
107940
  if (!existsSync15(framesDir)) mkdirSync10(framesDir, { recursive: true });
107905
107941
  const captureOptions = {
107906
107942
  width,
@@ -107912,7 +107948,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107912
107948
  const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
107913
107949
  const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
107914
107950
  const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
107915
- const videoOnlyPath = join14(workDir, `video-only${videoExt}`);
107951
+ const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
107916
107952
  const preset = getEncoderPreset(job.config.quality, outputFormat);
107917
107953
  const effectiveQuality = job.config.crf ?? preset.quality;
107918
107954
  const effectiveBitrate = job.config.videoBitrate;
@@ -108188,7 +108224,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
108188
108224
  }
108189
108225
  if (job.config.debug) {
108190
108226
  if (existsSync15(outputPath)) {
108191
- const debugOutput = join14(workDir, `output${videoExt}`);
108227
+ const debugOutput = join15(workDir, `output${videoExt}`);
108192
108228
  copyFileSync2(outputPath, debugOutput);
108193
108229
  }
108194
108230
  } else {
@@ -108283,7 +108319,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
108283
108319
 
108284
108320
  // src/services/hyperframeLint.ts
108285
108321
  import { existsSync as existsSync16, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
108286
- import { resolve as resolve10, join as join15 } from "node:path";
108322
+ import { resolve as resolve11, join as join16 } from "node:path";
108287
108323
  function isStringRecord(value) {
108288
108324
  if (!value || typeof value !== "object" || Array.isArray(value)) {
108289
108325
  return false;
@@ -108310,7 +108346,7 @@ function pickEntryFile(files, preferredEntryFile) {
108310
108346
  return null;
108311
108347
  }
108312
108348
  function readProjectEntryFile(projectDir, preferredEntryFile) {
108313
- const absProjectDir = resolve10(projectDir);
108349
+ const absProjectDir = resolve11(projectDir);
108314
108350
  if (!existsSync16(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
108315
108351
  return { error: `Project directory not found: ${absProjectDir}` };
108316
108352
  }
@@ -108318,7 +108354,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
108318
108354
  (value) => typeof value === "string" && value.trim().length > 0
108319
108355
  );
108320
108356
  for (const entryFile of entryCandidates) {
108321
- const absoluteEntryPath = resolve10(absProjectDir, entryFile);
108357
+ const absoluteEntryPath = resolve11(absProjectDir, entryFile);
108322
108358
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
108323
108359
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
108324
108360
  }
@@ -108331,7 +108367,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
108331
108367
  }
108332
108368
  }
108333
108369
  return {
108334
- error: `No HTML entry file found in project directory: ${join15(absProjectDir, preferredEntryFile || "index.html")}`
108370
+ error: `No HTML entry file found in project directory: ${join16(absProjectDir, preferredEntryFile || "index.html")}`
108335
108371
  };
108336
108372
  }
108337
108373
  function prepareHyperframeLintBody(body) {
@@ -108371,17 +108407,6 @@ function runHyperframeLint(prepared) {
108371
108407
  return lintHyperframeHtml(prepared.html, { filePath: prepared.entryFile });
108372
108408
  }
108373
108409
 
108374
- // src/utils/paths.ts
108375
- import { resolve as resolve11, basename as basename2, join as join16 } from "node:path";
108376
- var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
108377
- function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
108378
- const absoluteProjectDir = resolve11(projectDir);
108379
- const projectName = basename2(absoluteProjectDir);
108380
- const resolvedOutputPath = outputPath ?? join16(rendersDir, `${projectName}.mp4`);
108381
- const absoluteOutputPath = resolve11(resolvedOutputPath);
108382
- return { absoluteProjectDir, absoluteOutputPath };
108383
- }
108384
-
108385
108410
  // src/utils/semaphore.ts
108386
108411
  var Semaphore = class {
108387
108412
  constructor(maxConcurrent) {