@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.
package/dist/index.js CHANGED
@@ -57865,7 +57865,7 @@ var require_util2 = __commonJS({
57865
57865
  }
57866
57866
  path12 = url.path;
57867
57867
  }
57868
- var isAbsolute2 = exports.isAbsolute(path12);
57868
+ var isAbsolute3 = exports.isAbsolute(path12);
57869
57869
  var parts = path12.split(/\/+/);
57870
57870
  for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
57871
57871
  part = parts[i];
@@ -57885,7 +57885,7 @@ var require_util2 = __commonJS({
57885
57885
  }
57886
57886
  path12 = parts.join("/");
57887
57887
  if (path12 === "") {
57888
- path12 = isAbsolute2 ? "/" : ".";
57888
+ path12 = isAbsolute3 ? "/" : ".";
57889
57889
  }
57890
57890
  if (url) {
57891
57891
  url.path = path12;
@@ -57930,7 +57930,7 @@ var require_util2 = __commonJS({
57930
57930
  exports.isAbsolute = function(aPath) {
57931
57931
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
57932
57932
  };
57933
- function relative2(aRoot, aPath) {
57933
+ function relative3(aRoot, aPath) {
57934
57934
  if (aRoot === "") {
57935
57935
  aRoot = ".";
57936
57936
  }
@@ -57949,7 +57949,7 @@ var require_util2 = __commonJS({
57949
57949
  }
57950
57950
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
57951
57951
  }
57952
- exports.relative = relative2;
57952
+ exports.relative = relative3;
57953
57953
  var supportsNullProto = (function() {
57954
57954
  var obj = /* @__PURE__ */ Object.create(null);
57955
57955
  return !("__proto__" in obj);
@@ -92714,10 +92714,10 @@ function compareDocumentPosition(nodeA, nodeB) {
92714
92714
  function uniqueSort(nodes) {
92715
92715
  nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
92716
92716
  nodes.sort((a, b) => {
92717
- const relative2 = compareDocumentPosition(a, b);
92718
- if (relative2 & DocumentPosition.PRECEDING) {
92717
+ const relative3 = compareDocumentPosition(a, b);
92718
+ if (relative3 & DocumentPosition.PRECEDING) {
92719
92719
  return -1;
92720
- } else if (relative2 & DocumentPosition.FOLLOWING) {
92720
+ } else if (relative3 & DocumentPosition.FOLLOWING) {
92721
92721
  return 1;
92722
92722
  }
92723
92723
  return 0;
@@ -101064,12 +101064,20 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
101064
101064
  config: config2
101065
101065
  };
101066
101066
  }
101067
+ function isFontResourceError(type, text, locationUrl) {
101068
+ if (type !== "error") return false;
101069
+ if (!text.startsWith("Failed to load resource")) return false;
101070
+ return /fonts\.googleapis|fonts\.gstatic|\.(woff2?|ttf|otf)(\b|$)/i.test(
101071
+ `${locationUrl} ${text}`
101072
+ );
101073
+ }
101067
101074
  async function initializeSession(session) {
101068
101075
  const { page, serverUrl } = session;
101069
101076
  page.on("console", (msg) => {
101070
101077
  const type = msg.type();
101071
101078
  const text = msg.text();
101072
- const isFontLoadError = type === "error" && text.startsWith("Failed to load resource") && /fonts\.googleapis|fonts\.gstatic|\.woff2?(\b|$)/i.test(text);
101079
+ const locationUrl = msg.location()?.url ?? "";
101080
+ const isFontLoadError = isFontResourceError(type, text, locationUrl);
101073
101081
  const isResourceLoadError = type === "error" && text.startsWith("Failed to load resource") && !isFontLoadError;
101074
101082
  const prefix = isResourceLoadError ? "[non-blocking]" : type === "error" ? "[Browser:ERROR]" : type === "warn" ? "[Browser:WARN]" : "[Browser]";
101075
101083
  if (!isFontLoadError) {
@@ -105758,7 +105766,7 @@ var serve = (options, listeningListener) => {
105758
105766
  };
105759
105767
 
105760
105768
  // src/services/renderOrchestrator.ts
105761
- import { join as join14, dirname as dirname10, resolve as resolve9 } from "path";
105769
+ import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
105762
105770
  import { randomUUID } from "crypto";
105763
105771
  import { freemem as freemem2 } from "os";
105764
105772
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -106118,13 +106126,41 @@ function createFileServer2(options) {
106118
106126
 
106119
106127
  // src/services/htmlCompiler.ts
106120
106128
  import { readFileSync as readFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
106121
- import { join as join13, dirname as dirname9, resolve as resolve8 } from "path";
106129
+ import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
106122
106130
  import postcss from "postcss";
106123
106131
 
106132
+ // src/utils/paths.ts
106133
+ import { resolve as resolve8, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
106134
+ var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve8(new URL(import.meta.url).pathname, "../../..", "renders");
106135
+ function isPathInside(childPath, parentPath) {
106136
+ const absChild = resolve8(childPath);
106137
+ const absParent = resolve8(parentPath);
106138
+ if (absChild === absParent) return true;
106139
+ const rel = relative2(absParent, absChild);
106140
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
106141
+ }
106142
+ function toExternalAssetKey(absPath) {
106143
+ if (absPath.startsWith("hf-ext/")) return absPath;
106144
+ let normalised = absPath.replace(/\\/g, "/");
106145
+ normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
106146
+ normalised = normalised.replace(/^\/\/\?\//, "");
106147
+ normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
106148
+ normalised = normalised.replace(/^\/+/, "");
106149
+ normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
106150
+ return "hf-ext/" + normalised;
106151
+ }
106152
+ function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
106153
+ const absoluteProjectDir = resolve8(projectDir);
106154
+ const projectName = basename2(absoluteProjectDir);
106155
+ const resolvedOutputPath = outputPath ?? join12(rendersDir, `${projectName}.mp4`);
106156
+ const absoluteOutputPath = resolve8(resolvedOutputPath);
106157
+ return { absoluteProjectDir, absoluteOutputPath };
106158
+ }
106159
+
106124
106160
  // src/services/deterministicFonts.ts
106125
106161
  import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
106126
106162
  import { homedir as homedir2 } from "node:os";
106127
- import { join as join12 } from "node:path";
106163
+ import { join as join13 } from "node:path";
106128
106164
 
106129
106165
  // src/services/fontData.generated.ts
106130
106166
  var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
@@ -106402,20 +106438,20 @@ function warnUnresolvedFonts(unresolved) {
106402
106438
  Docs: https://hyperframes.heygen.com/docs/fonts`
106403
106439
  );
106404
106440
  }
106405
- var GOOGLE_FONTS_CACHE_DIR = join12(homedir2(), ".cache", "hyperframes", "fonts");
106441
+ var GOOGLE_FONTS_CACHE_DIR = join13(homedir2(), ".cache", "hyperframes", "fonts");
106406
106442
  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";
106407
106443
  function fontSlug(familyName) {
106408
106444
  return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
106409
106445
  }
106410
106446
  function fontCacheDir(slug) {
106411
- const dir = join12(GOOGLE_FONTS_CACHE_DIR, slug);
106447
+ const dir = join13(GOOGLE_FONTS_CACHE_DIR, slug);
106412
106448
  if (!existsSync13(dir)) {
106413
106449
  mkdirSync8(dir, { recursive: true });
106414
106450
  }
106415
106451
  return dir;
106416
106452
  }
106417
106453
  function cachedWoff2Path(slug, weight, style) {
106418
- return join12(fontCacheDir(slug), `${weight}-${style}.woff2`);
106454
+ return join13(fontCacheDir(slug), `${weight}-${style}.woff2`);
106419
106455
  }
106420
106456
  async function fetchGoogleFont(familyName) {
106421
106457
  const slug = fontSlug(familyName);
@@ -106517,7 +106553,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
106517
106553
  return { duration: 0, resolvedPath: src };
106518
106554
  }
106519
106555
  } else if (!filePath.startsWith("/")) {
106520
- filePath = join13(baseDir, filePath);
106556
+ filePath = join14(baseDir, filePath);
106521
106557
  }
106522
106558
  if (!existsSync14(filePath)) {
106523
106559
  return { duration: 0, resolvedPath: filePath };
@@ -106583,7 +106619,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
106583
106619
  const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
106584
106620
  const absoluteStart = parentOffset + elStart;
106585
106621
  const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
106586
- const filePath = resolve8(projectDir, srcPath);
106622
+ const filePath = resolve9(projectDir, srcPath);
106587
106623
  if (visited.has(filePath)) {
106588
106624
  continue;
106589
106625
  }
@@ -106783,7 +106819,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
106783
106819
  if (!srcPath) continue;
106784
106820
  let compHtml = subCompositions.get(srcPath) || null;
106785
106821
  if (!compHtml) {
106786
- const filePath = resolve8(projectDir, srcPath);
106822
+ const filePath = resolve9(projectDir, srcPath);
106787
106823
  if (existsSync14(filePath)) {
106788
106824
  compHtml = readFileSync8(filePath, "utf-8");
106789
106825
  }
@@ -106996,7 +107032,7 @@ ${safeText}
106996
107032
  return result;
106997
107033
  }
106998
107034
  function collectExternalAssets(html, projectDir) {
106999
- const absProjectDir = resolve8(projectDir);
107035
+ const absProjectDir = resolve9(projectDir);
107000
107036
  const externalAssets = /* @__PURE__ */ new Map();
107001
107037
  const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
107002
107038
  function processPath(rawPath) {
@@ -107004,12 +107040,12 @@ function collectExternalAssets(html, projectDir) {
107004
107040
  if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
107005
107041
  return null;
107006
107042
  }
107007
- const absPath = resolve8(absProjectDir, trimmed);
107008
- if (absPath.startsWith(absProjectDir + "/") || absPath === absProjectDir) {
107043
+ const absPath = resolve9(absProjectDir, trimmed);
107044
+ if (isPathInside(absPath, absProjectDir)) {
107009
107045
  return null;
107010
107046
  }
107011
107047
  if (!existsSync14(absPath)) return null;
107012
- const safeKey = "hf-ext/" + absPath.replace(/^\//, "");
107048
+ const safeKey = toExternalAssetKey(absPath);
107013
107049
  externalAssets.set(safeKey, absPath);
107014
107050
  return safeKey;
107015
107051
  }
@@ -107081,7 +107117,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
107081
107117
  const audios = dedupeElementsById([...mainAudios, ...subAudios]);
107082
107118
  for (const video of videos) {
107083
107119
  if (isHttpUrl(video.src)) continue;
107084
- const videoPath = resolve8(projectDir, video.src);
107120
+ const videoPath = resolve9(projectDir, video.src);
107085
107121
  const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
107086
107122
  Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
107087
107123
  if (analysis.isProblematic) {
@@ -107308,17 +107344,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
107308
107344
  };
107309
107345
  }
107310
107346
  function writeCompiledArtifacts(compiled, workDir, includeSummary) {
107311
- const compileDir = join14(workDir, "compiled");
107347
+ const compileDir = join15(workDir, "compiled");
107312
107348
  mkdirSync10(compileDir, { recursive: true });
107313
- writeFileSync4(join14(compileDir, "index.html"), compiled.html, "utf-8");
107349
+ writeFileSync4(join15(compileDir, "index.html"), compiled.html, "utf-8");
107314
107350
  for (const [srcPath, html] of compiled.subCompositions) {
107315
- const outPath = join14(compileDir, srcPath);
107351
+ const outPath = join15(compileDir, srcPath);
107316
107352
  mkdirSync10(dirname10(outPath), { recursive: true });
107317
107353
  writeFileSync4(outPath, html, "utf-8");
107318
107354
  }
107319
107355
  for (const [relativePath, absolutePath] of compiled.externalAssets) {
107320
- const outPath = resolve9(join14(compileDir, relativePath));
107321
- if (!outPath.startsWith(compileDir + "/")) {
107356
+ const outPath = resolve10(join15(compileDir, relativePath));
107357
+ if (!isPathInside(outPath, compileDir)) {
107322
107358
  console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
107323
107359
  continue;
107324
107360
  }
@@ -107346,7 +107382,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
107346
107382
  })),
107347
107383
  subCompositions: Array.from(compiled.subCompositions.keys())
107348
107384
  };
107349
- writeFileSync4(join14(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
107385
+ writeFileSync4(join15(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
107350
107386
  }
107351
107387
  }
107352
107388
  function createRenderJob(config2) {
@@ -107390,9 +107426,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
107390
107426
  }
107391
107427
  async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
107392
107428
  const moduleDir = dirname10(fileURLToPath3(import.meta.url));
107393
- const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve9(process.env.PRODUCER_RENDERS_DIR, "..") : resolve9(moduleDir, "../..");
107394
- const debugDir = join14(producerRoot, ".debug");
107395
- const workDir = job.config.debug ? join14(debugDir, job.id) : join14(dirname10(outputPath), `work-${job.id}`);
107429
+ const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve10(process.env.PRODUCER_RENDERS_DIR, "..") : resolve10(moduleDir, "../..");
107430
+ const debugDir = join15(producerRoot, ".debug");
107431
+ const workDir = job.config.debug ? join15(debugDir, job.id) : join15(dirname10(outputPath), `work-${job.id}`);
107396
107432
  const pipelineStart = Date.now();
107397
107433
  const log = job.config.logger ?? defaultLogger;
107398
107434
  let fileServer = null;
@@ -107400,7 +107436,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107400
107436
  let lastBrowserConsole = [];
107401
107437
  let restoreLogger = null;
107402
107438
  const perfStages = {};
107403
- const perfOutputPath = join14(workDir, "perf-summary.json");
107439
+ const perfOutputPath = join15(workDir, "perf-summary.json");
107404
107440
  const cfg = { ...job.config.producerConfig ?? resolveConfig() };
107405
107441
  const outputFormat = job.config.format ?? "mp4";
107406
107442
  const isWebm = outputFormat === "webm";
@@ -107422,19 +107458,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107422
107458
  assertNotAborted();
107423
107459
  if (!existsSync15(workDir)) mkdirSync10(workDir, { recursive: true });
107424
107460
  if (job.config.debug) {
107425
- const logPath = join14(workDir, "render.log");
107461
+ const logPath = join15(workDir, "render.log");
107426
107462
  restoreLogger = installDebugLogger(logPath, log);
107427
107463
  }
107428
107464
  const entryFile = job.config.entryFile || "index.html";
107429
- let htmlPath = join14(projectDir, entryFile);
107465
+ let htmlPath = join15(projectDir, entryFile);
107430
107466
  if (!existsSync15(htmlPath)) {
107431
107467
  throw new Error(`Entry file not found: ${htmlPath}`);
107432
107468
  }
107433
107469
  assertNotAborted();
107434
107470
  const rawEntry = readFileSync9(htmlPath, "utf-8");
107435
107471
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
107436
- const wrapperPath = join14(workDir, "standalone-entry.html");
107437
- const projectIndexPath = join14(projectDir, "index.html");
107472
+ const wrapperPath = join15(workDir, "standalone-entry.html");
107473
+ const projectIndexPath = join15(projectDir, "index.html");
107438
107474
  if (!existsSync15(projectIndexPath)) {
107439
107475
  throw new Error(
107440
107476
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
@@ -107458,7 +107494,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107458
107494
  const stage1Start = Date.now();
107459
107495
  updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
107460
107496
  const compileStart = Date.now();
107461
- let compiled = await compileForRender(projectDir, htmlPath, join14(workDir, "downloads"));
107497
+ let compiled = await compileForRender(projectDir, htmlPath, join15(workDir, "downloads"));
107462
107498
  assertNotAborted();
107463
107499
  perfStages.compileOnlyMs = Date.now() - compileStart;
107464
107500
  writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
@@ -107487,7 +107523,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107487
107523
  reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
107488
107524
  fileServer = await createFileServer2({
107489
107525
  projectDir,
107490
- compiledDir: join14(workDir, "compiled"),
107526
+ compiledDir: join15(workDir, "compiled"),
107491
107527
  port: 0
107492
107528
  });
107493
107529
  assertNotAborted();
@@ -107500,7 +107536,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107500
107536
  };
107501
107537
  probeSession = await createCaptureSession(
107502
107538
  fileServer.url,
107503
- join14(workDir, "probe"),
107539
+ join15(workDir, "probe"),
107504
107540
  captureOpts,
107505
107541
  null,
107506
107542
  cfg
@@ -107532,7 +107568,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107532
107568
  compiled,
107533
107569
  resolutions,
107534
107570
  projectDir,
107535
- join14(workDir, "downloads")
107571
+ join15(workDir, "downloads")
107536
107572
  );
107537
107573
  assertNotAborted();
107538
107574
  composition.videos = compiled.videos;
@@ -107667,12 +107703,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107667
107703
  const stage2Start = Date.now();
107668
107704
  updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
107669
107705
  let frameLookup = null;
107670
- const compiledDir = join14(workDir, "compiled");
107706
+ const compiledDir = join15(workDir, "compiled");
107671
107707
  if (composition.videos.length > 0) {
107672
107708
  const extractionResult = await extractAllVideoFrames(
107673
107709
  composition.videos,
107674
107710
  projectDir,
107675
- { fps: job.config.fps, outputDir: join14(workDir, "video-frames") },
107711
+ { fps: job.config.fps, outputDir: join15(workDir, "video-frames") },
107676
107712
  abortSignal,
107677
107713
  void 0,
107678
107714
  compiledDir
@@ -107706,13 +107742,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107706
107742
  }
107707
107743
  const stage3Start = Date.now();
107708
107744
  updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
107709
- const audioOutputPath = join14(workDir, "audio.aac");
107745
+ const audioOutputPath = join15(workDir, "audio.aac");
107710
107746
  let hasAudio = false;
107711
107747
  if (composition.audios.length > 0) {
107712
107748
  const audioResult = await processCompositionAudio(
107713
107749
  composition.audios,
107714
107750
  projectDir,
107715
- join14(workDir, "audio-work"),
107751
+ join15(workDir, "audio-work"),
107716
107752
  audioOutputPath,
107717
107753
  job.duration,
107718
107754
  abortSignal,
@@ -107730,12 +107766,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107730
107766
  if (!fileServer) {
107731
107767
  fileServer = await createFileServer2({
107732
107768
  projectDir,
107733
- compiledDir: join14(workDir, "compiled"),
107769
+ compiledDir: join15(workDir, "compiled"),
107734
107770
  port: 0
107735
107771
  });
107736
107772
  assertNotAborted();
107737
107773
  }
107738
- const framesDir = join14(workDir, "captured-frames");
107774
+ const framesDir = join15(workDir, "captured-frames");
107739
107775
  if (!existsSync15(framesDir)) mkdirSync10(framesDir, { recursive: true });
107740
107776
  const captureOptions = {
107741
107777
  width,
@@ -107747,7 +107783,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107747
107783
  const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
107748
107784
  const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
107749
107785
  const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
107750
- const videoOnlyPath = join14(workDir, `video-only${videoExt}`);
107786
+ const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
107751
107787
  const preset = getEncoderPreset(job.config.quality, outputFormat);
107752
107788
  const effectiveQuality = job.config.crf ?? preset.quality;
107753
107789
  const effectiveBitrate = job.config.videoBitrate;
@@ -108023,7 +108059,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
108023
108059
  }
108024
108060
  if (job.config.debug) {
108025
108061
  if (existsSync15(outputPath)) {
108026
- const debugOutput = join14(workDir, `output${videoExt}`);
108062
+ const debugOutput = join15(workDir, `output${videoExt}`);
108027
108063
  copyFileSync2(outputPath, debugOutput);
108028
108064
  }
108029
108065
  } else {
@@ -108282,7 +108318,7 @@ var streamSSE = (c, cb, onError) => {
108282
108318
 
108283
108319
  // src/services/hyperframeLint.ts
108284
108320
  import { existsSync as existsSync16, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
108285
- import { resolve as resolve10, join as join15 } from "node:path";
108321
+ import { resolve as resolve11, join as join16 } from "node:path";
108286
108322
  function isStringRecord(value) {
108287
108323
  if (!value || typeof value !== "object" || Array.isArray(value)) {
108288
108324
  return false;
@@ -108309,7 +108345,7 @@ function pickEntryFile(files, preferredEntryFile) {
108309
108345
  return null;
108310
108346
  }
108311
108347
  function readProjectEntryFile(projectDir, preferredEntryFile) {
108312
- const absProjectDir = resolve10(projectDir);
108348
+ const absProjectDir = resolve11(projectDir);
108313
108349
  if (!existsSync16(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
108314
108350
  return { error: `Project directory not found: ${absProjectDir}` };
108315
108351
  }
@@ -108317,7 +108353,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
108317
108353
  (value) => typeof value === "string" && value.trim().length > 0
108318
108354
  );
108319
108355
  for (const entryFile of entryCandidates) {
108320
- const absoluteEntryPath = resolve10(absProjectDir, entryFile);
108356
+ const absoluteEntryPath = resolve11(absProjectDir, entryFile);
108321
108357
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
108322
108358
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
108323
108359
  }
@@ -108330,7 +108366,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
108330
108366
  }
108331
108367
  }
108332
108368
  return {
108333
- error: `No HTML entry file found in project directory: ${join15(absProjectDir, preferredEntryFile || "index.html")}`
108369
+ error: `No HTML entry file found in project directory: ${join16(absProjectDir, preferredEntryFile || "index.html")}`
108334
108370
  };
108335
108371
  }
108336
108372
  function prepareHyperframeLintBody(body) {
@@ -108370,17 +108406,6 @@ function runHyperframeLint(prepared) {
108370
108406
  return lintHyperframeHtml(prepared.html, { filePath: prepared.entryFile });
108371
108407
  }
108372
108408
 
108373
- // src/utils/paths.ts
108374
- import { resolve as resolve11, basename as basename2, join as join16 } from "node:path";
108375
- var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
108376
- function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
108377
- const absoluteProjectDir = resolve11(projectDir);
108378
- const projectName = basename2(absoluteProjectDir);
108379
- const resolvedOutputPath = outputPath ?? join16(rendersDir, `${projectName}.mp4`);
108380
- const absoluteOutputPath = resolve11(resolvedOutputPath);
108381
- return { absoluteProjectDir, absoluteOutputPath };
108382
- }
108383
-
108384
108409
  // src/utils/semaphore.ts
108385
108410
  var Semaphore = class {
108386
108411
  constructor(maxConcurrent) {