@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.
@@ -8,7 +8,7 @@ import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframe
8
8
  import {
9
9
  copyFileSync as copyFileSync6,
10
10
  cpSync as cpSync2,
11
- existsSync as existsSync16,
11
+ existsSync as existsSync17,
12
12
  linkSync,
13
13
  mkdirSync as mkdirSync10,
14
14
  rmSync as rmSync7,
@@ -71,7 +71,7 @@ var defaultLogger = createConsoleLogger("info");
71
71
  // src/services/renderOrchestrator.ts
72
72
  import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
73
73
  import {
74
- existsSync as existsSync11,
74
+ existsSync as existsSync12,
75
75
  mkdirSync as mkdirSync6,
76
76
  readdirSync as readdirSync3,
77
77
  rmSync as rmSync5,
@@ -5927,6 +5927,7 @@ import {
5927
5927
  } from "@hyperframes/engine";
5928
5928
 
5929
5929
  // src/services/render/stages/audioStage.ts
5930
+ import { existsSync as existsSync9 } from "node:fs";
5930
5931
  import { join as join12 } from "node:path";
5931
5932
  import {
5932
5933
  MIXED_AUDIO_FILENAME,
@@ -6060,8 +6061,9 @@ var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
6060
6061
  var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
6061
6062
  var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
6062
6063
  var MAX_TRUE_PEAK_CORRECTION_PASSES = 3;
6064
+ var gainFilter = (gainDb) => `volume=${gainDb.toFixed(3)}dB`;
6063
6065
  function aacTruePeakCorrectionFilter(targetDurationSeconds, attenuationDb) {
6064
- return `volume=${attenuationDb.toFixed(3)}dB,apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
6066
+ return `${gainFilter(attenuationDb)},apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
6065
6067
  }
6066
6068
  function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, targetDurationSeconds) {
6067
6069
  const delta = targetDurationSeconds - sourceDurationSeconds;
@@ -6099,7 +6101,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6099
6101
  const probeAudio = input.probeAudioInfo ?? defaultProbeAudioInfo;
6100
6102
  const timeoutMs = input.timeoutMs ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
6101
6103
  const runner = input.runFfmpeg ?? ((args) => defaultRunFfmpeg(args, timeoutMs, input.signal));
6102
- const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal);
6104
+ const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal, input.sourcePath);
6103
6105
  const probeTruePeak = input.probeAudioTruePeakDbfs ?? (input.runFfmpeg || input.encodeAac ? void 0 : (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }));
6104
6106
  const [videoResult, audioResult] = await Promise.allSettled([
6105
6107
  probeVideo(input.videoPath),
@@ -6147,7 +6149,12 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6147
6149
  );
6148
6150
  try {
6149
6151
  for (const step of plan.steps) {
6150
- const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(input.audioPath, input.outputPath, targetDurationSeconds, step.filter);
6152
+ const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(
6153
+ input.sourcePath ?? input.audioPath,
6154
+ input.outputPath,
6155
+ targetDurationSeconds,
6156
+ step.filter
6157
+ );
6151
6158
  if (!ffmpegResult.success) {
6152
6159
  return {
6153
6160
  success: false,
@@ -6176,6 +6183,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6176
6183
  if (probeTruePeak) {
6177
6184
  const correction = await enforceAacTruePeak({
6178
6185
  audioPath: input.outputPath,
6186
+ sourcePath: input.sourcePath,
6179
6187
  targetDurationSeconds,
6180
6188
  signal: input.signal,
6181
6189
  probeTruePeak,
@@ -6211,9 +6219,27 @@ async function constrainAacTruePeak(input) {
6211
6219
  targetDurationSeconds: input.targetDurationSeconds,
6212
6220
  signal: input.signal,
6213
6221
  probeTruePeak: input.probeTruePeakDbfs ?? ((audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal })),
6214
- encode: input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal, input.sourcePath)
6222
+ encode: input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal, input.sourcePath),
6223
+ rewriteSource: input.rewriteSource ?? ((sourcePath, outputPath, filter) => defaultRunFfmpeg(
6224
+ ["-i", sourcePath, "-af", filter, "-c:a", "pcm_f32le", "-y", outputPath],
6225
+ timeoutMs,
6226
+ input.signal
6227
+ ))
6215
6228
  });
6216
6229
  }
6230
+ async function cutSource(input, scratchDir, attenuationDb) {
6231
+ if (!input.sourcePath || !input.rewriteSource) return true;
6232
+ const cutPath = join10(scratchDir, "source.wav");
6233
+ try {
6234
+ const result = await input.rewriteSource(input.sourcePath, cutPath, gainFilter(attenuationDb));
6235
+ if (!result.success) throw new Error(result.error);
6236
+ renameWithRetry5(cutPath, input.sourcePath, { copyFallback: true });
6237
+ return true;
6238
+ } catch {
6239
+ removeScratch(input.sourcePath);
6240
+ return false;
6241
+ }
6242
+ }
6217
6243
  async function enforceAacTruePeak(input) {
6218
6244
  let scratchDir;
6219
6245
  try {
@@ -6233,8 +6259,10 @@ async function enforceAacTruePeak(input) {
6233
6259
  }
6234
6260
  if (truePeakDbfs <= AAC_DELIVERY_TRUE_PEAK_DBFS) {
6235
6261
  if (measuredPath !== correctedPath) return { success: true };
6262
+ const sourceCut = await cutSource(input, scratchDir, attenuationDb);
6236
6263
  renameWithRetry5(correctedPath, input.audioPath, { copyFallback: true });
6237
- return { success: true, loweredDb: Number((-attenuationDb).toFixed(2)) };
6264
+ const loweredDb = Number((-attenuationDb).toFixed(2));
6265
+ return sourceCut ? { success: true, loweredDb } : { success: true, loweredDb, sourceStale: true };
6238
6266
  }
6239
6267
  if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
6240
6268
  const headroomDb = AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB * 2 ** pass;
@@ -6244,7 +6272,7 @@ async function enforceAacTruePeak(input) {
6244
6272
  const referenceDbfs = Math.max(truePeakDbfs, (sourcePeakDbfs ?? -Infinity) + attenuationDb);
6245
6273
  attenuationDb += AAC_DELIVERY_TRUE_PEAK_DBFS - headroomDb - referenceDbfs;
6246
6274
  const result = await input.encode(
6247
- input.audioPath,
6275
+ input.sourcePath ?? input.audioPath,
6248
6276
  correctedPath,
6249
6277
  input.targetDurationSeconds,
6250
6278
  aacTruePeakCorrectionFilter(input.targetDurationSeconds, attenuationDb)
@@ -6473,36 +6501,54 @@ async function runAudioStageScoped(input) {
6473
6501
  const stageStart = Date.now();
6474
6502
  const pcmSourcePath = join12(input.workDir, "audio-source.wav");
6475
6503
  const duration = input.totalFrames * input.fps.den / input.fps.num;
6504
+ let deliverySourcePath;
6476
6505
  try {
6477
6506
  const result = await mixAudioForDelivery(input, duration, pcmSourcePath);
6478
6507
  let audioLoweredDb;
6479
6508
  if (result.hasAudio) {
6480
6509
  const guardStart = Date.now();
6481
- const limited = await limitDeliveryPeaks({
6482
- audioPath: result.audioOutputPath,
6483
- sourcePath: pcmSourcePath,
6484
- targetDurationSeconds: duration,
6485
- signal: input.abortSignal,
6486
- timeoutMs: input.ffmpegProcessTimeout,
6487
- warn: (message, details) => input.log?.warn?.(message, details)
6488
- });
6489
- if (!limited.success) throw encoderFailureError("Audio true-peak limit failed", limited);
6490
- const peak = await constrainAacTruePeak({
6491
- audioPath: result.audioOutputPath,
6492
- sourcePath: pcmSourcePath,
6493
- targetDurationSeconds: duration,
6494
- signal: input.abortSignal,
6495
- timeoutMs: input.ffmpegProcessTimeout
6496
- });
6497
- if (!peak.success) throw encoderFailureError("Audio true-peak check failed", peak);
6498
- audioLoweredDb = peak.loweredDb;
6510
+ const guard = await guardDeliveryPeaks(
6511
+ input,
6512
+ result.audioOutputPath,
6513
+ pcmSourcePath,
6514
+ duration
6515
+ );
6516
+ audioLoweredDb = guard.loweredDb;
6499
6517
  input.log?.info("[audio] phases", { ...result.audioPhaseMs, guard: Date.now() - guardStart });
6518
+ if (input.keepDeliverySource && !guard.sourceStale && existsSync9(pcmSourcePath)) {
6519
+ deliverySourcePath = pcmSourcePath;
6520
+ }
6500
6521
  }
6501
- return { ...result, audioLoweredDb, audioProcessMs: Date.now() - stageStart };
6522
+ return {
6523
+ ...result,
6524
+ audioLoweredDb,
6525
+ deliverySourcePath,
6526
+ audioProcessMs: Date.now() - stageStart
6527
+ };
6502
6528
  } finally {
6503
- removeScratch2(pcmSourcePath);
6529
+ if (!deliverySourcePath) removeScratch2(pcmSourcePath);
6504
6530
  }
6505
6531
  }
6532
+ async function guardDeliveryPeaks(input, audioPath, sourcePath, duration) {
6533
+ const limited = await limitDeliveryPeaks({
6534
+ audioPath,
6535
+ sourcePath,
6536
+ targetDurationSeconds: duration,
6537
+ signal: input.abortSignal,
6538
+ timeoutMs: input.ffmpegProcessTimeout,
6539
+ warn: (message, details) => input.log?.warn?.(message, details)
6540
+ });
6541
+ if (!limited.success) throw encoderFailureError("Audio true-peak limit failed", limited);
6542
+ const peak = await constrainAacTruePeak({
6543
+ audioPath,
6544
+ sourcePath,
6545
+ targetDurationSeconds: duration,
6546
+ signal: input.abortSignal,
6547
+ timeoutMs: input.ffmpegProcessTimeout
6548
+ });
6549
+ if (!peak.success) throw encoderFailureError("Audio true-peak check failed", peak);
6550
+ return { loweredDb: peak.loweredDb, sourceStale: peak.sourceStale };
6551
+ }
6506
6552
  async function mixAudioForDelivery(input, duration, pcmSourcePath) {
6507
6553
  const {
6508
6554
  projectDir,
@@ -6597,7 +6643,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
6597
6643
  }
6598
6644
 
6599
6645
  // src/services/render/stages/captureStage.ts
6600
- import { existsSync as existsSync9, readdirSync, statfsSync } from "node:fs";
6646
+ import { existsSync as existsSync10, readdirSync, statfsSync } from "node:fs";
6601
6647
  import { join as join13 } from "node:path";
6602
6648
  import {
6603
6649
  classifyCaptureFailure as classifyCaptureFailure2,
@@ -6649,7 +6695,7 @@ function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis, remed
6649
6695
  }
6650
6696
  function measureCaptureFrameBytes(workDir, framesDir) {
6651
6697
  let total = sampleDirectoryBytes(framesDir);
6652
- if (!existsSync9(workDir)) return total;
6698
+ if (!existsSync10(workDir)) return total;
6653
6699
  for (const attempt of readdirSync(workDir)) {
6654
6700
  if (/^retry-\d+-batch-\d+-worker-\d+$/.test(attempt)) {
6655
6701
  total += sampleDirectoryBytes(join13(workDir, attempt));
@@ -6986,7 +7032,7 @@ import {
6986
7032
  // src/services/render/stages/encodeStage.ts
6987
7033
  import {
6988
7034
  copyFileSync as copyFileSync4,
6989
- existsSync as existsSync10,
7035
+ existsSync as existsSync11,
6990
7036
  mkdirSync as mkdirSync5,
6991
7037
  readdirSync as readdirSync2,
6992
7038
  readFileSync as readFileSync5,
@@ -7120,7 +7166,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
7120
7166
  const failure = await reencodeWithClearedWholeFrames(argsInput, run, startTime);
7121
7167
  if (failure) return failure;
7122
7168
  }
7123
- const fileSize = existsSync10(outputPath) ? statSync4(outputPath).size : 0;
7169
+ const fileSize = existsSync11(outputPath) ? statSync4(outputPath).size : 0;
7124
7170
  return {
7125
7171
  success: true,
7126
7172
  outputPath,
@@ -7281,7 +7327,7 @@ async function runEncodeStage(input) {
7281
7327
  const stage5Start = Date.now();
7282
7328
  if (isPngSequence) {
7283
7329
  const encoded = startEncodeProgress(job, "Writing PNG sequence", onProgress);
7284
- if (!existsSync10(outputPath)) mkdirSync5(outputPath, { recursive: true });
7330
+ if (!existsSync11(outputPath)) mkdirSync5(outputPath, { recursive: true });
7285
7331
  const captured = readdirSync2(framesDir).filter((name) => name.endsWith(".png")).sort();
7286
7332
  if (captured.length === 0) {
7287
7333
  throw new Error(
@@ -7292,7 +7338,7 @@ async function runEncodeStage(input) {
7292
7338
  const dst = join14(outputPath, formatExportFrameName(i, "png"));
7293
7339
  copyFileSync4(join14(framesDir, name), dst);
7294
7340
  });
7295
- if (hasAudio && audioOutputPath && existsSync10(audioOutputPath)) {
7341
+ if (hasAudio && audioOutputPath && existsSync11(audioOutputPath)) {
7296
7342
  copyFileSync4(audioOutputPath, join14(outputPath, MIXED_AUDIO_FILENAME2));
7297
7343
  log.info(
7298
7344
  `[Render] png-sequence: ${MIXED_AUDIO_FILENAME2} sidecar written to ${outputPath}/${MIXED_AUDIO_FILENAME2}`
@@ -7459,7 +7505,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
7459
7505
  let rangeStart = null;
7460
7506
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
7461
7507
  const framePath = join15(framesDir, formatCaptureFrameName(frameIndex, frameExt));
7462
- const missing = !existsSync11(framePath) || statSync5(framePath).size <= 8;
7508
+ const missing = !existsSync12(framePath) || statSync5(framePath).size <= 8;
7463
7509
  if (missing && rangeStart === null) {
7464
7510
  rangeStart = frameIndex;
7465
7511
  } else if (!missing && rangeStart !== null) {
@@ -7549,7 +7595,7 @@ function countCapturedFrames(totalFrames, framesDir, frameExt) {
7549
7595
  let captured = 0;
7550
7596
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
7551
7597
  const framePath = join15(framesDir, formatCaptureFrameName(frameIndex, frameExt));
7552
- if (existsSync11(framePath)) captured++;
7598
+ if (existsSync12(framePath)) captured++;
7553
7599
  }
7554
7600
  return captured;
7555
7601
  }
@@ -7776,7 +7822,7 @@ import {
7776
7822
  } from "@hyperframes/engine";
7777
7823
 
7778
7824
  // src/services/distributed/chunkFrames.ts
7779
- import { existsSync as existsSync13, readdirSync as readdirSync4 } from "node:fs";
7825
+ import { existsSync as existsSync14, readdirSync as readdirSync4 } from "node:fs";
7780
7826
  import { extname as extname2, join as join17 } from "node:path";
7781
7827
  import {
7782
7828
  compositionRequiresWebGpu as compositionRequiresWebGpu3,
@@ -7788,7 +7834,7 @@ import {
7788
7834
  // src/services/distributed/shared.ts
7789
7835
  import { execFile as execFileCallback } from "node:child_process";
7790
7836
  import { dirname as dirname10, join as join16 } from "node:path";
7791
- import { existsSync as existsSync12, readFileSync as readFileSync6 } from "node:fs";
7837
+ import { existsSync as existsSync13, readFileSync as readFileSync6 } from "node:fs";
7792
7838
  import { fileURLToPath as fileURLToPath3 } from "node:url";
7793
7839
  import { promisify as promisify2 } from "node:util";
7794
7840
  import {
@@ -7804,7 +7850,7 @@ function isPlanAudioArtifactPath(path) {
7804
7850
  function resolvePlanAudioPath(planDir) {
7805
7851
  for (const name of [PLAN_AUDIO_RELATIVE_PATH, PLAN_AUDIO_LEGACY_RELATIVE_PATH]) {
7806
7852
  const candidate = join16(planDir, name);
7807
- if (existsSync12(candidate)) return candidate;
7853
+ if (existsSync13(candidate)) return candidate;
7808
7854
  }
7809
7855
  return null;
7810
7856
  }
@@ -8065,7 +8111,7 @@ function readProducerVersion() {
8065
8111
  let current = startDir;
8066
8112
  for (let i = 0; i < 10; i++) {
8067
8113
  const candidate = join16(current, "package.json");
8068
- if (existsSync12(candidate)) {
8114
+ if (existsSync13(candidate)) {
8069
8115
  try {
8070
8116
  const pkg = JSON.parse(readFileSync6(candidate, "utf-8"));
8071
8117
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
@@ -8119,7 +8165,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
8119
8165
  const result = [];
8120
8166
  for (const v of videos) {
8121
8167
  const outputDir = join17(planDir, "video-frames", v.videoId);
8122
- if (!existsSync13(outputDir)) {
8168
+ if (!existsSync14(outputDir)) {
8123
8169
  throw new Error(
8124
8170
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
8125
8171
  );
@@ -8235,7 +8281,7 @@ async function extractDeferredVideoFramesForChunk(input) {
8235
8281
  const range = video.deferredRange;
8236
8282
  const remoteUrl = remoteSources[range.sourcePath];
8237
8283
  const sourcePath = remoteUrl ?? join17(input.planDir, ...range.sourcePath.split("/"));
8238
- if (remoteUrl === void 0 && !existsSync13(sourcePath)) {
8284
+ if (remoteUrl === void 0 && !existsSync14(sourcePath)) {
8239
8285
  throw new RenderChunkValidationError(
8240
8286
  MISSING_PLAN_ARTIFACT,
8241
8287
  `[renderChunk] planDir is missing the source for video ${JSON.stringify(video.videoId)}: ${range.sourcePath}`
@@ -8453,7 +8499,7 @@ async function readPlanReferenceBackground(input) {
8453
8499
  }
8454
8500
 
8455
8501
  // src/services/render/stages/freezePlan.ts
8456
- import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync7, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
8502
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync7, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
8457
8503
  import { join as join20, relative as relative3, resolve as resolve8 } from "node:path";
8458
8504
  import {
8459
8505
  REFERENCE_BACKGROUND_FIELD,
@@ -8647,7 +8693,7 @@ function planFileSha256(absolutePath, digests) {
8647
8693
  return sha256;
8648
8694
  }
8649
8695
  async function prehashPlanFiles(dir, digests) {
8650
- if (!existsSync14(dir)) return;
8696
+ if (!existsSync15(dir)) return;
8651
8697
  for (const { absolutePath } of listPlanFiles(dir)) {
8652
8698
  if (!digests.has(absolutePath)) digests.set(absolutePath, await sha256FileAsync(absolutePath));
8653
8699
  }
@@ -8717,15 +8763,15 @@ function writePlanRemoteFiles(planDir, files) {
8717
8763
  }
8718
8764
  function readPlanRemoteFiles(planDir) {
8719
8765
  const path = join20(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
8720
- return existsSync14(path) ? JSON.parse(readFileSync7(path, "utf-8")) : [];
8766
+ return existsSync15(path) ? JSON.parse(readFileSync7(path, "utf-8")) : [];
8721
8767
  }
8722
8768
  function recomputePlanHashFromPlanDir(planDir, digests) {
8723
8769
  const planJsonPath = join20(planDir, "plan.json");
8724
8770
  const encoderJsonPath = join20(planDir, "meta", "encoder.json");
8725
- if (!existsSync14(planJsonPath)) {
8771
+ if (!existsSync15(planJsonPath)) {
8726
8772
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
8727
8773
  }
8728
- if (!existsSync14(encoderJsonPath)) {
8774
+ if (!existsSync15(encoderJsonPath)) {
8729
8775
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
8730
8776
  }
8731
8777
  const planJson = JSON.parse(readFileSync7(planJsonPath, "utf-8"));
@@ -8755,11 +8801,11 @@ async function freezePlan(input) {
8755
8801
  hasAudio,
8756
8802
  digests
8757
8803
  } = input;
8758
- if (!existsSync14(planDir)) {
8804
+ if (!existsSync15(planDir)) {
8759
8805
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
8760
8806
  }
8761
8807
  const metaDir = join20(planDir, "meta");
8762
- if (!existsSync14(metaDir)) mkdirSync7(metaDir, { recursive: true });
8808
+ if (!existsSync15(metaDir)) mkdirSync7(metaDir, { recursive: true });
8763
8809
  writeFileSync5(
8764
8810
  join20(metaDir, "composition.json"),
8765
8811
  `${JSON.stringify(composition, null, 2)}
@@ -8836,7 +8882,7 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
8836
8882
  }
8837
8883
 
8838
8884
  // src/services/distributed/chunkAudio.ts
8839
- import { closeSync as closeSync4, existsSync as existsSync15, ftruncateSync, mkdirSync as mkdirSync9, openSync as openSync4, readFileSync as readFileSync8 } from "node:fs";
8885
+ import { closeSync as closeSync4, existsSync as existsSync16, ftruncateSync, mkdirSync as mkdirSync9, openSync as openSync4, readFileSync as readFileSync8 } from "node:fs";
8840
8886
  import { writeFileSync as writeFileSync6, writeSync } from "node:fs";
8841
8887
  import { join as join22 } from "node:path";
8842
8888
  import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
@@ -9327,7 +9373,7 @@ async function writeChunkAudioSlices(input) {
9327
9373
  }
9328
9374
  function chunkAudioSource(planDir, chunkIndex, scratchPath) {
9329
9375
  const layoutPath = join22(planDir, SLICE_LAYOUT);
9330
- if (!existsSync15(layoutPath)) return resolvePlanAudioPath(planDir);
9376
+ if (!existsSync16(layoutPath)) return resolvePlanAudioPath(planDir);
9331
9377
  const layout = JSON.parse(readFileSync8(layoutPath, "utf-8"));
9332
9378
  const frame = readFileSync8(join22(planDir, SLICE_FRAME));
9333
9379
  const fd = openSync4(scratchPath, "w");
@@ -9891,7 +9937,7 @@ function createVideoSourceShipper(input) {
9891
9937
  let result = null;
9892
9938
  for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
9893
9939
  const rel = pathInside(root, srcPath);
9894
- if (rel !== null && (existsSync16(join24(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
9940
+ if (rel !== null && (existsSync17(join24(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
9895
9941
  result = ["compiled", ...rel.split(sep2)].join("/");
9896
9942
  break;
9897
9943
  }
@@ -9919,7 +9965,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
9919
9965
  useGpu: false,
9920
9966
  browserGpuMode: "software"
9921
9967
  });
9922
- if (!existsSync16(planDir)) mkdirSync10(planDir, { recursive: true });
9968
+ if (!existsSync17(planDir)) mkdirSync10(planDir, { recursive: true });
9923
9969
  const log = config.logger ?? defaultLogger;
9924
9970
  const sizeLimitBytes = options.executionPlanSizeLimitBytes ?? config.planDirSizeLimitBytes ?? PLAN_DIR_SIZE_LIMIT_BYTES;
9925
9971
  const abortSignal = config.abortSignal;
@@ -9949,7 +9995,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
9949
9995
  });
9950
9996
  const entryFile = config.entryFile ?? "index.html";
9951
9997
  const htmlPath = join24(projectDir, entryFile);
9952
- if (!existsSync16(htmlPath)) {
9998
+ if (!existsSync17(htmlPath)) {
9953
9999
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
9954
10000
  }
9955
10001
  const workDir = join24(planDir, ".plan-work");
@@ -10178,15 +10224,15 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
10178
10224
  logPlanStage(log, "extract", stageStarted);
10179
10225
  const stagedVideoFrames = join24(compiledDir, "__hyperframes_video_frames");
10180
10226
  const videoFramesDst = join24(planDir, "video-frames");
10181
- if (existsSync16(videoFramesDst)) rmSync7(videoFramesDst, { recursive: true, force: true });
10227
+ if (existsSync17(videoFramesDst)) rmSync7(videoFramesDst, { recursive: true, force: true });
10182
10228
  const videoSourcesDir = join24(planDir, "video-sources");
10183
10229
  rmSync7(videoSourcesDir, { recursive: true, force: true });
10184
- if (existsSync16(stagedVideoFrames)) {
10230
+ if (existsSync17(stagedVideoFrames)) {
10185
10231
  renameWithRetry8(stagedVideoFrames, videoFramesDst);
10186
10232
  } else {
10187
10233
  mkdirSync10(videoFramesDst, { recursive: true });
10188
10234
  }
10189
- if (existsSync16(finalCompiledDir)) rmSync7(finalCompiledDir, { recursive: true, force: true });
10235
+ if (existsSync17(finalCompiledDir)) rmSync7(finalCompiledDir, { recursive: true, force: true });
10190
10236
  renameWithRetry8(compiledDir, finalCompiledDir);
10191
10237
  const shipVideoSource = createVideoSourceShipper({
10192
10238
  planDir,
@@ -10306,10 +10352,10 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
10306
10352
  applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
10307
10353
  }
10308
10354
  const planAudioPath = join24(planDir, PLAN_AUDIO_RELATIVE_PATH);
10309
- if (audioResult?.hasAudio && existsSync16(audioResult.audioOutputPath)) {
10355
+ if (audioResult?.hasAudio && existsSync17(audioResult.audioOutputPath)) {
10310
10356
  renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
10311
10357
  }
10312
- if (chunksCarryAudio && existsSync16(planAudioPath)) {
10358
+ if (chunksCarryAudio && existsSync17(planAudioPath)) {
10313
10359
  if (options.sliceChunkAudio) {
10314
10360
  stageStarted = Date.now();
10315
10361
  await writeChunkAudioSlices({
@@ -10422,7 +10468,7 @@ async function buildPlanAudio(projectDir, config, workRoot, outputPath, options
10422
10468
  if (mixed.audioError) {
10423
10469
  applyDistributedAudioWarningPolicy(c.job, mixed.audioError, mixed.audioFailures, c.log);
10424
10470
  }
10425
- if (!mixed.hasAudio || !existsSync16(mixed.audioOutputPath)) return { hasAudio: false };
10471
+ if (!mixed.hasAudio || !existsSync17(mixed.audioOutputPath)) return { hasAudio: false };
10426
10472
  renameWithRetry8(mixed.audioOutputPath, outputPath);
10427
10473
  return { hasAudio: true };
10428
10474
  } finally {
@@ -10437,7 +10483,7 @@ import {
10437
10483
  } from "@hyperframes/engine";
10438
10484
  import {
10439
10485
  copyFileSync as copyFileSync8,
10440
- existsSync as existsSync18,
10486
+ existsSync as existsSync19,
10441
10487
  lstatSync as lstatSync2,
10442
10488
  mkdirSync as mkdirSync12,
10443
10489
  mkdtempSync as mkdtempSync4,
@@ -10455,7 +10501,7 @@ import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as r
10455
10501
  // src/services/distributed/planV2Publisher.ts
10456
10502
  import {
10457
10503
  copyFileSync as copyFileSync7,
10458
- existsSync as existsSync17,
10504
+ existsSync as existsSync18,
10459
10505
  linkSync as linkSync2,
10460
10506
  mkdirSync as mkdirSync11,
10461
10507
  mkdtempSync as mkdtempSync3,
@@ -10524,7 +10570,7 @@ var LocalPlanV2ArtifactPublisher = class {
10524
10570
  #linkFile;
10525
10571
  #committed = false;
10526
10572
  constructor(destinationDir, options = {}) {
10527
- if (existsSync17(destinationDir)) {
10573
+ if (existsSync18(destinationDir)) {
10528
10574
  throw new PlanV2IntegrityError(`output directory already exists: ${destinationDir}`);
10529
10575
  }
10530
10576
  this.destinationDir = destinationDir;
@@ -10541,7 +10587,7 @@ var LocalPlanV2ArtifactPublisher = class {
10541
10587
  );
10542
10588
  }
10543
10589
  const destinationPath = planV2BlobPath(this.temporaryDir, digest);
10544
- if (existsSync17(destinationPath)) return;
10590
+ if (existsSync18(destinationPath)) return;
10545
10591
  mkdirSync11(dirname12(destinationPath), { recursive: true });
10546
10592
  const stagingDir = mkdtempSync3(join26(dirname12(destinationPath), ".plan-v2-blob-"));
10547
10593
  const temporaryPath = join26(stagingDir, "blob");
@@ -10559,7 +10605,7 @@ var LocalPlanV2ArtifactPublisher = class {
10559
10605
  }
10560
10606
  async commitManifest(manifestBytes) {
10561
10607
  for (const digest of new Set(manifestDigests(manifestBytes))) {
10562
- if (!existsSync17(planV2BlobPath(this.temporaryDir, digest))) {
10608
+ if (!existsSync18(planV2BlobPath(this.temporaryDir, digest))) {
10563
10609
  throw new PlanV2IntegrityError(
10564
10610
  `cannot commit manifest before referenced blob is durable: ${digest}`
10565
10611
  );
@@ -10638,7 +10684,7 @@ function assertValidExtractionCacheCompleteSentinel(path) {
10638
10684
  }
10639
10685
  function validateExtractionCacheCompleteSentinels(executionPlanDir) {
10640
10686
  const videoRoot = join27(executionPlanDir, "video-frames");
10641
- if (!existsSync18(videoRoot)) return;
10687
+ if (!existsSync19(videoRoot)) return;
10642
10688
  for (const videoEntry of readdirSync7(videoRoot, { withFileTypes: true })) {
10643
10689
  if (!videoEntry.isDirectory()) continue;
10644
10690
  const videoDir = join27(videoRoot, videoEntry.name);
@@ -10739,7 +10785,7 @@ function parsePlanVideosJson2(value) {
10739
10785
  }
10740
10786
  function materializeExtractedVideoDirectories(planDir) {
10741
10787
  const videosPath = join27(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
10742
- if (!existsSync18(videosPath)) return;
10788
+ if (!existsSync19(videosPath)) return;
10743
10789
  const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
10744
10790
  for (const video of videos.extracted) {
10745
10791
  mkdirSync12(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
@@ -10773,9 +10819,9 @@ function parseChunkSlices(value) {
10773
10819
  }
10774
10820
  function buildVideoChunkDependencies(executionPlanDir, dimensions) {
10775
10821
  const videoRoot = join27(executionPlanDir, "video-frames");
10776
- const hasExtractedFrames = existsSync18(videoRoot) && listFiles(videoRoot).length > 0;
10822
+ const hasExtractedFrames = existsSync19(videoRoot) && listFiles(videoRoot).length > 0;
10777
10823
  const videosPath = join27(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
10778
- if (!existsSync18(videosPath)) {
10824
+ if (!existsSync19(videosPath)) {
10779
10825
  return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
10780
10826
  }
10781
10827
  const chunksPath = join27(executionPlanDir, "meta", "chunks.json");
@@ -10832,7 +10878,7 @@ function computeManifestHash(manifest) {
10832
10878
  return sha256Hex(`${PLAN_V2_HASH_PREFIX}${canonicalJsonStringify(manifestPayload(manifest))}`);
10833
10879
  }
10834
10880
  function writeBlob(sourcePath, destinationPath) {
10835
- if (existsSync18(destinationPath)) return;
10881
+ if (existsSync19(destinationPath)) return;
10836
10882
  mkdirSync12(dirname13(destinationPath), { recursive: true });
10837
10883
  const temporaryDir = mkdtempSync4(join27(dirname13(destinationPath), ".plan-v2-blob-"));
10838
10884
  const temporaryPath = join27(temporaryDir, "blob");
@@ -10872,7 +10918,7 @@ async function putTasks(tasks) {
10872
10918
  }
10873
10919
  function buildPlanV2Publication(executionPlanDir, digests) {
10874
10920
  const executionPlanPath = join27(executionPlanDir, "plan.json");
10875
- if (!existsSync18(executionPlanPath)) {
10921
+ if (!existsSync19(executionPlanPath)) {
10876
10922
  throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
10877
10923
  }
10878
10924
  const executionPlanValue = readJsonFile(executionPlanPath, "execution plan.json");
@@ -10952,7 +10998,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
10952
10998
  };
10953
10999
  }
10954
11000
  function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
10955
- if (existsSync18(planV2Dir)) {
11001
+ if (existsSync19(planV2Dir)) {
10956
11002
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
10957
11003
  }
10958
11004
  const publication = buildPlanV2Publication(executionPlanDir);
@@ -11038,7 +11084,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
11038
11084
  }
11039
11085
  }
11040
11086
  async function planV2(projectDir, config, planV2Dir) {
11041
- if (existsSync18(planV2Dir)) {
11087
+ if (existsSync19(planV2Dir)) {
11042
11088
  throw new PlanV2IntegrityError(`output directory already exists: ${planV2Dir}`);
11043
11089
  }
11044
11090
  const publisher = new LocalPlanV2ArtifactPublisher(planV2Dir);
@@ -11192,7 +11238,7 @@ function parsePlanV2Manifest(value) {
11192
11238
  }
11193
11239
  function readPlanV2Manifest(planV2Dir) {
11194
11240
  const manifestPath = join27(planV2Dir, "plan.json");
11195
- if (!existsSync18(manifestPath)) {
11241
+ if (!existsSync19(manifestPath)) {
11196
11242
  throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
11197
11243
  }
11198
11244
  const value = readJsonFile(manifestPath, "v2 manifest");
@@ -11211,7 +11257,7 @@ function listPlanV2ArtifactsForTarget(manifest, target) {
11211
11257
  }
11212
11258
  function verifyBlob(planV2Dir, artifact) {
11213
11259
  const sourcePath = planV2BlobPath(planV2Dir, artifact.sha256);
11214
- if (!existsSync18(sourcePath)) {
11260
+ if (!existsSync19(sourcePath)) {
11215
11261
  throw new PlanV2IntegrityError(`missing content-addressed artifact ${artifact.sha256}`);
11216
11262
  }
11217
11263
  const stats = statSync7(sourcePath);
@@ -11224,7 +11270,7 @@ function verifyBlob(planV2Dir, artifact) {
11224
11270
  return sourcePath;
11225
11271
  }
11226
11272
  function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}) {
11227
- if (existsSync18(destinationDir)) {
11273
+ if (existsSync19(destinationDir)) {
11228
11274
  throw new PlanV2IntegrityError(`materialization destination already exists: ${destinationDir}`);
11229
11275
  }
11230
11276
  const manifest = readPlanV2Manifest(planV2Dir);
@@ -11289,7 +11335,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
11289
11335
  }
11290
11336
  function readValidatedPlanV2Materialization(planDir, expectedTarget) {
11291
11337
  const markerPath = join27(planDir, PLAN_V2_MATERIALIZATION_MARKER);
11292
- if (!existsSync18(markerPath)) return null;
11338
+ if (!existsSync19(markerPath)) return null;
11293
11339
  const marker = readJsonFile(markerPath, "materialization marker");
11294
11340
  if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
11295
11341
  throw new PlanV2IntegrityError("malformed materialization marker");
@@ -11307,7 +11353,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
11307
11353
  for (const artifact of required) {
11308
11354
  if (Object.hasOwn(remoteSources, artifact.path)) continue;
11309
11355
  const path = join27(planDir, ...artifact.path.split("/"));
11310
- if (!existsSync18(path) || statSync7(path).size !== artifact.sizeBytes) {
11356
+ if (!existsSync19(path) || statSync7(path).size !== artifact.sizeBytes) {
11311
11357
  throw new PlanV2IntegrityError(
11312
11358
  `materialized artifact missing or truncated: ${artifact.path}`
11313
11359
  );
@@ -11331,7 +11377,7 @@ import {
11331
11377
  } from "@hyperframes/engine";
11332
11378
  import {
11333
11379
  cpSync as cpSync3,
11334
- existsSync as existsSync19,
11380
+ existsSync as existsSync20,
11335
11381
  mkdirSync as mkdirSync13,
11336
11382
  mkdtempSync as mkdtempSync5,
11337
11383
  readFileSync as readFileSync10,
@@ -11386,7 +11432,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11386
11432
  }
11387
11433
  const format = plan.dimensions.format;
11388
11434
  const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
11389
- if (!existsSync19(dirname14(outputPath))) {
11435
+ if (!existsSync20(dirname14(outputPath))) {
11390
11436
  mkdirSync13(dirname14(outputPath), { recursive: true });
11391
11437
  }
11392
11438
  const workDir = mkdtempSync5(`${outputPath}.assemble-work-`);
@@ -11410,7 +11456,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11410
11456
  try {
11411
11457
  const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
11412
11458
  const finalPath = join28(workDir, `output.${format}`);
11413
- const audio = audioPath !== null && existsSync19(audioPath) ? audioPath : null;
11459
+ const audio = audioPath !== null && existsSync20(audioPath) ? audioPath : null;
11414
11460
  await writeJoined(ctx, videoSources, audio, finalPath);
11415
11461
  renameWithRetry11(finalPath, outputPath);
11416
11462
  log.info("[assemble] stage timings", {
@@ -11428,7 +11474,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11428
11474
  });
11429
11475
  }
11430
11476
  }
11431
- const fileSize = existsSync19(outputPath) ? statSync8(outputPath).size : 0;
11477
+ const fileSize = existsSync20(outputPath) ? statSync8(outputPath).size : 0;
11432
11478
  return {
11433
11479
  ...referenceBackgroundResult6(plan[REFERENCE_BACKGROUND_FIELD4]),
11434
11480
  outputPath,
@@ -11440,13 +11486,13 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11440
11486
  function readAssemblePlan(planDir, chunkPaths) {
11441
11487
  const planJsonPath = join28(planDir, "plan.json");
11442
11488
  const chunksJsonPath = join28(planDir, "meta", "chunks.json");
11443
- if (!existsSync19(planJsonPath)) {
11489
+ if (!existsSync20(planJsonPath)) {
11444
11490
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
11445
11491
  }
11446
11492
  const plan = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
11447
11493
  readPlanProtocolV1(plan, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
11448
11494
  validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
11449
- if (!existsSync19(chunksJsonPath)) {
11495
+ if (!existsSync20(chunksJsonPath)) {
11450
11496
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
11451
11497
  }
11452
11498
  const chunks = JSON.parse(readFileSync10(chunksJsonPath, "utf-8"));
@@ -11461,7 +11507,7 @@ function readAssemblePlan(planDir, chunkPaths) {
11461
11507
  }
11462
11508
  }
11463
11509
  for (const path of chunkPaths.flat()) {
11464
- if (!existsSync19(path)) {
11510
+ if (!existsSync20(path)) {
11465
11511
  throw new Error(`[assemble] chunk path does not exist: ${path}`);
11466
11512
  }
11467
11513
  }
@@ -11600,7 +11646,7 @@ function planFormat(planDir) {
11600
11646
  }
11601
11647
  function lockedAudio(planDir) {
11602
11648
  const encoderJsonPath = join28(planDir, "meta", "encoder.json");
11603
- if (!existsSync19(encoderJsonPath)) return {};
11649
+ if (!existsSync20(encoderJsonPath)) return {};
11604
11650
  return JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
11605
11651
  }
11606
11652
  function readCfrEncoder(planDir, format) {
@@ -11610,7 +11656,7 @@ function readCfrEncoder(planDir, format) {
11610
11656
  );
11611
11657
  }
11612
11658
  const encoderJsonPath = join28(planDir, "meta", "encoder.json");
11613
- if (!existsSync19(encoderJsonPath)) {
11659
+ if (!existsSync20(encoderJsonPath)) {
11614
11660
  throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
11615
11661
  }
11616
11662
  const encoderJson = JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
@@ -11622,7 +11668,7 @@ function readCfrEncoder(planDir, format) {
11622
11668
  return encoderJson;
11623
11669
  }
11624
11670
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
11625
- if (existsSync19(outputPath)) rmSync10(outputPath, { recursive: true, force: true });
11671
+ if (existsSync20(outputPath)) rmSync10(outputPath, { recursive: true, force: true });
11626
11672
  mkdirSync13(outputPath, { recursive: true });
11627
11673
  let globalIdx = 0;
11628
11674
  for (const chunkDir of chunkPaths) {
@@ -11646,7 +11692,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
11646
11692
  `[assemble] png-sequence frame count mismatch: merged ${globalIdx} frames vs plan.totalFrames=${totalFrames}. Using on-disk count.`
11647
11693
  );
11648
11694
  }
11649
- if (audioPath !== null && existsSync19(audioPath)) {
11695
+ if (audioPath !== null && existsSync20(audioPath)) {
11650
11696
  const sidecar = join28(outputPath, MIXED_AUDIO_FILENAME4);
11651
11697
  cpSync3(audioPath, sidecar);
11652
11698
  }
@@ -11667,7 +11713,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
11667
11713
 
11668
11714
  // src/services/distributed/renderChunk.ts
11669
11715
  import { randomBytes } from "node:crypto";
11670
- import { existsSync as existsSync20, mkdirSync as mkdirSync14, readFileSync as readFileSync11, readdirSync as readdirSync9, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
11716
+ import { existsSync as existsSync21, mkdirSync as mkdirSync14, readFileSync as readFileSync11, readdirSync as readdirSync9, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
11671
11717
  import { cpus } from "node:os";
11672
11718
  import { join as join29 } from "node:path";
11673
11719
  import {
@@ -11813,7 +11859,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11813
11859
  const planJsonPath = join29(planDir, "plan.json");
11814
11860
  const encoderJsonPath = join29(planDir, "meta", "encoder.json");
11815
11861
  const chunksJsonPath = join29(planDir, "meta", "chunks.json");
11816
- if (!existsSync20(planJsonPath)) {
11862
+ if (!existsSync21(planJsonPath)) {
11817
11863
  throw new RenderChunkValidationError(
11818
11864
  MISSING_PLAN_ARTIFACT,
11819
11865
  `[renderChunk] planDir is missing required artifact: ${planJsonPath}`
@@ -11829,7 +11875,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11829
11875
  const v2Manifest = v2Materialization?.manifest ?? null;
11830
11876
  const remoteSources = v2Materialization?.remoteSources ?? {};
11831
11877
  for (const required of [encoderJsonPath, chunksJsonPath]) {
11832
- if (!existsSync20(required)) {
11878
+ if (!existsSync21(required)) {
11833
11879
  throw new RenderChunkValidationError(
11834
11880
  MISSING_PLAN_ARTIFACT,
11835
11881
  `[renderChunk] planDir is missing required artifact: ${required}`
@@ -11840,7 +11886,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11840
11886
  const chunks = JSON.parse(readFileSync11(chunksJsonPath, "utf-8"));
11841
11887
  const videosJsonPath = join29(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
11842
11888
  let planVideos = null;
11843
- if (existsSync20(videosJsonPath)) {
11889
+ if (existsSync21(videosJsonPath)) {
11844
11890
  try {
11845
11891
  planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync11(videosJsonPath, "utf-8")));
11846
11892
  } catch (err) {
@@ -11871,7 +11917,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11871
11917
  const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
11872
11918
  const framesInChunk = range.endFrame - range.startFrame;
11873
11919
  const compiledDir = join29(planDir, "compiled");
11874
- if (!existsSync20(compiledDir)) {
11920
+ if (!existsSync21(compiledDir)) {
11875
11921
  throw new RenderChunkValidationError(
11876
11922
  MISSING_PLAN_ARTIFACT,
11877
11923
  `[renderChunk] planDir missing compiled/ directory: ${compiledDir}`
@@ -12121,10 +12167,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
12121
12167
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
12122
12168
  const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
12123
12169
  if (isPngSequence) {
12124
- if (!existsSync20(outputChunkPath)) mkdirSync14(outputChunkPath, { recursive: true });
12170
+ if (!existsSync21(outputChunkPath)) mkdirSync14(outputChunkPath, { recursive: true });
12125
12171
  } else {
12126
12172
  const outDir = join29(outputChunkPath, "..");
12127
- if (!existsSync20(outDir)) mkdirSync14(outDir, { recursive: true });
12173
+ if (!existsSync21(outDir)) mkdirSync14(outDir, { recursive: true });
12128
12174
  }
12129
12175
  const encodeInput = {
12130
12176
  job,