@hyperframes/producer 0.9.14 → 0.9.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/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  // src/services/renderOrchestrator.ts
10
10
  import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
11
11
  import {
12
- existsSync as existsSync18,
12
+ existsSync as existsSync19,
13
13
  mkdirSync as mkdirSync10,
14
14
  readdirSync as readdirSync5,
15
15
  rmSync as rmSync10,
@@ -9986,6 +9986,7 @@ async function planVideoLayerPassthrough(input) {
9986
9986
  }
9987
9987
 
9988
9988
  // src/services/render/stages/audioStage.ts
9989
+ import { existsSync as existsSync14 } from "node:fs";
9989
9990
  import { join as join21 } from "node:path";
9990
9991
  import {
9991
9992
  MIXED_AUDIO_FILENAME,
@@ -10119,8 +10120,9 @@ var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
10119
10120
  var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
10120
10121
  var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
10121
10122
  var MAX_TRUE_PEAK_CORRECTION_PASSES = 3;
10123
+ var gainFilter = (gainDb) => `volume=${gainDb.toFixed(3)}dB`;
10122
10124
  function aacTruePeakCorrectionFilter(targetDurationSeconds, attenuationDb) {
10123
- return `volume=${attenuationDb.toFixed(3)}dB,apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
10125
+ return `${gainFilter(attenuationDb)},apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
10124
10126
  }
10125
10127
  function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, targetDurationSeconds) {
10126
10128
  const delta = targetDurationSeconds - sourceDurationSeconds;
@@ -10158,7 +10160,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
10158
10160
  const probeAudio = input.probeAudioInfo ?? defaultProbeAudioInfo;
10159
10161
  const timeoutMs = input.timeoutMs ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
10160
10162
  const runner = input.runFfmpeg ?? ((args) => defaultRunFfmpeg(args, timeoutMs, input.signal));
10161
- const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal);
10163
+ const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal, input.sourcePath);
10162
10164
  const probeTruePeak = input.probeAudioTruePeakDbfs ?? (input.runFfmpeg || input.encodeAac ? void 0 : (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }));
10163
10165
  const [videoResult, audioResult] = await Promise.allSettled([
10164
10166
  probeVideo(input.videoPath),
@@ -10206,7 +10208,12 @@ async function padOrTrimAudioToVideoFrameCount(input) {
10206
10208
  );
10207
10209
  try {
10208
10210
  for (const step of plan2.steps) {
10209
- const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(input.audioPath, input.outputPath, targetDurationSeconds, step.filter);
10211
+ const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(
10212
+ input.sourcePath ?? input.audioPath,
10213
+ input.outputPath,
10214
+ targetDurationSeconds,
10215
+ step.filter
10216
+ );
10210
10217
  if (!ffmpegResult.success) {
10211
10218
  return {
10212
10219
  success: false,
@@ -10235,6 +10242,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
10235
10242
  if (probeTruePeak) {
10236
10243
  const correction = await enforceAacTruePeak({
10237
10244
  audioPath: input.outputPath,
10245
+ sourcePath: input.sourcePath,
10238
10246
  targetDurationSeconds,
10239
10247
  signal: input.signal,
10240
10248
  probeTruePeak,
@@ -10270,9 +10278,27 @@ async function constrainAacTruePeak(input) {
10270
10278
  targetDurationSeconds: input.targetDurationSeconds,
10271
10279
  signal: input.signal,
10272
10280
  probeTruePeak: input.probeTruePeakDbfs ?? ((audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal })),
10273
- encode: input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal, input.sourcePath)
10281
+ encode: input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal, input.sourcePath),
10282
+ rewriteSource: input.rewriteSource ?? ((sourcePath, outputPath, filter) => defaultRunFfmpeg(
10283
+ ["-i", sourcePath, "-af", filter, "-c:a", "pcm_f32le", "-y", outputPath],
10284
+ timeoutMs,
10285
+ input.signal
10286
+ ))
10274
10287
  });
10275
10288
  }
10289
+ async function cutSource(input, scratchDir, attenuationDb) {
10290
+ if (!input.sourcePath || !input.rewriteSource) return true;
10291
+ const cutPath = join19(scratchDir, "source.wav");
10292
+ try {
10293
+ const result = await input.rewriteSource(input.sourcePath, cutPath, gainFilter(attenuationDb));
10294
+ if (!result.success) throw new Error(result.error);
10295
+ renameWithRetry5(cutPath, input.sourcePath, { copyFallback: true });
10296
+ return true;
10297
+ } catch {
10298
+ removeScratch(input.sourcePath);
10299
+ return false;
10300
+ }
10301
+ }
10276
10302
  async function enforceAacTruePeak(input) {
10277
10303
  let scratchDir;
10278
10304
  try {
@@ -10292,8 +10318,10 @@ async function enforceAacTruePeak(input) {
10292
10318
  }
10293
10319
  if (truePeakDbfs <= AAC_DELIVERY_TRUE_PEAK_DBFS) {
10294
10320
  if (measuredPath !== correctedPath) return { success: true };
10321
+ const sourceCut = await cutSource(input, scratchDir, attenuationDb);
10295
10322
  renameWithRetry5(correctedPath, input.audioPath, { copyFallback: true });
10296
- return { success: true, loweredDb: Number((-attenuationDb).toFixed(2)) };
10323
+ const loweredDb = Number((-attenuationDb).toFixed(2));
10324
+ return sourceCut ? { success: true, loweredDb } : { success: true, loweredDb, sourceStale: true };
10297
10325
  }
10298
10326
  if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
10299
10327
  const headroomDb = AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB * 2 ** pass;
@@ -10303,7 +10331,7 @@ async function enforceAacTruePeak(input) {
10303
10331
  const referenceDbfs = Math.max(truePeakDbfs, (sourcePeakDbfs ?? -Infinity) + attenuationDb);
10304
10332
  attenuationDb += AAC_DELIVERY_TRUE_PEAK_DBFS - headroomDb - referenceDbfs;
10305
10333
  const result = await input.encode(
10306
- input.audioPath,
10334
+ input.sourcePath ?? input.audioPath,
10307
10335
  correctedPath,
10308
10336
  input.targetDurationSeconds,
10309
10337
  aacTruePeakCorrectionFilter(input.targetDurationSeconds, attenuationDb)
@@ -10532,36 +10560,54 @@ async function runAudioStageScoped(input) {
10532
10560
  const stageStart = Date.now();
10533
10561
  const pcmSourcePath = join21(input.workDir, "audio-source.wav");
10534
10562
  const duration = input.totalFrames * input.fps.den / input.fps.num;
10563
+ let deliverySourcePath;
10535
10564
  try {
10536
10565
  const result = await mixAudioForDelivery(input, duration, pcmSourcePath);
10537
10566
  let audioLoweredDb;
10538
10567
  if (result.hasAudio) {
10539
10568
  const guardStart = Date.now();
10540
- const limited = await limitDeliveryPeaks({
10541
- audioPath: result.audioOutputPath,
10542
- sourcePath: pcmSourcePath,
10543
- targetDurationSeconds: duration,
10544
- signal: input.abortSignal,
10545
- timeoutMs: input.ffmpegProcessTimeout,
10546
- warn: (message, details) => input.log?.warn?.(message, details)
10547
- });
10548
- if (!limited.success) throw encoderFailureError("Audio true-peak limit failed", limited);
10549
- const peak = await constrainAacTruePeak({
10550
- audioPath: result.audioOutputPath,
10551
- sourcePath: pcmSourcePath,
10552
- targetDurationSeconds: duration,
10553
- signal: input.abortSignal,
10554
- timeoutMs: input.ffmpegProcessTimeout
10555
- });
10556
- if (!peak.success) throw encoderFailureError("Audio true-peak check failed", peak);
10557
- audioLoweredDb = peak.loweredDb;
10569
+ const guard = await guardDeliveryPeaks(
10570
+ input,
10571
+ result.audioOutputPath,
10572
+ pcmSourcePath,
10573
+ duration
10574
+ );
10575
+ audioLoweredDb = guard.loweredDb;
10558
10576
  input.log?.info("[audio] phases", { ...result.audioPhaseMs, guard: Date.now() - guardStart });
10577
+ if (input.keepDeliverySource && !guard.sourceStale && existsSync14(pcmSourcePath)) {
10578
+ deliverySourcePath = pcmSourcePath;
10579
+ }
10559
10580
  }
10560
- return { ...result, audioLoweredDb, audioProcessMs: Date.now() - stageStart };
10581
+ return {
10582
+ ...result,
10583
+ audioLoweredDb,
10584
+ deliverySourcePath,
10585
+ audioProcessMs: Date.now() - stageStart
10586
+ };
10561
10587
  } finally {
10562
- removeScratch2(pcmSourcePath);
10588
+ if (!deliverySourcePath) removeScratch2(pcmSourcePath);
10563
10589
  }
10564
10590
  }
10591
+ async function guardDeliveryPeaks(input, audioPath, sourcePath, duration) {
10592
+ const limited = await limitDeliveryPeaks({
10593
+ audioPath,
10594
+ sourcePath,
10595
+ targetDurationSeconds: duration,
10596
+ signal: input.abortSignal,
10597
+ timeoutMs: input.ffmpegProcessTimeout,
10598
+ warn: (message, details) => input.log?.warn?.(message, details)
10599
+ });
10600
+ if (!limited.success) throw encoderFailureError("Audio true-peak limit failed", limited);
10601
+ const peak = await constrainAacTruePeak({
10602
+ audioPath,
10603
+ sourcePath,
10604
+ targetDurationSeconds: duration,
10605
+ signal: input.abortSignal,
10606
+ timeoutMs: input.ffmpegProcessTimeout
10607
+ });
10608
+ if (!peak.success) throw encoderFailureError("Audio true-peak check failed", peak);
10609
+ return { loweredDb: peak.loweredDb, sourceStale: peak.sourceStale };
10610
+ }
10565
10611
  async function mixAudioForDelivery(input, duration, pcmSourcePath) {
10566
10612
  const {
10567
10613
  projectDir,
@@ -10656,7 +10702,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
10656
10702
  }
10657
10703
 
10658
10704
  // src/services/render/stages/captureStage.ts
10659
- import { existsSync as existsSync14, readdirSync as readdirSync3, statfsSync as statfsSync2 } from "node:fs";
10705
+ import { existsSync as existsSync15, readdirSync as readdirSync3, statfsSync as statfsSync2 } from "node:fs";
10660
10706
  import { join as join22 } from "node:path";
10661
10707
  import {
10662
10708
  classifyCaptureFailure as classifyCaptureFailure2,
@@ -10727,7 +10773,7 @@ function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis, remed
10727
10773
  }
10728
10774
  function measureCaptureFrameBytes(workDir, framesDir) {
10729
10775
  let total = sampleDirectoryBytes(framesDir);
10730
- if (!existsSync14(workDir)) return total;
10776
+ if (!existsSync15(workDir)) return total;
10731
10777
  for (const attempt of readdirSync3(workDir)) {
10732
10778
  if (/^retry-\d+-batch-\d+-worker-\d+$/.test(attempt)) {
10733
10779
  total += sampleDirectoryBytes(join22(workDir, attempt));
@@ -11030,7 +11076,7 @@ async function captureSessionFrames(session, { input, rangeStart, rangeEnd, resu
11030
11076
  }
11031
11077
 
11032
11078
  // src/services/render/stages/captureHdrStage.ts
11033
- import { existsSync as existsSync16, mkdirSync as mkdirSync8 } from "node:fs";
11079
+ import { existsSync as existsSync17, mkdirSync as mkdirSync8 } from "node:fs";
11034
11080
  import { join as join26 } from "node:path";
11035
11081
  import {
11036
11082
  closeCaptureSession as closeCaptureSession7,
@@ -11276,7 +11322,7 @@ import { Worker } from "node:worker_threads";
11276
11322
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
11277
11323
  import { dirname as dirname10, join as join24 } from "node:path";
11278
11324
  import { createRequire } from "node:module";
11279
- import { existsSync as existsSync15 } from "node:fs";
11325
+ import { existsSync as existsSync16 } from "node:fs";
11280
11326
  import { cpus as cpus2 } from "node:os";
11281
11327
  function resolveWorkerEntry(explicit) {
11282
11328
  if (explicit && explicit.length > 0) {
@@ -11289,7 +11335,7 @@ function resolveWorkerEntry(explicit) {
11289
11335
  }
11290
11336
  const moduleDir = dirname10(fileURLToPath3(import.meta.url));
11291
11337
  const jsPath = join24(moduleDir, "shaderTransitionWorker.js");
11292
- if (existsSync15(jsPath)) return { path: jsPath, isTs: false };
11338
+ if (existsSync16(jsPath)) return { path: jsPath, isTs: false };
11293
11339
  const tsPath = join24(moduleDir, "shaderTransitionWorker.ts");
11294
11340
  return { path: tsPath, isTs: true };
11295
11341
  }
@@ -11850,7 +11896,7 @@ async function runCaptureHdrStage(input) {
11850
11896
  }
11851
11897
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
11852
11898
  const debugDumpDir = debugDumpEnabled ? join26(framesDir, "debug-composite") : null;
11853
- if (debugDumpDir && !existsSync16(debugDumpDir)) {
11899
+ if (debugDumpDir && !existsSync17(debugDumpDir)) {
11854
11900
  mkdirSync8(debugDumpDir, { recursive: true });
11855
11901
  }
11856
11902
  const compositeTransfer = resolveCompositeTransfer(hasHdrContent, effectiveHdr);
@@ -12007,7 +12053,7 @@ async function runCaptureHdrStage(input) {
12007
12053
  // src/services/render/stages/encodeStage.ts
12008
12054
  import {
12009
12055
  copyFileSync as copyFileSync4,
12010
- existsSync as existsSync17,
12056
+ existsSync as existsSync18,
12011
12057
  mkdirSync as mkdirSync9,
12012
12058
  readdirSync as readdirSync4,
12013
12059
  readFileSync as readFileSync8,
@@ -12141,7 +12187,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
12141
12187
  const failure = await reencodeWithClearedWholeFrames(argsInput, run, startTime);
12142
12188
  if (failure) return failure;
12143
12189
  }
12144
- const fileSize = existsSync17(outputPath) ? statSync7(outputPath).size : 0;
12190
+ const fileSize = existsSync18(outputPath) ? statSync7(outputPath).size : 0;
12145
12191
  return {
12146
12192
  success: true,
12147
12193
  outputPath,
@@ -12302,7 +12348,7 @@ async function runEncodeStage(input) {
12302
12348
  const stage5Start = Date.now();
12303
12349
  if (isPngSequence) {
12304
12350
  const encoded = startEncodeProgress(job, "Writing PNG sequence", onProgress);
12305
- if (!existsSync17(outputPath)) mkdirSync9(outputPath, { recursive: true });
12351
+ if (!existsSync18(outputPath)) mkdirSync9(outputPath, { recursive: true });
12306
12352
  const captured = readdirSync4(framesDir).filter((name) => name.endsWith(".png")).sort();
12307
12353
  if (captured.length === 0) {
12308
12354
  throw new Error(
@@ -12313,7 +12359,7 @@ async function runEncodeStage(input) {
12313
12359
  const dst = join27(outputPath, formatExportFrameName(i, "png"));
12314
12360
  copyFileSync4(join27(framesDir, name), dst);
12315
12361
  });
12316
- if (hasAudio && audioOutputPath && existsSync17(audioOutputPath)) {
12362
+ if (hasAudio && audioOutputPath && existsSync18(audioOutputPath)) {
12317
12363
  copyFileSync4(audioOutputPath, join27(outputPath, MIXED_AUDIO_FILENAME2));
12318
12364
  log.info(
12319
12365
  `[Render] png-sequence: ${MIXED_AUDIO_FILENAME2} sidecar written to ${outputPath}/${MIXED_AUDIO_FILENAME2}`
@@ -12424,6 +12470,7 @@ async function assembleOutput(input, onSecondsWritten) {
12424
12470
  const normalizeResult = await padOrTrimAudioToVideoFrameCount({
12425
12471
  videoPath: videoOnlyPath,
12426
12472
  audioPath: audioOutputPath,
12473
+ sourcePath: input.audioPcmPath,
12427
12474
  outputPath: normalizedAudioPath,
12428
12475
  signal: abortSignal,
12429
12476
  timeoutMs: ffmpegProcessTimeout
@@ -12705,7 +12752,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
12705
12752
  let rangeStart = null;
12706
12753
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
12707
12754
  const framePath = join28(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12708
- const missing = !existsSync18(framePath) || statSync8(framePath).size <= 8;
12755
+ const missing = !existsSync19(framePath) || statSync8(framePath).size <= 8;
12709
12756
  if (missing && rangeStart === null) {
12710
12757
  rangeStart = frameIndex;
12711
12758
  } else if (!missing && rangeStart !== null) {
@@ -12830,7 +12877,7 @@ function countCapturedFrames(totalFrames, framesDir, frameExt) {
12830
12877
  let captured = 0;
12831
12878
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
12832
12879
  const framePath = join28(framesDir, formatCaptureFrameName(frameIndex, frameExt));
12833
- if (existsSync18(framePath)) captured++;
12880
+ if (existsSync19(framePath)) captured++;
12834
12881
  }
12835
12882
  return captured;
12836
12883
  }
@@ -13495,7 +13542,7 @@ async function executeRenderJob(job, projectDir, outputPath, progressSink, abort
13495
13542
  validateDeliveryEncoderConfig(job.config);
13496
13543
  const debugDir = resolveRenderDebugDir();
13497
13544
  const outputDir = dirname12(outputPath);
13498
- if (!existsSync18(outputDir)) mkdirSync10(outputDir, { recursive: true });
13545
+ if (!existsSync19(outputDir)) mkdirSync10(outputDir, { recursive: true });
13499
13546
  const workDir = job.config.debug ? join28(debugDir, job.id) : createRenderWorkDir(resolveRenderWorkDirPrefix(outputPath, job.id), outputDir);
13500
13547
  const pipelineStart = Date.now();
13501
13548
  const baseLog = job.config.logger ?? defaultLogger;
@@ -13637,7 +13684,7 @@ async function executeRenderPipeline(input) {
13637
13684
  job.startedAt = /* @__PURE__ */ new Date();
13638
13685
  assertNotAborted();
13639
13686
  assertConfiguredFfmpegBinariesExist();
13640
- if (!existsSync18(workDir)) mkdirSync10(workDir, { recursive: true });
13687
+ if (!existsSync19(workDir)) mkdirSync10(workDir, { recursive: true });
13641
13688
  if (job.config.debug) {
13642
13689
  log.info("[Render] Debug artifacts enabled", { workDir, logPath });
13643
13690
  }
@@ -13667,7 +13714,7 @@ async function executeRenderPipeline(input) {
13667
13714
  });
13668
13715
  const entryFile = job.config.entryFile || "index.html";
13669
13716
  let htmlPath = join28(projectDir, entryFile);
13670
- if (!existsSync18(htmlPath)) {
13717
+ if (!existsSync19(htmlPath)) {
13671
13718
  throw new Error(`Entry file not found: ${htmlPath}`);
13672
13719
  }
13673
13720
  assertNotAborted();
@@ -13675,7 +13722,7 @@ async function executeRenderPipeline(input) {
13675
13722
  if (entryFile !== "index.html" && isTemplateEntry(rawEntry)) {
13676
13723
  const wrapperPath = join28(workDir, "standalone-entry.html");
13677
13724
  const projectIndexPath = join28(projectDir, "index.html");
13678
- if (!existsSync18(projectIndexPath)) {
13725
+ if (!existsSync19(projectIndexPath)) {
13679
13726
  throw new Error(
13680
13727
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
13681
13728
  );
@@ -13986,7 +14033,8 @@ async function executeRenderPipeline(input) {
13986
14033
  masterFxChain: composition.masterFxChain,
13987
14034
  abortSignal: executionSignal,
13988
14035
  assertNotAborted,
13989
- log
14036
+ log,
14037
+ keepDeliverySource: true
13990
14038
  })
13991
14039
  );
13992
14040
  pendingAudio = audioStage.catch(() => void 0);
@@ -14018,7 +14066,7 @@ async function executeRenderPipeline(input) {
14018
14066
  throw new Error("File server failed to initialize before frame capture");
14019
14067
  }
14020
14068
  const framesDir = join28(workDir, "captured-frames");
14021
- if (!existsSync18(framesDir)) mkdirSync10(framesDir, { recursive: true });
14069
+ if (!existsSync19(framesDir)) mkdirSync10(framesDir, { recursive: true });
14022
14070
  updateJobStatus(job, "rendering", "Checking browser GPU", 25, onProgress, {
14023
14071
  code: "start_browsers"
14024
14072
  });
@@ -14694,7 +14742,7 @@ async function executeRenderPipeline(input) {
14694
14742
  const effectiveQuality = job.config.crf ?? preset.quality;
14695
14743
  const effectiveBitrate = job.config.crf != null ? void 0 : job.config.videoBitrate;
14696
14744
  const audioResult = await audioStage;
14697
- const { audioOutputPath, hasAudio } = audioResult;
14745
+ const { audioOutputPath, deliverySourcePath, hasAudio } = audioResult;
14698
14746
  perfStages.audioProcessMs = audioResult.audioProcessMs;
14699
14747
  recordLimiterAttenuation(job, audioResult.audioLoweredDb);
14700
14748
  if (audioResult.audioError) {
@@ -15320,6 +15368,7 @@ async function executeRenderPipeline(input) {
15320
15368
  job,
15321
15369
  videoOnlyPath,
15322
15370
  audioOutputPath,
15371
+ audioPcmPath: deliverySourcePath,
15323
15372
  outputPath: stagedOutputPath,
15324
15373
  hasAudio,
15325
15374
  format: outputFormat,
@@ -15345,7 +15394,7 @@ async function executeRenderPipeline(input) {
15345
15394
  })
15346
15395
  );
15347
15396
  const totalElapsed = Date.now() - pipelineStart;
15348
- const tmpPeakBytes = existsSync18(workDir) ? sampleDirectoryBytes(workDir) : 0;
15397
+ const tmpPeakBytes = existsSync19(workDir) ? sampleDirectoryBytes(workDir) : 0;
15349
15398
  recordTransientRetryObservability();
15350
15399
  observability.checkpoint("pipeline", "artifact validated", { totalElapsedMs: totalElapsed });
15351
15400
  const observabilitySummary = observability.summary({
@@ -15426,7 +15475,7 @@ async function executeRenderPipeline(input) {
15426
15475
  }
15427
15476
  }
15428
15477
  if (job.config.debug) {
15429
- if (!isPngSequence && !isHls && existsSync18(stagedOutputPath)) {
15478
+ if (!isPngSequence && !isHls && existsSync19(stagedOutputPath)) {
15430
15479
  const debugOutput = join28(workDir, `output${videoExt}`);
15431
15480
  copyFileSync5(stagedOutputPath, debugOutput);
15432
15481
  }
@@ -15938,7 +15987,7 @@ import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframe
15938
15987
  import {
15939
15988
  copyFileSync as copyFileSync6,
15940
15989
  cpSync as cpSync2,
15941
- existsSync as existsSync23,
15990
+ existsSync as existsSync24,
15942
15991
  linkSync,
15943
15992
  mkdirSync as mkdirSync14,
15944
15993
  rmSync as rmSync12,
@@ -15969,7 +16018,7 @@ import {
15969
16018
  } from "@hyperframes/engine";
15970
16019
 
15971
16020
  // src/services/distributed/chunkFrames.ts
15972
- import { existsSync as existsSync20, readdirSync as readdirSync6 } from "node:fs";
16021
+ import { existsSync as existsSync21, readdirSync as readdirSync6 } from "node:fs";
15973
16022
  import { extname as extname4, join as join31 } from "node:path";
15974
16023
  import {
15975
16024
  compositionRequiresWebGpu as compositionRequiresWebGpu3,
@@ -15981,7 +16030,7 @@ import {
15981
16030
  // src/services/distributed/shared.ts
15982
16031
  import { execFile as execFileCallback } from "node:child_process";
15983
16032
  import { dirname as dirname14, join as join30 } from "node:path";
15984
- import { existsSync as existsSync19, readFileSync as readFileSync9 } from "node:fs";
16033
+ import { existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
15985
16034
  import { fileURLToPath as fileURLToPath5 } from "node:url";
15986
16035
  import { promisify as promisify2 } from "node:util";
15987
16036
  import {
@@ -15997,7 +16046,7 @@ function isPlanAudioArtifactPath(path) {
15997
16046
  function resolvePlanAudioPath(planDir) {
15998
16047
  for (const name of [PLAN_AUDIO_RELATIVE_PATH, PLAN_AUDIO_LEGACY_RELATIVE_PATH]) {
15999
16048
  const candidate = join30(planDir, name);
16000
- if (existsSync19(candidate)) return candidate;
16049
+ if (existsSync20(candidate)) return candidate;
16001
16050
  }
16002
16051
  return null;
16003
16052
  }
@@ -16258,7 +16307,7 @@ function readProducerVersion() {
16258
16307
  let current = startDir;
16259
16308
  for (let i = 0; i < 10; i++) {
16260
16309
  const candidate = join30(current, "package.json");
16261
- if (existsSync19(candidate)) {
16310
+ if (existsSync20(candidate)) {
16262
16311
  try {
16263
16312
  const pkg = JSON.parse(readFileSync9(candidate, "utf-8"));
16264
16313
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
@@ -16312,7 +16361,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
16312
16361
  const result = [];
16313
16362
  for (const v of videos) {
16314
16363
  const outputDir = join31(planDir, "video-frames", v.videoId);
16315
- if (!existsSync20(outputDir)) {
16364
+ if (!existsSync21(outputDir)) {
16316
16365
  throw new Error(
16317
16366
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
16318
16367
  );
@@ -16428,7 +16477,7 @@ async function extractDeferredVideoFramesForChunk(input) {
16428
16477
  const range = video.deferredRange;
16429
16478
  const remoteUrl = remoteSources[range.sourcePath];
16430
16479
  const sourcePath = remoteUrl ?? join31(input.planDir, ...range.sourcePath.split("/"));
16431
- if (remoteUrl === void 0 && !existsSync20(sourcePath)) {
16480
+ if (remoteUrl === void 0 && !existsSync21(sourcePath)) {
16432
16481
  throw new RenderChunkValidationError(
16433
16482
  MISSING_PLAN_ARTIFACT,
16434
16483
  `[renderChunk] planDir is missing the source for video ${JSON.stringify(video.videoId)}: ${range.sourcePath}`
@@ -16646,7 +16695,7 @@ async function readPlanReferenceBackground(input) {
16646
16695
  }
16647
16696
 
16648
16697
  // src/services/render/stages/freezePlan.ts
16649
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync10, readdirSync as readdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
16698
+ import { existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync10, readdirSync as readdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
16650
16699
  import { join as join34, relative as relative3, resolve as resolve9 } from "node:path";
16651
16700
  import {
16652
16701
  REFERENCE_BACKGROUND_FIELD,
@@ -16840,7 +16889,7 @@ function planFileSha256(absolutePath, digests) {
16840
16889
  return sha256;
16841
16890
  }
16842
16891
  async function prehashPlanFiles(dir, digests) {
16843
- if (!existsSync21(dir)) return;
16892
+ if (!existsSync22(dir)) return;
16844
16893
  for (const { absolutePath } of listPlanFiles(dir)) {
16845
16894
  if (!digests.has(absolutePath)) digests.set(absolutePath, await sha256FileAsync(absolutePath));
16846
16895
  }
@@ -16910,15 +16959,15 @@ function writePlanRemoteFiles(planDir, files) {
16910
16959
  }
16911
16960
  function readPlanRemoteFiles(planDir) {
16912
16961
  const path = join34(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
16913
- return existsSync21(path) ? JSON.parse(readFileSync10(path, "utf-8")) : [];
16962
+ return existsSync22(path) ? JSON.parse(readFileSync10(path, "utf-8")) : [];
16914
16963
  }
16915
16964
  function recomputePlanHashFromPlanDir(planDir, digests) {
16916
16965
  const planJsonPath = join34(planDir, "plan.json");
16917
16966
  const encoderJsonPath = join34(planDir, "meta", "encoder.json");
16918
- if (!existsSync21(planJsonPath)) {
16967
+ if (!existsSync22(planJsonPath)) {
16919
16968
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
16920
16969
  }
16921
- if (!existsSync21(encoderJsonPath)) {
16970
+ if (!existsSync22(encoderJsonPath)) {
16922
16971
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
16923
16972
  }
16924
16973
  const planJson = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
@@ -16948,11 +16997,11 @@ async function freezePlan(input) {
16948
16997
  hasAudio,
16949
16998
  digests
16950
16999
  } = input;
16951
- if (!existsSync21(planDir)) {
17000
+ if (!existsSync22(planDir)) {
16952
17001
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
16953
17002
  }
16954
17003
  const metaDir = join34(planDir, "meta");
16955
- if (!existsSync21(metaDir)) mkdirSync12(metaDir, { recursive: true });
17004
+ if (!existsSync22(metaDir)) mkdirSync12(metaDir, { recursive: true });
16956
17005
  writeFileSync7(
16957
17006
  join34(metaDir, "composition.json"),
16958
17007
  `${JSON.stringify(composition, null, 2)}
@@ -17029,7 +17078,7 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
17029
17078
  }
17030
17079
 
17031
17080
  // src/services/distributed/chunkAudio.ts
17032
- import { closeSync as closeSync6, existsSync as existsSync22, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync11 } from "node:fs";
17081
+ import { closeSync as closeSync6, existsSync as existsSync23, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync11 } from "node:fs";
17033
17082
  import { writeFileSync as writeFileSync8, writeSync } from "node:fs";
17034
17083
  import { join as join35 } from "node:path";
17035
17084
  import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
@@ -17135,7 +17184,7 @@ async function writeChunkAudioSlices(input) {
17135
17184
  }
17136
17185
  function chunkAudioSource(planDir, chunkIndex, scratchPath) {
17137
17186
  const layoutPath = join35(planDir, SLICE_LAYOUT);
17138
- if (!existsSync22(layoutPath)) return resolvePlanAudioPath(planDir);
17187
+ if (!existsSync23(layoutPath)) return resolvePlanAudioPath(planDir);
17139
17188
  const layout = JSON.parse(readFileSync11(layoutPath, "utf-8"));
17140
17189
  const frame = readFileSync11(join35(planDir, SLICE_FRAME));
17141
17190
  const fd = openSync6(scratchPath, "w");
@@ -17695,7 +17744,7 @@ function createVideoSourceShipper(input) {
17695
17744
  let result = null;
17696
17745
  for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
17697
17746
  const rel = pathInside(root, srcPath);
17698
- if (rel !== null && (existsSync23(join37(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
17747
+ if (rel !== null && (existsSync24(join37(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
17699
17748
  result = ["compiled", ...rel.split(sep2)].join("/");
17700
17749
  break;
17701
17750
  }
@@ -17723,7 +17772,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17723
17772
  useGpu: false,
17724
17773
  browserGpuMode: "software"
17725
17774
  });
17726
- if (!existsSync23(planDir)) mkdirSync14(planDir, { recursive: true });
17775
+ if (!existsSync24(planDir)) mkdirSync14(planDir, { recursive: true });
17727
17776
  const log = config.logger ?? defaultLogger;
17728
17777
  const sizeLimitBytes = options.executionPlanSizeLimitBytes ?? config.planDirSizeLimitBytes ?? PLAN_DIR_SIZE_LIMIT_BYTES;
17729
17778
  const abortSignal = config.abortSignal;
@@ -17753,7 +17802,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
17753
17802
  });
17754
17803
  const entryFile = config.entryFile ?? "index.html";
17755
17804
  const htmlPath = join37(projectDir, entryFile);
17756
- if (!existsSync23(htmlPath)) {
17805
+ if (!existsSync24(htmlPath)) {
17757
17806
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
17758
17807
  }
17759
17808
  const workDir = join37(planDir, ".plan-work");
@@ -17982,15 +18031,15 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
17982
18031
  logPlanStage(log, "extract", stageStarted);
17983
18032
  const stagedVideoFrames = join37(compiledDir, "__hyperframes_video_frames");
17984
18033
  const videoFramesDst = join37(planDir, "video-frames");
17985
- if (existsSync23(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
18034
+ if (existsSync24(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
17986
18035
  const videoSourcesDir = join37(planDir, "video-sources");
17987
18036
  rmSync12(videoSourcesDir, { recursive: true, force: true });
17988
- if (existsSync23(stagedVideoFrames)) {
18037
+ if (existsSync24(stagedVideoFrames)) {
17989
18038
  renameWithRetry8(stagedVideoFrames, videoFramesDst);
17990
18039
  } else {
17991
18040
  mkdirSync14(videoFramesDst, { recursive: true });
17992
18041
  }
17993
- if (existsSync23(finalCompiledDir)) rmSync12(finalCompiledDir, { recursive: true, force: true });
18042
+ if (existsSync24(finalCompiledDir)) rmSync12(finalCompiledDir, { recursive: true, force: true });
17994
18043
  renameWithRetry8(compiledDir, finalCompiledDir);
17995
18044
  const shipVideoSource = createVideoSourceShipper({
17996
18045
  planDir,
@@ -18110,10 +18159,10 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18110
18159
  applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
18111
18160
  }
18112
18161
  const planAudioPath = join37(planDir, PLAN_AUDIO_RELATIVE_PATH);
18113
- if (audioResult?.hasAudio && existsSync23(audioResult.audioOutputPath)) {
18162
+ if (audioResult?.hasAudio && existsSync24(audioResult.audioOutputPath)) {
18114
18163
  renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
18115
18164
  }
18116
- if (chunksCarryAudio && existsSync23(planAudioPath)) {
18165
+ if (chunksCarryAudio && existsSync24(planAudioPath)) {
18117
18166
  if (options.sliceChunkAudio) {
18118
18167
  stageStarted = Date.now();
18119
18168
  await writeChunkAudioSlices({
@@ -18231,7 +18280,7 @@ async function plan(projectDir, config, planDir, options = {}) {
18231
18280
 
18232
18281
  // src/services/distributed/renderChunk.ts
18233
18282
  import { randomBytes } from "node:crypto";
18234
- import { existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync13, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync12 } from "node:fs";
18283
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync13, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync12 } from "node:fs";
18235
18284
  import { cpus as cpus3 } from "node:os";
18236
18285
  import { join as join41 } from "node:path";
18237
18286
  import {
@@ -18258,7 +18307,7 @@ import {
18258
18307
  } from "@hyperframes/engine";
18259
18308
  import {
18260
18309
  copyFileSync as copyFileSync8,
18261
- existsSync as existsSync25,
18310
+ existsSync as existsSync26,
18262
18311
  lstatSync as lstatSync3,
18263
18312
  mkdirSync as mkdirSync16,
18264
18313
  mkdtempSync as mkdtempSync6,
@@ -18276,7 +18325,7 @@ import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as r
18276
18325
  // src/services/distributed/planV2Publisher.ts
18277
18326
  import {
18278
18327
  copyFileSync as copyFileSync7,
18279
- existsSync as existsSync24,
18328
+ existsSync as existsSync25,
18280
18329
  linkSync as linkSync2,
18281
18330
  mkdirSync as mkdirSync15,
18282
18331
  mkdtempSync as mkdtempSync5,
@@ -18345,7 +18394,7 @@ var LocalPlanV2ArtifactPublisher = class {
18345
18394
  #linkFile;
18346
18395
  #committed = false;
18347
18396
  constructor(destinationDir, options = {}) {
18348
- if (existsSync24(destinationDir)) {
18397
+ if (existsSync25(destinationDir)) {
18349
18398
  throw new PlanV2IntegrityError(`output directory already exists: ${destinationDir}`);
18350
18399
  }
18351
18400
  this.destinationDir = destinationDir;
@@ -18362,7 +18411,7 @@ var LocalPlanV2ArtifactPublisher = class {
18362
18411
  );
18363
18412
  }
18364
18413
  const destinationPath = planV2BlobPath(this.temporaryDir, digest);
18365
- if (existsSync24(destinationPath)) return;
18414
+ if (existsSync25(destinationPath)) return;
18366
18415
  mkdirSync15(dirname15(destinationPath), { recursive: true });
18367
18416
  const stagingDir = mkdtempSync5(join39(dirname15(destinationPath), ".plan-v2-blob-"));
18368
18417
  const temporaryPath = join39(stagingDir, "blob");
@@ -18380,7 +18429,7 @@ var LocalPlanV2ArtifactPublisher = class {
18380
18429
  }
18381
18430
  async commitManifest(manifestBytes) {
18382
18431
  for (const digest of new Set(manifestDigests(manifestBytes))) {
18383
- if (!existsSync24(planV2BlobPath(this.temporaryDir, digest))) {
18432
+ if (!existsSync25(planV2BlobPath(this.temporaryDir, digest))) {
18384
18433
  throw new PlanV2IntegrityError(
18385
18434
  `cannot commit manifest before referenced blob is durable: ${digest}`
18386
18435
  );
@@ -18459,7 +18508,7 @@ function assertValidExtractionCacheCompleteSentinel(path) {
18459
18508
  }
18460
18509
  function validateExtractionCacheCompleteSentinels(executionPlanDir) {
18461
18510
  const videoRoot = join40(executionPlanDir, "video-frames");
18462
- if (!existsSync25(videoRoot)) return;
18511
+ if (!existsSync26(videoRoot)) return;
18463
18512
  for (const videoEntry of readdirSync9(videoRoot, { withFileTypes: true })) {
18464
18513
  if (!videoEntry.isDirectory()) continue;
18465
18514
  const videoDir = join40(videoRoot, videoEntry.name);
@@ -18560,7 +18609,7 @@ function parsePlanVideosJson2(value) {
18560
18609
  }
18561
18610
  function materializeExtractedVideoDirectories(planDir) {
18562
18611
  const videosPath = join40(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18563
- if (!existsSync25(videosPath)) return;
18612
+ if (!existsSync26(videosPath)) return;
18564
18613
  const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
18565
18614
  for (const video of videos.extracted) {
18566
18615
  mkdirSync16(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
@@ -18594,9 +18643,9 @@ function parseChunkSlices(value) {
18594
18643
  }
18595
18644
  function buildVideoChunkDependencies(executionPlanDir, dimensions) {
18596
18645
  const videoRoot = join40(executionPlanDir, "video-frames");
18597
- const hasExtractedFrames = existsSync25(videoRoot) && listFiles(videoRoot).length > 0;
18646
+ const hasExtractedFrames = existsSync26(videoRoot) && listFiles(videoRoot).length > 0;
18598
18647
  const videosPath = join40(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
18599
- if (!existsSync25(videosPath)) {
18648
+ if (!existsSync26(videosPath)) {
18600
18649
  return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
18601
18650
  }
18602
18651
  const chunksPath = join40(executionPlanDir, "meta", "chunks.json");
@@ -18653,7 +18702,7 @@ function computeManifestHash(manifest) {
18653
18702
  return sha256Hex(`${PLAN_V2_HASH_PREFIX}${canonicalJsonStringify(manifestPayload(manifest))}`);
18654
18703
  }
18655
18704
  function writeBlob(sourcePath, destinationPath) {
18656
- if (existsSync25(destinationPath)) return;
18705
+ if (existsSync26(destinationPath)) return;
18657
18706
  mkdirSync16(dirname16(destinationPath), { recursive: true });
18658
18707
  const temporaryDir = mkdtempSync6(join40(dirname16(destinationPath), ".plan-v2-blob-"));
18659
18708
  const temporaryPath = join40(temporaryDir, "blob");
@@ -18693,7 +18742,7 @@ async function putTasks(tasks) {
18693
18742
  }
18694
18743
  function buildPlanV2Publication(executionPlanDir, digests) {
18695
18744
  const executionPlanPath = join40(executionPlanDir, "plan.json");
18696
- if (!existsSync25(executionPlanPath)) {
18745
+ if (!existsSync26(executionPlanPath)) {
18697
18746
  throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
18698
18747
  }
18699
18748
  const executionPlanValue = readJsonFile(executionPlanPath, "execution plan.json");
@@ -18773,7 +18822,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
18773
18822
  };
18774
18823
  }
18775
18824
  function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
18776
- if (existsSync25(planV2Dir)) {
18825
+ if (existsSync26(planV2Dir)) {
18777
18826
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
18778
18827
  }
18779
18828
  const publication = buildPlanV2Publication(executionPlanDir);
@@ -18859,7 +18908,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
18859
18908
  }
18860
18909
  }
18861
18910
  async function planV2(projectDir, config, planV2Dir) {
18862
- if (existsSync25(planV2Dir)) {
18911
+ if (existsSync26(planV2Dir)) {
18863
18912
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
18864
18913
  }
18865
18914
  const publisher = new LocalPlanV2ArtifactPublisher(planV2Dir);
@@ -19013,7 +19062,7 @@ function parsePlanV2Manifest(value) {
19013
19062
  }
19014
19063
  function readPlanV2Manifest(planV2Dir) {
19015
19064
  const manifestPath = join40(planV2Dir, "plan.json");
19016
- if (!existsSync25(manifestPath)) {
19065
+ if (!existsSync26(manifestPath)) {
19017
19066
  throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
19018
19067
  }
19019
19068
  const value = readJsonFile(manifestPath, "v2 manifest");
@@ -19032,7 +19081,7 @@ function listPlanV2ArtifactsForTarget(manifest, target) {
19032
19081
  }
19033
19082
  function verifyBlob(planV2Dir, artifact) {
19034
19083
  const sourcePath = planV2BlobPath(planV2Dir, artifact.sha256);
19035
- if (!existsSync25(sourcePath)) {
19084
+ if (!existsSync26(sourcePath)) {
19036
19085
  throw new PlanV2IntegrityError(`missing content-addressed artifact ${artifact.sha256}`);
19037
19086
  }
19038
19087
  const stats = statSync10(sourcePath);
@@ -19045,7 +19094,7 @@ function verifyBlob(planV2Dir, artifact) {
19045
19094
  return sourcePath;
19046
19095
  }
19047
19096
  function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}) {
19048
- if (existsSync25(destinationDir)) {
19097
+ if (existsSync26(destinationDir)) {
19049
19098
  throw new PlanV2IntegrityError(`materialization destination already exists: ${destinationDir}`);
19050
19099
  }
19051
19100
  const manifest = readPlanV2Manifest(planV2Dir);
@@ -19110,7 +19159,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
19110
19159
  }
19111
19160
  function readValidatedPlanV2Materialization(planDir, expectedTarget) {
19112
19161
  const markerPath = join40(planDir, PLAN_V2_MATERIALIZATION_MARKER);
19113
- if (!existsSync25(markerPath)) return null;
19162
+ if (!existsSync26(markerPath)) return null;
19114
19163
  const marker = readJsonFile(markerPath, "materialization marker");
19115
19164
  if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
19116
19165
  throw new PlanV2IntegrityError("malformed materialization marker");
@@ -19128,7 +19177,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
19128
19177
  for (const artifact of required) {
19129
19178
  if (Object.hasOwn(remoteSources, artifact.path)) continue;
19130
19179
  const path = join40(planDir, ...artifact.path.split("/"));
19131
- if (!existsSync25(path) || statSync10(path).size !== artifact.sizeBytes) {
19180
+ if (!existsSync26(path) || statSync10(path).size !== artifact.sizeBytes) {
19132
19181
  throw new PlanV2IntegrityError(
19133
19182
  `materialized artifact missing or truncated: ${artifact.path}`
19134
19183
  );
@@ -19268,7 +19317,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19268
19317
  const planJsonPath = join41(planDir, "plan.json");
19269
19318
  const encoderJsonPath = join41(planDir, "meta", "encoder.json");
19270
19319
  const chunksJsonPath = join41(planDir, "meta", "chunks.json");
19271
- if (!existsSync26(planJsonPath)) {
19320
+ if (!existsSync27(planJsonPath)) {
19272
19321
  throw new RenderChunkValidationError(
19273
19322
  MISSING_PLAN_ARTIFACT,
19274
19323
  `[renderChunk] planDir is missing required artifact: ${planJsonPath}`
@@ -19284,7 +19333,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19284
19333
  const v2Manifest = v2Materialization?.manifest ?? null;
19285
19334
  const remoteSources = v2Materialization?.remoteSources ?? {};
19286
19335
  for (const required of [encoderJsonPath, chunksJsonPath]) {
19287
- if (!existsSync26(required)) {
19336
+ if (!existsSync27(required)) {
19288
19337
  throw new RenderChunkValidationError(
19289
19338
  MISSING_PLAN_ARTIFACT,
19290
19339
  `[renderChunk] planDir is missing required artifact: ${required}`
@@ -19295,7 +19344,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19295
19344
  const chunks = JSON.parse(readFileSync13(chunksJsonPath, "utf-8"));
19296
19345
  const videosJsonPath = join41(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19297
19346
  let planVideos = null;
19298
- if (existsSync26(videosJsonPath)) {
19347
+ if (existsSync27(videosJsonPath)) {
19299
19348
  try {
19300
19349
  planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync13(videosJsonPath, "utf-8")));
19301
19350
  } catch (err) {
@@ -19326,7 +19375,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19326
19375
  const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
19327
19376
  const framesInChunk = range.endFrame - range.startFrame;
19328
19377
  const compiledDir = join41(planDir, "compiled");
19329
- if (!existsSync26(compiledDir)) {
19378
+ if (!existsSync27(compiledDir)) {
19330
19379
  throw new RenderChunkValidationError(
19331
19380
  MISSING_PLAN_ARTIFACT,
19332
19381
  `[renderChunk] planDir missing compiled/ directory: ${compiledDir}`
@@ -19576,10 +19625,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19576
19625
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
19577
19626
  const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
19578
19627
  if (isPngSequence) {
19579
- if (!existsSync26(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
19628
+ if (!existsSync27(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
19580
19629
  } else {
19581
19630
  const outDir = join41(outputChunkPath, "..");
19582
- if (!existsSync26(outDir)) mkdirSync17(outDir, { recursive: true });
19631
+ if (!existsSync27(outDir)) mkdirSync17(outDir, { recursive: true });
19583
19632
  }
19584
19633
  const encodeInput = {
19585
19634
  job,
@@ -20479,7 +20528,7 @@ import {
20479
20528
 
20480
20529
  // src/server.ts
20481
20530
  import {
20482
- existsSync as existsSync29,
20531
+ existsSync as existsSync30,
20483
20532
  mkdirSync as mkdirSync19,
20484
20533
  statSync as statSync12,
20485
20534
  mkdtempSync as mkdtempSync8,
@@ -20502,7 +20551,7 @@ import {
20502
20551
 
20503
20552
  // src/services/hyperframeLint.ts
20504
20553
  import {
20505
- existsSync as existsSync27,
20554
+ existsSync as existsSync28,
20506
20555
  readFileSync as readFileSync15,
20507
20556
  statSync as statSync11,
20508
20557
  openSync as openSync7,
@@ -20556,7 +20605,7 @@ function readEntryHtml(filePath) {
20556
20605
  }
20557
20606
  function readProjectEntryFile(projectDir, preferredEntryFile) {
20558
20607
  const absProjectDir = resolve11(projectDir);
20559
- if (!existsSync27(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
20608
+ if (!existsSync28(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
20560
20609
  return { error: `Project directory not found: ${absProjectDir}` };
20561
20610
  }
20562
20611
  const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
@@ -20625,7 +20674,7 @@ async function runHyperframeLint(prepared) {
20625
20674
  import { Worker as Worker2 } from "node:worker_threads";
20626
20675
  import { fileURLToPath as fileURLToPath6 } from "node:url";
20627
20676
  import { dirname as dirname17, join as join44 } from "node:path";
20628
- import { existsSync as existsSync28 } from "node:fs";
20677
+ import { existsSync as existsSync29 } from "node:fs";
20629
20678
  var DEFAULT_HEALTH_PORT = 9848;
20630
20679
  async function startHealthWorker(options = {}) {
20631
20680
  const log = options.logger ?? defaultLogger2();
@@ -20702,7 +20751,7 @@ function resolveWorkerEntry2() {
20702
20751
  const here = dirname17(fileURLToPath6(import.meta.url));
20703
20752
  const candidates = [join44(here, "healthWorkerThread.js"), join44(here, "healthWorkerThread.ts")];
20704
20753
  for (const candidate of candidates) {
20705
- if (existsSync28(candidate)) return candidate;
20754
+ if (existsSync29(candidate)) return candidate;
20706
20755
  }
20707
20756
  return void 0;
20708
20757
  }
@@ -20848,7 +20897,7 @@ function resolvePreparedRenderOutput(prepared, rendersDir, log) {
20848
20897
  const { input, cleanupProjectDir } = prepared;
20849
20898
  const absoluteOutputPath = resolveOutputPath(input.projectDir, input.outputPath, rendersDir, log);
20850
20899
  const outputDir = dirname18(absoluteOutputPath);
20851
- if (!existsSync29(outputDir)) mkdirSync19(outputDir, { recursive: true });
20900
+ if (!existsSync30(outputDir)) mkdirSync19(outputDir, { recursive: true });
20852
20901
  return { input, cleanupProjectDir, absoluteOutputPath };
20853
20902
  }
20854
20903
  function validateRenderOverrides(body) {
@@ -20889,11 +20938,11 @@ function prepareProjectDirectory(projectDir, options) {
20889
20938
  const candidate = nonEmptyString(projectDir);
20890
20939
  if (!candidate) return null;
20891
20940
  const absProjectDir = resolve12(candidate);
20892
- if (!existsSync29(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
20941
+ if (!existsSync30(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
20893
20942
  return { error: `Project directory not found: ${absProjectDir}` };
20894
20943
  }
20895
20944
  const entry = options.entryFile || "index.html";
20896
- if (!existsSync29(resolve12(absProjectDir, entry))) {
20945
+ if (!existsSync30(resolve12(absProjectDir, entry))) {
20897
20946
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
20898
20947
  }
20899
20948
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -20985,7 +21034,7 @@ function cleanupTempDir(dir, log) {
20985
21034
  }
20986
21035
  }
20987
21036
  function outputFileSize(path) {
20988
- return existsSync29(path) ? statSync12(path).size : 0;
21037
+ return existsSync30(path) ? statSync12(path).size : 0;
20989
21038
  }
20990
21039
  function createBlockingProgressReporter(log, requestId) {
20991
21040
  let lastLoggedPct = -10;
@@ -21289,7 +21338,7 @@ function createRenderHandlers(options = {}) {
21289
21338
  if (!artifact) {
21290
21339
  return c.json({ success: false, error: "Output artifact not found or expired" }, 404);
21291
21340
  }
21292
- if (!existsSync29(artifact.path)) {
21341
+ if (!existsSync30(artifact.path)) {
21293
21342
  store.delete(token);
21294
21343
  return c.json({ success: false, error: "Output artifact file missing" }, 404);
21295
21344
  }
@@ -21395,7 +21444,7 @@ import {
21395
21444
  } from "@hyperframes/engine";
21396
21445
  import {
21397
21446
  cpSync as cpSync3,
21398
- existsSync as existsSync30,
21447
+ existsSync as existsSync31,
21399
21448
  mkdirSync as mkdirSync20,
21400
21449
  mkdtempSync as mkdtempSync9,
21401
21450
  readFileSync as readFileSync16,
@@ -21450,7 +21499,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21450
21499
  }
21451
21500
  const format = plan2.dimensions.format;
21452
21501
  const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
21453
- if (!existsSync30(dirname19(outputPath))) {
21502
+ if (!existsSync31(dirname19(outputPath))) {
21454
21503
  mkdirSync20(dirname19(outputPath), { recursive: true });
21455
21504
  }
21456
21505
  const workDir = mkdtempSync9(`${outputPath}.assemble-work-`);
@@ -21474,7 +21523,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21474
21523
  try {
21475
21524
  const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
21476
21525
  const finalPath = join46(workDir, `output.${format}`);
21477
- const audio = audioPath !== null && existsSync30(audioPath) ? audioPath : null;
21526
+ const audio = audioPath !== null && existsSync31(audioPath) ? audioPath : null;
21478
21527
  await writeJoined(ctx, videoSources, audio, finalPath);
21479
21528
  renameWithRetry11(finalPath, outputPath);
21480
21529
  log.info("[assemble] stage timings", {
@@ -21492,7 +21541,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21492
21541
  });
21493
21542
  }
21494
21543
  }
21495
- const fileSize = existsSync30(outputPath) ? statSync13(outputPath).size : 0;
21544
+ const fileSize = existsSync31(outputPath) ? statSync13(outputPath).size : 0;
21496
21545
  return {
21497
21546
  ...referenceBackgroundResult8(plan2[REFERENCE_BACKGROUND_FIELD6]),
21498
21547
  outputPath,
@@ -21504,13 +21553,13 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
21504
21553
  function readAssemblePlan(planDir, chunkPaths) {
21505
21554
  const planJsonPath = join46(planDir, "plan.json");
21506
21555
  const chunksJsonPath = join46(planDir, "meta", "chunks.json");
21507
- if (!existsSync30(planJsonPath)) {
21556
+ if (!existsSync31(planJsonPath)) {
21508
21557
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
21509
21558
  }
21510
21559
  const plan2 = JSON.parse(readFileSync16(planJsonPath, "utf-8"));
21511
21560
  readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
21512
21561
  validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
21513
- if (!existsSync30(chunksJsonPath)) {
21562
+ if (!existsSync31(chunksJsonPath)) {
21514
21563
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
21515
21564
  }
21516
21565
  const chunks = JSON.parse(readFileSync16(chunksJsonPath, "utf-8"));
@@ -21525,7 +21574,7 @@ function readAssemblePlan(planDir, chunkPaths) {
21525
21574
  }
21526
21575
  }
21527
21576
  for (const path of chunkPaths.flat()) {
21528
- if (!existsSync30(path)) {
21577
+ if (!existsSync31(path)) {
21529
21578
  throw new Error(`[assemble] chunk path does not exist: ${path}`);
21530
21579
  }
21531
21580
  }
@@ -21664,7 +21713,7 @@ function planFormat(planDir) {
21664
21713
  }
21665
21714
  function lockedAudio(planDir) {
21666
21715
  const encoderJsonPath = join46(planDir, "meta", "encoder.json");
21667
- if (!existsSync30(encoderJsonPath)) return {};
21716
+ if (!existsSync31(encoderJsonPath)) return {};
21668
21717
  return JSON.parse(readFileSync16(encoderJsonPath, "utf-8"));
21669
21718
  }
21670
21719
  function readCfrEncoder(planDir, format) {
@@ -21674,7 +21723,7 @@ function readCfrEncoder(planDir, format) {
21674
21723
  );
21675
21724
  }
21676
21725
  const encoderJsonPath = join46(planDir, "meta", "encoder.json");
21677
- if (!existsSync30(encoderJsonPath)) {
21726
+ if (!existsSync31(encoderJsonPath)) {
21678
21727
  throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
21679
21728
  }
21680
21729
  const encoderJson = JSON.parse(readFileSync16(encoderJsonPath, "utf-8"));
@@ -21686,7 +21735,7 @@ function readCfrEncoder(planDir, format) {
21686
21735
  return encoderJson;
21687
21736
  }
21688
21737
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
21689
- if (existsSync30(outputPath)) rmSync18(outputPath, { recursive: true, force: true });
21738
+ if (existsSync31(outputPath)) rmSync18(outputPath, { recursive: true, force: true });
21690
21739
  mkdirSync20(outputPath, { recursive: true });
21691
21740
  let globalIdx = 0;
21692
21741
  for (const chunkDir of chunkPaths) {
@@ -21710,7 +21759,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
21710
21759
  `[assemble] png-sequence frame count mismatch: merged ${globalIdx} frames vs plan.totalFrames=${totalFrames}. Using on-disk count.`
21711
21760
  );
21712
21761
  }
21713
- if (audioPath !== null && existsSync30(audioPath)) {
21762
+ if (audioPath !== null && existsSync31(audioPath)) {
21714
21763
  const sidecar = join46(outputPath, MIXED_AUDIO_FILENAME4);
21715
21764
  cpSync3(audioPath, sidecar);
21716
21765
  }