@hyperframes/producer 0.8.197 → 0.8.199

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.
@@ -5,8 +5,8 @@ import {
5
5
  cpSync as cpSync2,
6
6
  existsSync as existsSync15,
7
7
  linkSync,
8
- mkdirSync as mkdirSync10,
9
- rmSync as rmSync9,
8
+ mkdirSync as mkdirSync9,
9
+ rmSync as rmSync8,
10
10
  writeFileSync as writeFileSync6
11
11
  } from "node:fs";
12
12
  import { extname as extname4, isAbsolute as isAbsolute3, join as join21, relative as relative5, sep as sep2 } from "node:path";
@@ -66,10 +66,10 @@ var defaultLogger = createConsoleLogger("info");
66
66
  import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
67
67
  import {
68
68
  existsSync as existsSync10,
69
- mkdirSync as mkdirSync6,
70
- readFileSync as readFileSync6,
69
+ mkdirSync as mkdirSync5,
70
+ readFileSync as readFileSync5,
71
71
  readdirSync as readdirSync3,
72
- rmSync as rmSync7,
72
+ rmSync as rmSync6,
73
73
  statSync as statSync4,
74
74
  writeFileSync as writeFileSync3,
75
75
  copyFileSync as copyFileSync4,
@@ -1297,17 +1297,6 @@ import {
1297
1297
  } from "@hyperframes/engine";
1298
1298
 
1299
1299
  // src/services/render/stages/captureHdrResources.ts
1300
- import {
1301
- closeSync as closeSync2,
1302
- constants as constants2,
1303
- fstatSync as fstatSync2,
1304
- mkdirSync as mkdirSync2,
1305
- mkdtempSync,
1306
- openSync as openSync2,
1307
- readFileSync as readFileSync2,
1308
- rmSync as rmSync2,
1309
- statfsSync
1310
- } from "node:fs";
1311
1300
  import {
1312
1301
  decodePngToRgb48le,
1313
1302
  extractMediaMetadata as extractMediaMetadata2,
@@ -1321,8 +1310,8 @@ import {
1321
1310
  runFfmpeg
1322
1311
  } from "@hyperframes/engine";
1323
1312
  import { fpsToFfmpegArg, fpsToNumber as fpsToNumber4 } from "@hyperframes/core";
1324
- var NO_FOLLOW_FLAG = constants2.O_NOFOLLOW ?? 0;
1325
1313
  var BYTES_PER_MIB = 1024 * 1024;
1314
+ var DEFAULT_HDR_WINDOW_BYTES = 512 * BYTES_PER_MIB;
1326
1315
 
1327
1316
  // src/services/render/stages/captureStreamingStage.ts
1328
1317
  import {
@@ -1476,7 +1465,7 @@ import { suggestMatchingPreset } from "@hyperframes/core";
1476
1465
  // src/services/htmlCompiler.ts
1477
1466
  import { decodedUrlPath } from "@hyperframes/parsers/asset-paths";
1478
1467
  import { createHash as createHash3 } from "node:crypto";
1479
- import { createReadStream as createReadStream2, existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4 } from "fs";
1468
+ import { createReadStream as createReadStream2, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "fs";
1480
1469
  import { join as join5, dirname as dirname4, resolve as resolve5, basename as basename3, relative as relative2 } from "path";
1481
1470
  import { parseHTML as parseHTML4 } from "linkedom";
1482
1471
  import {
@@ -1704,7 +1693,7 @@ import {
1704
1693
 
1705
1694
  // src/services/animatedGifPrep.ts
1706
1695
  import { createHash as createHash2 } from "node:crypto";
1707
- import { copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, rmSync as rmSync3, statSync as statSync2 } from "node:fs";
1696
+ import { copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, statSync as statSync2 } from "node:fs";
1708
1697
  import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve4 } from "node:path";
1709
1698
  import { parseHTML as parseHTML3 } from "linkedom";
1710
1699
  import { parseAnimatedGifMetadata } from "@hyperframes/core";
@@ -1862,10 +1851,10 @@ async function runAnimatedGifTranscode(request) {
1862
1851
  }
1863
1852
  async function ensurePreparedWebm(input) {
1864
1853
  if (!existsSync4(dirname3(input.cachePath))) {
1865
- mkdirSync3(dirname3(input.cachePath), { recursive: true });
1854
+ mkdirSync2(dirname3(input.cachePath), { recursive: true });
1866
1855
  }
1867
1856
  if (!existsSync4(dirname3(input.outputPath))) {
1868
- mkdirSync3(dirname3(input.outputPath), { recursive: true });
1857
+ mkdirSync2(dirname3(input.outputPath), { recursive: true });
1869
1858
  }
1870
1859
  if (!isUsableFile(input.cachePath)) {
1871
1860
  const tmpPath = `${input.cachePath}.tmp-${process.pid}-${Date.now()}`;
@@ -1889,10 +1878,10 @@ async function ensurePreparedWebm(input) {
1889
1878
  if (!isUsableFile(input.cachePath)) {
1890
1879
  renameWithRetry3(tmpPath, input.cachePath);
1891
1880
  } else {
1892
- rmSync3(tmpPath, { force: true });
1881
+ rmSync2(tmpPath, { force: true });
1893
1882
  }
1894
1883
  } catch (error) {
1895
- rmSync3(tmpPath, { force: true });
1884
+ rmSync2(tmpPath, { force: true });
1896
1885
  throw error;
1897
1886
  }
1898
1887
  }
@@ -1962,7 +1951,7 @@ async function prepareAnimatedGifInputs(html, options) {
1962
1951
  if (!hasGifExtension(src)) continue;
1963
1952
  const sourcePath = resolveGifSourcePath(src, options);
1964
1953
  if (!sourcePath) continue;
1965
- const bytes = readFileSync3(sourcePath);
1954
+ const bytes = readFileSync2(sourcePath);
1966
1955
  const metadata = parseAnimatedGifMetadata(bytes);
1967
1956
  if (!metadata?.animated) continue;
1968
1957
  const loop = resolveLoop(metadata, readLoopOverride(img));
@@ -2375,7 +2364,7 @@ function detectShaderTransitionUsage(html) {
2375
2364
  async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, downloadDir, tagName, elementIdentity, log, urlByAbsentLocalPath) {
2376
2365
  let filePath = src;
2377
2366
  if (isHttpUrl(src)) {
2378
- if (!existsSync6(downloadDir)) mkdirSync4(downloadDir, { recursive: true });
2367
+ if (!existsSync6(downloadDir)) mkdirSync3(downloadDir, { recursive: true });
2379
2368
  try {
2380
2369
  filePath = await downloadToTemp(src, downloadDir, void 0, void 0, void 0, {
2381
2370
  onTelemetry: logRemoteDownloadTelemetry
@@ -2958,7 +2947,7 @@ var REMOTE_SOURCE_TAG_RE = /<source\b[^>]*?\bsrc\s*=\s*["'](https?:\/\/[^"']+)["
2958
2947
  var REMOTE_IMG_TAG_RE = /<img\b[^>]*?(?<![\w-])src\s*=\s*["'](https?:\/\/[^"']+)["'][^>]*>/gi;
2959
2948
  async function downloadAndRewriteUrls(urlSet, html, remoteDir, warnLabel, logLabel, extraRewrite) {
2960
2949
  if (urlSet.size === 0) return { html, remoteMediaAssets: /* @__PURE__ */ new Map() };
2961
- if (!existsSync6(remoteDir)) mkdirSync4(remoteDir, { recursive: true });
2950
+ if (!existsSync6(remoteDir)) mkdirSync3(remoteDir, { recursive: true });
2962
2951
  const urlToLocal = /* @__PURE__ */ new Map();
2963
2952
  await Promise.all(
2964
2953
  [...urlSet].map(async (url) => {
@@ -3304,7 +3293,7 @@ function rebaseDirectEntryAssetPaths(html, projectDir, htmlPath) {
3304
3293
  }
3305
3294
  async function compileForRender(projectDir, htmlPath, downloadDir, options = {}) {
3306
3295
  const entryHtml = rebaseDirectEntryAssetPaths(
3307
- readFileSync4(htmlPath, "utf-8"),
3296
+ readFileSync3(htmlPath, "utf-8"),
3308
3297
  projectDir,
3309
3298
  htmlPath
3310
3299
  );
@@ -5073,7 +5062,7 @@ async function appendVideoAudioFromProbe(input) {
5073
5062
 
5074
5063
  // src/services/render/stages/audioStage.ts
5075
5064
  import { join as join10 } from "node:path";
5076
- import { rmSync as rmSync5 } from "node:fs";
5065
+ import { rmSync as rmSync4 } from "node:fs";
5077
5066
  import {
5078
5067
  MIXED_AUDIO_FILENAME,
5079
5068
  audioFailureDiagnostics,
@@ -5082,7 +5071,7 @@ import {
5082
5071
 
5083
5072
  // src/services/render/audioPadTrim.ts
5084
5073
  import { spawn } from "node:child_process";
5085
- import { mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
5074
+ import { mkdtempSync, rmSync as rmSync3 } from "node:fs";
5086
5075
  import { dirname as dirname5, join as join9 } from "node:path";
5087
5076
  import {
5088
5077
  DEFAULT_CONFIG,
@@ -5286,7 +5275,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
5286
5275
  error: `audioPadTrim: failed to materialize ${plan2.operation}: ${err instanceof Error ? err.message : String(err)}`
5287
5276
  };
5288
5277
  } finally {
5289
- for (const path of plan2.cleanupPaths) rmSync4(path, { force: true });
5278
+ for (const path of plan2.cleanupPaths) rmSync3(path, { force: true });
5290
5279
  }
5291
5280
  let loweredDb = 0;
5292
5281
  if (probeTruePeak) {
@@ -5332,7 +5321,7 @@ async function constrainAacTruePeak(input) {
5332
5321
  async function enforceAacTruePeak(input) {
5333
5322
  let scratchDir;
5334
5323
  try {
5335
- scratchDir = mkdtempSync2(join9(dirname5(input.audioPath), ".true-peak-"));
5324
+ scratchDir = mkdtempSync(join9(dirname5(input.audioPath), ".true-peak-"));
5336
5325
  const correctedPath = join9(scratchDir, "audio.m4a");
5337
5326
  const measurements = [];
5338
5327
  let attenuationDb = 0;
@@ -5384,7 +5373,7 @@ async function enforceAacTruePeak(input) {
5384
5373
  )}`
5385
5374
  };
5386
5375
  } finally {
5387
- if (scratchDir) rmSync4(scratchDir, { recursive: true, force: true });
5376
+ if (scratchDir) rmSync3(scratchDir, { recursive: true, force: true });
5388
5377
  }
5389
5378
  }
5390
5379
  function failResult(outputPath, target, source, error) {
@@ -5551,7 +5540,7 @@ async function runAudioStage(input) {
5551
5540
  }
5552
5541
  return { ...result, audioLoweredDb, audioProcessMs: Date.now() - stageStart };
5553
5542
  } finally {
5554
- rmSync5(pcmSourcePath, { force: true });
5543
+ rmSync4(pcmSourcePath, { force: true });
5555
5544
  }
5556
5545
  }
5557
5546
  async function mixAudioForDelivery(input, duration, pcmSourcePath) {
@@ -5648,7 +5637,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
5648
5637
  }
5649
5638
 
5650
5639
  // src/services/render/stages/captureStage.ts
5651
- import { existsSync as existsSync8, readdirSync, statfsSync as statfsSync2 } from "node:fs";
5640
+ import { existsSync as existsSync8, readdirSync, statfsSync } from "node:fs";
5652
5641
  import { join as join11 } from "node:path";
5653
5642
  import {
5654
5643
  classifyCaptureFailure as classifyCaptureFailure2,
@@ -5670,7 +5659,7 @@ function shouldAllowAdaptiveCaptureRetry(workerCount, _explicitlyConfigured) {
5670
5659
  var DISK_PROJECTION_SAMPLE_FRAMES = 10;
5671
5660
  function freeDiskBytesAt(path) {
5672
5661
  try {
5673
- const stat = statfsSync2(path);
5662
+ const stat = statfsSync(path);
5674
5663
  return stat.bavail * stat.bsize;
5675
5664
  } catch {
5676
5665
  return null;
@@ -6030,10 +6019,10 @@ import {
6030
6019
  import {
6031
6020
  copyFileSync as copyFileSync3,
6032
6021
  existsSync as existsSync9,
6033
- mkdirSync as mkdirSync5,
6022
+ mkdirSync as mkdirSync4,
6034
6023
  readdirSync as readdirSync2,
6035
- readFileSync as readFileSync5,
6036
- rmSync as rmSync6,
6024
+ readFileSync as readFileSync4,
6025
+ rmSync as rmSync5,
6037
6026
  statSync as statSync3,
6038
6027
  writeFileSync as writeFileSync2
6039
6028
  } from "node:fs";
@@ -6126,7 +6115,7 @@ async function reencodeWithClearedWholeFrames(argsInput, run, startTime) {
6126
6115
  const error = formatFfmpegError(result.exitCode, result.stderr);
6127
6116
  return gifEncodeFailure(startTime, outputPath, error, result.failureReason);
6128
6117
  }
6129
- const gif = readFileSync5(outputPath);
6118
+ const gif = readFileSync4(outputPath);
6130
6119
  if (!clearGifFramesBeforeNext(gif)) {
6131
6120
  const error = "[FFmpeg] GIF output could not be parsed to clear its frames";
6132
6121
  return gifEncodeFailure(startTime, outputPath, error);
@@ -6159,7 +6148,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
6159
6148
  return gifEncodeFailure(startTime, outputPath, error, result.failureReason);
6160
6149
  }
6161
6150
  }
6162
- if (input.preserveAlpha && gifClearsAfterLeavingFrameInPlace(readFileSync5(outputPath)) !== false) {
6151
+ if (input.preserveAlpha && gifClearsAfterLeavingFrameInPlace(readFileSync4(outputPath)) !== false) {
6163
6152
  const failure = await reencodeWithClearedWholeFrames(argsInput, run, startTime);
6164
6153
  if (failure) return failure;
6165
6154
  }
@@ -6172,7 +6161,7 @@ async function encodeGifFromDir(framesDir, framePattern, outputPath, input) {
6172
6161
  fileSize
6173
6162
  };
6174
6163
  } finally {
6175
- rmSync6(input.palettePath, { force: true });
6164
+ rmSync5(input.palettePath, { force: true });
6176
6165
  }
6177
6166
  }
6178
6167
  function startEncodeProgress(job, stage, onProgress) {
@@ -6322,7 +6311,7 @@ async function runEncodeStage(input) {
6322
6311
  const stage5Start = Date.now();
6323
6312
  if (isPngSequence) {
6324
6313
  const encoded = startEncodeProgress(job, "Writing PNG sequence", onProgress);
6325
- if (!existsSync9(outputPath)) mkdirSync5(outputPath, { recursive: true });
6314
+ if (!existsSync9(outputPath)) mkdirSync4(outputPath, { recursive: true });
6326
6315
  const captured = readdirSync2(framesDir).filter((name) => name.endsWith(".png")).sort();
6327
6316
  if (captured.length === 0) {
6328
6317
  throw new Error(
@@ -6778,7 +6767,7 @@ import {
6778
6767
  // src/services/distributed/shared.ts
6779
6768
  import { execFile as execFileCallback } from "node:child_process";
6780
6769
  import { dirname as dirname8, join as join14 } from "node:path";
6781
- import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
6770
+ import { existsSync as existsSync11, readFileSync as readFileSync6 } from "node:fs";
6782
6771
  import { fileURLToPath as fileURLToPath3 } from "node:url";
6783
6772
  import { promisify as promisify2 } from "node:util";
6784
6773
  import {
@@ -7056,7 +7045,7 @@ function readProducerVersion() {
7056
7045
  const candidate = join14(current, "package.json");
7057
7046
  if (existsSync11(candidate)) {
7058
7047
  try {
7059
- const pkg = JSON.parse(readFileSync7(candidate, "utf-8"));
7048
+ const pkg = JSON.parse(readFileSync6(candidate, "utf-8"));
7060
7049
  if (pkg.name === "@hyperframes/producer" && typeof pkg.version === "string") {
7061
7050
  cachedProducerVersion = pkg.version;
7062
7051
  return pkg.version;
@@ -7309,8 +7298,72 @@ async function measurePlanSecondsPerFrame(input) {
7309
7298
  }
7310
7299
  }
7311
7300
 
7301
+ // src/services/distributed/chunkWeights.ts
7302
+ import { resolveFrameFormat } from "@hyperframes/engine";
7303
+ var PAGE_BASE_WEIGHT = 0.7;
7304
+ var PNG_WEIGHT_FACTOR = 1.5;
7305
+ function isUniformFrameCost(weights) {
7306
+ let lightest = Infinity;
7307
+ let heaviest = 0;
7308
+ for (const weight of weights) {
7309
+ lightest = Math.min(lightest, weight);
7310
+ heaviest = Math.max(heaviest, weight);
7311
+ }
7312
+ return heaviest <= lightest * 1.05;
7313
+ }
7314
+ function planFrameWeights(input) {
7315
+ const { totalFrames, fps } = input;
7316
+ const delta = new Float64Array(totalFrames + 1);
7317
+ const outputPixels = input.width * input.height;
7318
+ const extractedById = new Map(input.extracted.map((entry) => [entry.videoId, entry]));
7319
+ for (const video of input.videos) {
7320
+ const entry = extractedById.get(video.id);
7321
+ if (!entry || video.hidden) continue;
7322
+ const start = Math.max(0, Math.round(video.start * fps));
7323
+ const end = Math.min(totalFrames, Math.round(video.end * fps));
7324
+ if (!(end > start)) continue;
7325
+ const { width, height } = entry.metadata;
7326
+ const factor = resolveFrameFormat(entry.metadata) === "png" ? PNG_WEIGHT_FACTOR : 1;
7327
+ const weight = Math.min(width * height, outputPixels) / 1e6 * factor;
7328
+ delta[start] = delta[start] + weight;
7329
+ delta[end] = delta[end] - weight;
7330
+ }
7331
+ const weights = new Float64Array(totalFrames);
7332
+ let active = 0;
7333
+ for (let frame = 0; frame < totalFrames; frame++) {
7334
+ active += delta[frame];
7335
+ weights[frame] = PAGE_BASE_WEIGHT + active;
7336
+ }
7337
+ return weights;
7338
+ }
7339
+ function buildWeightedChunkSlices(weights, chunkCount, minFrames, maxFrames) {
7340
+ if (isUniformFrameCost(weights)) return null;
7341
+ const totalFrames = weights.length;
7342
+ const total = weights.reduce((sum2, weight) => sum2 + weight, 0);
7343
+ const minSize = Math.max(1, Math.min(minFrames, Math.floor(totalFrames / chunkCount)));
7344
+ const maxSize = Math.max(maxFrames, Math.ceil(totalFrames / chunkCount));
7345
+ const slices = [];
7346
+ let startFrame = 0;
7347
+ let frame = 0;
7348
+ let costBefore = 0;
7349
+ for (let index = 0; index < chunkCount - 1; index++) {
7350
+ const target = (index + 1) * total / chunkCount;
7351
+ while (frame < totalFrames && costBefore + weights[frame] / 2 < target) {
7352
+ costBefore += weights[frame++];
7353
+ }
7354
+ const remaining = chunkCount - index - 1;
7355
+ const low = Math.max(startFrame + minSize, totalFrames - remaining * maxSize);
7356
+ const high = Math.min(startFrame + maxSize, totalFrames - remaining * minSize);
7357
+ const endFrame = Math.min(high, Math.max(low, frame));
7358
+ slices.push({ index, startFrame, endFrame });
7359
+ startFrame = endFrame;
7360
+ }
7361
+ slices.push({ index: chunkCount - 1, startFrame, endFrame: totalFrames });
7362
+ return slices;
7363
+ }
7364
+
7312
7365
  // src/services/render/stages/freezePlan.ts
7313
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync8, readdirSync as readdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
7366
+ import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync7, readdirSync as readdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
7314
7367
  import { join as join17, relative as relative3, resolve as resolve7 } from "node:path";
7315
7368
 
7316
7369
  // src/services/distributed/planProtocol.ts
@@ -7410,7 +7463,7 @@ function readPlanProtocolV1(planJson, capabilities = DISTRIBUTED_RENDER_CAPABILI
7410
7463
 
7411
7464
  // src/services/render/stages/planHash.ts
7412
7465
  import { createHash as createHash4 } from "node:crypto";
7413
- import { closeSync as closeSync3, createReadStream as createReadStream3, openSync as openSync3, readSync } from "node:fs";
7466
+ import { closeSync as closeSync2, createReadStream as createReadStream3, openSync as openSync2, readSync } from "node:fs";
7414
7467
  var PLAN_HASH_SCHEMA_PREFIX = "hyperframes-plan-hash-v1\0";
7415
7468
  var FIELD_DELIMITER = Buffer.from([0]);
7416
7469
  function computePlanHash(input) {
@@ -7468,7 +7521,7 @@ function sha256Hex(bytes) {
7468
7521
  function sha256File(path) {
7469
7522
  const hash = createHash4("sha256");
7470
7523
  const buffer = Buffer.allocUnsafe(1024 * 1024);
7471
- const fd = openSync3(path, "r");
7524
+ const fd = openSync2(path, "r");
7472
7525
  try {
7473
7526
  let bytesRead = 0;
7474
7527
  do {
@@ -7476,7 +7529,7 @@ function sha256File(path) {
7476
7529
  if (bytesRead > 0) hash.update(buffer.subarray(0, bytesRead));
7477
7530
  } while (bytesRead > 0);
7478
7531
  } finally {
7479
- closeSync3(fd);
7532
+ closeSync2(fd);
7480
7533
  }
7481
7534
  return hash.digest("hex");
7482
7535
  }
@@ -7550,7 +7603,7 @@ function collectPlanAssetShas(planDir, digests) {
7550
7603
  const assets = [];
7551
7604
  for (const file of files) {
7552
7605
  if (file.planRelativePath === COMPILED_INDEX_RELATIVE_PATH) {
7553
- compositionHtml = readFileSync8(file.absolutePath);
7606
+ compositionHtml = readFileSync7(file.absolutePath);
7554
7607
  continue;
7555
7608
  }
7556
7609
  if (HASH_EXCLUDED_PLAN_FILES.has(file.planRelativePath)) continue;
@@ -7574,7 +7627,7 @@ function writePlanRemoteFiles(planDir, files) {
7574
7627
  }
7575
7628
  function readPlanRemoteFiles(planDir) {
7576
7629
  const path = join17(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
7577
- return existsSync13(path) ? JSON.parse(readFileSync8(path, "utf-8")) : [];
7630
+ return existsSync13(path) ? JSON.parse(readFileSync7(path, "utf-8")) : [];
7578
7631
  }
7579
7632
  function recomputePlanHashFromPlanDir(planDir, digests) {
7580
7633
  const planJsonPath = join17(planDir, "plan.json");
@@ -7585,8 +7638,8 @@ function recomputePlanHashFromPlanDir(planDir, digests) {
7585
7638
  if (!existsSync13(encoderJsonPath)) {
7586
7639
  throw new Error(`[freezePlan] meta/encoder.json missing: ${encoderJsonPath}`);
7587
7640
  }
7588
- const planJson = JSON.parse(readFileSync8(planJsonPath, "utf-8"));
7589
- const encoderConfigCanonicalJson = readFileSync8(encoderJsonPath, "utf-8");
7641
+ const planJson = JSON.parse(readFileSync7(planJsonPath, "utf-8"));
7642
+ const encoderConfigCanonicalJson = readFileSync7(encoderJsonPath, "utf-8");
7590
7643
  const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
7591
7644
  return computePlanHash({
7592
7645
  compositionHtml,
@@ -7616,7 +7669,7 @@ async function freezePlan(input) {
7616
7669
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
7617
7670
  }
7618
7671
  const metaDir = join17(planDir, "meta");
7619
- if (!existsSync13(metaDir)) mkdirSync7(metaDir, { recursive: true });
7672
+ if (!existsSync13(metaDir)) mkdirSync6(metaDir, { recursive: true });
7620
7673
  writeFileSync4(
7621
7674
  join17(metaDir, "composition.json"),
7622
7675
  `${JSON.stringify(composition, null, 2)}
@@ -7692,13 +7745,13 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
7692
7745
  }
7693
7746
 
7694
7747
  // src/services/distributed/chunkAudio.ts
7695
- import { closeSync as closeSync4, existsSync as existsSync14, ftruncateSync, mkdirSync as mkdirSync9, openSync as openSync4, readFileSync as readFileSync9 } from "node:fs";
7748
+ import { closeSync as closeSync3, existsSync as existsSync14, ftruncateSync, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync8 } from "node:fs";
7696
7749
  import { writeFileSync as writeFileSync5, writeSync } from "node:fs";
7697
7750
  import { join as join19 } from "node:path";
7698
7751
  import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure3, runFfmpeg as runFfmpeg6 } from "@hyperframes/engine";
7699
7752
 
7700
7753
  // src/services/distributed/mp4Stitch.ts
7701
- import { createReadStream as createReadStream4, createWriteStream, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync8 } from "node:fs";
7754
+ import { createReadStream as createReadStream4, createWriteStream, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync7 } from "node:fs";
7702
7755
  import { open } from "node:fs/promises";
7703
7756
  import { renameWithRetry as renameWithRetry5 } from "@hyperframes/engine";
7704
7757
  import { dirname as dirname9, join as join18 } from "node:path";
@@ -8065,8 +8118,8 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
8065
8118
  const sourcePaths = audioPath ? [audioPath, ...chunkPaths] : chunkPaths;
8066
8119
  const layouts = await Promise.all(sourcePaths.map((path) => readMp4Layout(fileRange(path))));
8067
8120
  const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
8068
- mkdirSync8(dirname9(outputPath), { recursive: true });
8069
- const workDir = mkdtempSync3(`${outputPath}.stitch-`);
8121
+ mkdirSync7(dirname9(outputPath), { recursive: true });
8122
+ const workDir = mkdtempSync2(`${outputPath}.stitch-`);
8070
8123
  const out = createWriteStream(join18(workDir, "out.mp4"));
8071
8124
  try {
8072
8125
  out.write(header);
@@ -8076,7 +8129,7 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
8076
8129
  renameWithRetry5(join18(workDir, "out.mp4"), outputPath);
8077
8130
  } finally {
8078
8131
  out.destroy();
8079
- rmSync8(workDir, { recursive: true, force: true });
8132
+ rmSync7(workDir, { recursive: true, force: true });
8080
8133
  }
8081
8134
  }
8082
8135
 
@@ -8165,9 +8218,9 @@ async function writeChunkAudioSlices(input) {
8165
8218
  offset += track.sizes[offsets.length - 1];
8166
8219
  }
8167
8220
  });
8168
- const bytes = readFileSync9(input.audioPath);
8221
+ const bytes = readFileSync8(input.audioPath);
8169
8222
  const layout = { sizeBytes: bytes.length, payloadStart, payloadEnd, partStarts: {} };
8170
- mkdirSync9(join19(input.planDir, SLICE_DIR), { recursive: true });
8223
+ mkdirSync8(join19(input.planDir, SLICE_DIR), { recursive: true });
8171
8224
  input.chunks.forEach((_, index) => {
8172
8225
  const cut = audioCutForChunk(grid, input.chunks, index, input.fps);
8173
8226
  if (!cut) return;
@@ -8184,9 +8237,9 @@ async function writeChunkAudioSlices(input) {
8184
8237
  function chunkAudioSource(planDir, chunkIndex, scratchPath) {
8185
8238
  const layoutPath = join19(planDir, SLICE_LAYOUT);
8186
8239
  if (!existsSync14(layoutPath)) return resolvePlanAudioPath(planDir);
8187
- const layout = JSON.parse(readFileSync9(layoutPath, "utf-8"));
8188
- const frame = readFileSync9(join19(planDir, SLICE_FRAME));
8189
- const fd = openSync4(scratchPath, "w");
8240
+ const layout = JSON.parse(readFileSync8(layoutPath, "utf-8"));
8241
+ const frame = readFileSync8(join19(planDir, SLICE_FRAME));
8242
+ const fd = openSync3(scratchPath, "w");
8190
8243
  try {
8191
8244
  writeSync(fd, frame, 0, layout.payloadStart, 0);
8192
8245
  writeSync(
@@ -8198,12 +8251,12 @@ function chunkAudioSource(planDir, chunkIndex, scratchPath) {
8198
8251
  );
8199
8252
  const start = layout.partStarts[chunkIndex];
8200
8253
  if (start !== void 0) {
8201
- const part = readFileSync9(join19(planDir, chunkAudioSlicePath(chunkIndex)));
8254
+ const part = readFileSync8(join19(planDir, chunkAudioSlicePath(chunkIndex)));
8202
8255
  writeSync(fd, part, 0, part.length, start);
8203
8256
  }
8204
8257
  ftruncateSync(fd, layout.sizeBytes);
8205
8258
  } finally {
8206
- closeSync4(fd);
8259
+ closeSync3(fd);
8207
8260
  }
8208
8261
  return scratchPath;
8209
8262
  }
@@ -8424,6 +8477,7 @@ var PLAN_PROJECT_DIR_SKIP_SEGMENTS = /* @__PURE__ */ new Set([
8424
8477
  var DEFAULT_CHUNK_SIZE = 240;
8425
8478
  var DEFAULT_MAX_PARALLEL_CHUNKS = 16;
8426
8479
  var MIN_CHUNK_SIZE = 10;
8480
+ var MAX_CHUNK_SIZE = 3600;
8427
8481
  var MAX_PARALLEL_CHUNKS_CEILING = 256;
8428
8482
  var ESTIMATED_SECONDS_PER_MEGAPIXEL_FRAME = 0.11;
8429
8483
  var ESTIMATED_CHUNK_OVERHEAD_SECONDS = 60;
@@ -8450,6 +8504,11 @@ var ChunkExceedsWorkerTimeoutError = class extends Error {
8450
8504
  this.name = "ChunkExceedsWorkerTimeoutError";
8451
8505
  }
8452
8506
  };
8507
+ function framesWithinWorkerTimeout(workerTimeoutSeconds, secondsPerFrame) {
8508
+ return Math.floor(
8509
+ (workerTimeoutSeconds * WORKER_TIMEOUT_MARGIN - ESTIMATED_CHUNK_OVERHEAD_SECONDS) / secondsPerFrame
8510
+ );
8511
+ }
8453
8512
  function resolveMaxParallelChunks(config, totalFrames, megapixels, log = defaultLogger, measuredSecondsPerFrame) {
8454
8513
  if (config.maxParallelChunks !== void 0) return config.maxParallelChunks;
8455
8514
  const { workerTimeoutSeconds, workerConcurrency } = config;
@@ -8462,9 +8521,7 @@ function resolveMaxParallelChunks(config, totalFrames, megapixels, log = default
8462
8521
  const minFramesPerChunk = Math.ceil(ESTIMATED_CHUNK_OVERHEAD_SECONDS / secondsPerFrame);
8463
8522
  const wide = Math.max(1, Math.min(wave, Math.floor(totalFrames / minFramesPerChunk)));
8464
8523
  if (workerTimeoutSeconds === void 0) return wide;
8465
- const maxFramesPerChunk = Math.floor(
8466
- (workerTimeoutSeconds * WORKER_TIMEOUT_MARGIN - ESTIMATED_CHUNK_OVERHEAD_SECONDS) / secondsPerFrame
8467
- );
8524
+ const maxFramesPerChunk = framesWithinWorkerTimeout(workerTimeoutSeconds, secondsPerFrame);
8468
8525
  const needed = maxFramesPerChunk < 1 ? Infinity : Math.ceil(totalFrames / maxFramesPerChunk);
8469
8526
  if (needed > MAX_PARALLEL_CHUNKS_CEILING) {
8470
8527
  const framesAtCeiling = Math.ceil(totalFrames / MAX_PARALLEL_CHUNKS_CEILING);
@@ -8584,7 +8641,7 @@ var FREEZE_OWNED_PLAN_FILES = [
8584
8641
  ];
8585
8642
  function removeFreezeOwnedPlanFiles(planDir) {
8586
8643
  for (const relativePath of FREEZE_OWNED_PLAN_FILES) {
8587
- rmSync9(join21(planDir, relativePath), { force: true });
8644
+ rmSync8(join21(planDir, relativePath), { force: true });
8588
8645
  }
8589
8646
  }
8590
8647
  function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
@@ -8596,6 +8653,15 @@ function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
8596
8653
  }
8597
8654
  return slices;
8598
8655
  }
8656
+ function buildPlanChunkSlices(frameWeights, config, chunkCount, effectiveChunkSize, maxFramesPerChunk = Infinity) {
8657
+ const weighted = config.chunkSize === void 0 ? buildWeightedChunkSlices(
8658
+ frameWeights,
8659
+ chunkCount,
8660
+ MIN_CHUNK_SIZE,
8661
+ Math.min(config.targetChunkFrames ?? MAX_CHUNK_SIZE, MAX_CHUNK_SIZE, maxFramesPerChunk)
8662
+ ) : null;
8663
+ return weighted ?? buildChunkSlices(frameWeights.length, chunkCount, effectiveChunkSize);
8664
+ }
8599
8665
  async function readFontSnapshotSha() {
8600
8666
  const module = await import("@hyperframes/core/fonts/embedded-data");
8601
8667
  const data = module.EMBEDDED_FONT_DATA;
@@ -8729,7 +8795,7 @@ function createVideoSourceShipper(input) {
8729
8795
  if (result === null) {
8730
8796
  result = `video-sources/${shipped.size}${extname4(current)}`;
8731
8797
  const destination = join21(input.planDir, ...result.split("/"));
8732
- mkdirSync10(join21(input.planDir, "video-sources"), { recursive: true });
8798
+ mkdirSync9(join21(input.planDir, "video-sources"), { recursive: true });
8733
8799
  try {
8734
8800
  linkSync(current, destination);
8735
8801
  } catch {
@@ -8749,7 +8815,7 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
8749
8815
  useGpu: false,
8750
8816
  browserGpuMode: "software"
8751
8817
  });
8752
- if (!existsSync15(planDir)) mkdirSync10(planDir, { recursive: true });
8818
+ if (!existsSync15(planDir)) mkdirSync9(planDir, { recursive: true });
8753
8819
  const log = config.logger ?? defaultLogger;
8754
8820
  const sizeLimitBytes = options.executionPlanSizeLimitBytes ?? config.planDirSizeLimitBytes ?? PLAN_DIR_SIZE_LIMIT_BYTES;
8755
8821
  const abortSignal = config.abortSignal;
@@ -8783,10 +8849,10 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
8783
8849
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
8784
8850
  }
8785
8851
  const workDir = join21(planDir, ".plan-work");
8786
- rmSync9(workDir, { recursive: true, force: true });
8787
- mkdirSync10(workDir, { recursive: true });
8852
+ rmSync8(workDir, { recursive: true, force: true });
8853
+ mkdirSync9(workDir, { recursive: true });
8788
8854
  const compiledDir = join21(workDir, "compiled");
8789
- mkdirSync10(compiledDir, { recursive: true });
8855
+ mkdirSync9(compiledDir, { recursive: true });
8790
8856
  let stageStarted = Date.now();
8791
8857
  cpSync2(projectDir, compiledDir, {
8792
8858
  recursive: true,
@@ -8990,15 +9056,15 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
8990
9056
  logPlanStage(log, "extract", stageStarted);
8991
9057
  const stagedVideoFrames = join21(compiledDir, "__hyperframes_video_frames");
8992
9058
  const videoFramesDst = join21(planDir, "video-frames");
8993
- if (existsSync15(videoFramesDst)) rmSync9(videoFramesDst, { recursive: true, force: true });
9059
+ if (existsSync15(videoFramesDst)) rmSync8(videoFramesDst, { recursive: true, force: true });
8994
9060
  const videoSourcesDir = join21(planDir, "video-sources");
8995
- rmSync9(videoSourcesDir, { recursive: true, force: true });
9061
+ rmSync8(videoSourcesDir, { recursive: true, force: true });
8996
9062
  if (existsSync15(stagedVideoFrames)) {
8997
9063
  renameWithRetry6(stagedVideoFrames, videoFramesDst);
8998
9064
  } else {
8999
- mkdirSync10(videoFramesDst, { recursive: true });
9065
+ mkdirSync9(videoFramesDst, { recursive: true });
9000
9066
  }
9001
- if (existsSync15(finalCompiledDir)) rmSync9(finalCompiledDir, { recursive: true, force: true });
9067
+ if (existsSync15(finalCompiledDir)) rmSync8(finalCompiledDir, { recursive: true, force: true });
9002
9068
  renameWithRetry6(compiledDir, finalCompiledDir);
9003
9069
  const shipVideoSource = createVideoSourceShipper({
9004
9070
  planDir,
@@ -9028,7 +9094,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
9028
9094
  };
9029
9095
  })
9030
9096
  });
9031
- mkdirSync10(join21(planDir, "meta"), { recursive: true });
9097
+ mkdirSync9(join21(planDir, "meta"), { recursive: true });
9032
9098
  writePlanRemoteFiles(
9033
9099
  planDir,
9034
9100
  remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
@@ -9045,6 +9111,14 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
9045
9111
  const digests = options.digests ?? /* @__PURE__ */ new Map();
9046
9112
  const separateAudio = plansSeparateAudio(config, options);
9047
9113
  const chunksCarryAudio = !separateAudio && carriesChunkAudio(config, options);
9114
+ const frameWeights = planFrameWeights({
9115
+ videos: planVideosJson.videos,
9116
+ extracted: planVideosJson.extracted,
9117
+ totalFrames,
9118
+ fps: config.fps,
9119
+ width,
9120
+ height
9121
+ });
9048
9122
  stageStarted = Date.now();
9049
9123
  const [audioOutcome, overlapOutcome, frameCostOutcome] = await Promise.allSettled([
9050
9124
  separateAudio ? null : mixPlanAudio(c, finalCompiledDir).finally(() => logPlanStage(log, "audio", stageStarted)),
@@ -9095,7 +9169,16 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
9095
9169
  maxParallel,
9096
9170
  config.targetChunkFrames
9097
9171
  );
9098
- const chunks = buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize);
9172
+ const chunks = buildPlanChunkSlices(
9173
+ frameWeights,
9174
+ config,
9175
+ chunkCount,
9176
+ effectiveChunkSize,
9177
+ chunkSizingUsesFrameCost(config) && config.workerTimeoutSeconds !== void 0 ? framesWithinWorkerTimeout(
9178
+ config.workerTimeoutSeconds,
9179
+ estimateFrameSeconds(megapixels, frameCostOutcome.value)
9180
+ ) : void 0
9181
+ );
9099
9182
  const audioResult = audioOutcome.value;
9100
9183
  if (audioResult?.audioError) {
9101
9184
  applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
@@ -9149,7 +9232,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
9149
9232
  format: config.format
9150
9233
  };
9151
9234
  try {
9152
- rmSync9(workDir, { recursive: true, force: true });
9235
+ rmSync8(workDir, { recursive: true, force: true });
9153
9236
  } catch (err) {
9154
9237
  log.warn("[plan] failed to remove temp work dir", {
9155
9238
  workDir,
@@ -9219,7 +9302,7 @@ async function buildPlanAudio(projectDir, config, workRoot, outputPath, options
9219
9302
  renameWithRetry6(mixed.audioOutputPath, outputPath);
9220
9303
  return { hasAudio: true };
9221
9304
  } finally {
9222
- rmSync9(c.workDir, { recursive: true, force: true });
9305
+ rmSync8(c.workDir, { recursive: true, force: true });
9223
9306
  }
9224
9307
  }
9225
9308
  async function plan(projectDir, config, planDir, options = {}) {
@@ -9244,11 +9327,11 @@ import {
9244
9327
  copyFileSync as copyFileSync7,
9245
9328
  existsSync as existsSync17,
9246
9329
  lstatSync as lstatSync2,
9247
- mkdirSync as mkdirSync12,
9248
- mkdtempSync as mkdtempSync5,
9249
- readFileSync as readFileSync10,
9330
+ mkdirSync as mkdirSync11,
9331
+ mkdtempSync as mkdtempSync4,
9332
+ readFileSync as readFileSync9,
9250
9333
  readdirSync as readdirSync7,
9251
- rmSync as rmSync11,
9334
+ rmSync as rmSync10,
9252
9335
  statSync as statSync6,
9253
9336
  writeFileSync as writeFileSync8
9254
9337
  } from "node:fs";
@@ -9262,9 +9345,9 @@ import {
9262
9345
  copyFileSync as copyFileSync6,
9263
9346
  existsSync as existsSync16,
9264
9347
  linkSync as linkSync2,
9265
- mkdirSync as mkdirSync11,
9266
- mkdtempSync as mkdtempSync4,
9267
- rmSync as rmSync10,
9348
+ mkdirSync as mkdirSync10,
9349
+ mkdtempSync as mkdtempSync3,
9350
+ rmSync as rmSync9,
9268
9351
  statSync as statSync5,
9269
9352
  writeFileSync as writeFileSync7
9270
9353
  } from "node:fs";
@@ -9334,8 +9417,8 @@ var LocalPlanV2ArtifactPublisher = class {
9334
9417
  }
9335
9418
  this.destinationDir = destinationDir;
9336
9419
  this.#linkFile = options.linkFile ?? linkSync2;
9337
- mkdirSync11(dirname10(destinationDir), { recursive: true });
9338
- this.temporaryDir = mkdtempSync4(join23(dirname10(destinationDir), ".plan-v2-publish-"));
9420
+ mkdirSync10(dirname10(destinationDir), { recursive: true });
9421
+ this.temporaryDir = mkdtempSync3(join23(dirname10(destinationDir), ".plan-v2-publish-"));
9339
9422
  }
9340
9423
  async putBlob(blob) {
9341
9424
  const digest = assertPlanV2Sha256(blob.sha256, "published blob sha256");
@@ -9347,8 +9430,8 @@ var LocalPlanV2ArtifactPublisher = class {
9347
9430
  }
9348
9431
  const destinationPath = planV2BlobPath(this.temporaryDir, digest);
9349
9432
  if (existsSync16(destinationPath)) return;
9350
- mkdirSync11(dirname10(destinationPath), { recursive: true });
9351
- const stagingDir = mkdtempSync4(join23(dirname10(destinationPath), ".plan-v2-blob-"));
9433
+ mkdirSync10(dirname10(destinationPath), { recursive: true });
9434
+ const stagingDir = mkdtempSync3(join23(dirname10(destinationPath), ".plan-v2-blob-"));
9352
9435
  const temporaryPath = join23(stagingDir, "blob");
9353
9436
  try {
9354
9437
  try {
@@ -9359,7 +9442,7 @@ var LocalPlanV2ArtifactPublisher = class {
9359
9442
  }
9360
9443
  renameWithRetry7(temporaryPath, destinationPath);
9361
9444
  } finally {
9362
- rmSync10(stagingDir, { recursive: true, force: true });
9445
+ rmSync9(stagingDir, { recursive: true, force: true });
9363
9446
  }
9364
9447
  }
9365
9448
  async commitManifest(manifestBytes) {
@@ -9376,7 +9459,7 @@ var LocalPlanV2ArtifactPublisher = class {
9376
9459
  }
9377
9460
  async abort() {
9378
9461
  if (!this.#committed) {
9379
- rmSync10(this.temporaryDir, { recursive: true, force: true });
9462
+ rmSync9(this.temporaryDir, { recursive: true, force: true });
9380
9463
  }
9381
9464
  }
9382
9465
  };
@@ -9395,7 +9478,7 @@ function isNonNegativeIntegerArray(value) {
9395
9478
  return Array.isArray(value) && value.every((item) => typeof item === "number" && Number.isInteger(item) && item >= 0);
9396
9479
  }
9397
9480
  function readJsonFile(path, label) {
9398
- const contents = readFileSync10(path, "utf-8");
9481
+ const contents = readFileSync9(path, "utf-8");
9399
9482
  try {
9400
9483
  const parsed = JSON.parse(contents);
9401
9484
  return parsed;
@@ -9547,7 +9630,7 @@ function materializeExtractedVideoDirectories(planDir) {
9547
9630
  if (!existsSync17(videosPath)) return;
9548
9631
  const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
9549
9632
  for (const video of videos.extracted) {
9550
- mkdirSync12(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
9633
+ mkdirSync11(resolveExtractedVideoOutputDir(planDir, video.videoId), { recursive: true });
9551
9634
  }
9552
9635
  }
9553
9636
  function parseChunkSlices(value) {
@@ -9633,14 +9716,14 @@ function computeManifestHash(manifest) {
9633
9716
  }
9634
9717
  function writeBlob(sourcePath, destinationPath) {
9635
9718
  if (existsSync17(destinationPath)) return;
9636
- mkdirSync12(dirname11(destinationPath), { recursive: true });
9637
- const temporaryDir = mkdtempSync5(join24(dirname11(destinationPath), ".plan-v2-blob-"));
9719
+ mkdirSync11(dirname11(destinationPath), { recursive: true });
9720
+ const temporaryDir = mkdtempSync4(join24(dirname11(destinationPath), ".plan-v2-blob-"));
9638
9721
  const temporaryPath = join24(temporaryDir, "blob");
9639
9722
  try {
9640
9723
  copyFileSync7(sourcePath, temporaryPath);
9641
9724
  renameWithRetry8(temporaryPath, destinationPath);
9642
9725
  } finally {
9643
- rmSync11(temporaryDir, { recursive: true, force: true });
9726
+ rmSync10(temporaryDir, { recursive: true, force: true });
9644
9727
  }
9645
9728
  }
9646
9729
  function publishBlobFor(absolutePath, digests) {
@@ -9759,8 +9842,8 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
9759
9842
  if (publication.storedBlobs.length > 0) {
9760
9843
  throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
9761
9844
  }
9762
- mkdirSync12(dirname11(planV2Dir), { recursive: true });
9763
- const tempDir = mkdtempSync5(join24(dirname11(planV2Dir), ".plan-v2-build-"));
9845
+ mkdirSync11(dirname11(planV2Dir), { recursive: true });
9846
+ const tempDir = mkdtempSync4(join24(dirname11(planV2Dir), ".plan-v2-build-"));
9764
9847
  try {
9765
9848
  for (const blob of publication.blobs) {
9766
9849
  writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
@@ -9773,7 +9856,7 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
9773
9856
  renameWithRetry8(tempDir, planV2Dir);
9774
9857
  return resultFromManifest(planV2Dir, publication.manifest);
9775
9858
  } catch (error) {
9776
- rmSync11(tempDir, { recursive: true, force: true });
9859
+ rmSync10(tempDir, { recursive: true, force: true });
9777
9860
  throw error;
9778
9861
  }
9779
9862
  }
@@ -9813,7 +9896,7 @@ async function publishPlanV2FromV1(executionPlanDir, publisher) {
9813
9896
  return publishPlanV2FromExecutionPlan(executionPlanDir, publisher);
9814
9897
  }
9815
9898
  async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
9816
- const stagingRoot = mkdtempSync5(join24(options.stagingParentDir ?? tmpdir(), ".execution-plan-"));
9899
+ const stagingRoot = mkdtempSync4(join24(options.stagingParentDir ?? tmpdir(), ".execution-plan-"));
9817
9900
  const digests = /* @__PURE__ */ new Map();
9818
9901
  try {
9819
9902
  await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
@@ -9840,7 +9923,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
9840
9923
  }
9841
9924
  throw error;
9842
9925
  } finally {
9843
- rmSync11(stagingRoot, { recursive: true, force: true });
9926
+ rmSync10(stagingRoot, { recursive: true, force: true });
9844
9927
  }
9845
9928
  }
9846
9929
  async function planV2(projectDir, config, planV2Dir) {
@@ -10037,12 +10120,12 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
10037
10120
  artifact,
10038
10121
  sourcePath: verifyBlob(planV2Dir, artifact)
10039
10122
  }));
10040
- mkdirSync12(dirname11(destinationDir), { recursive: true });
10041
- const tempDir = mkdtempSync5(join24(dirname11(destinationDir), ".plan-v2-materialize-"));
10123
+ mkdirSync11(dirname11(destinationDir), { recursive: true });
10124
+ const tempDir = mkdtempSync4(join24(dirname11(destinationDir), ".plan-v2-materialize-"));
10042
10125
  try {
10043
10126
  for (const { artifact, sourcePath } of verified) {
10044
10127
  const destinationPath = join24(tempDir, ...artifact.path.split("/"));
10045
- mkdirSync12(dirname11(destinationPath), { recursive: true });
10128
+ mkdirSync11(dirname11(destinationPath), { recursive: true });
10046
10129
  copyFileSync7(sourcePath, destinationPath);
10047
10130
  }
10048
10131
  if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
@@ -10057,7 +10140,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
10057
10140
  );
10058
10141
  renameWithRetry8(tempDir, destinationDir);
10059
10142
  } catch (error) {
10060
- rmSync11(tempDir, { recursive: true, force: true });
10143
+ rmSync10(tempDir, { recursive: true, force: true });
10061
10144
  throw error;
10062
10145
  }
10063
10146
  return {
@@ -10121,7 +10204,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
10121
10204
  }
10122
10205
 
10123
10206
  // src/services/distributed/planV2Execution.ts
10124
- import { mkdtempSync as mkdtempSync7, rmSync as rmSync14 } from "node:fs";
10207
+ import { mkdtempSync as mkdtempSync6, rmSync as rmSync13 } from "node:fs";
10125
10208
  import { tmpdir as tmpdir2 } from "node:os";
10126
10209
  import { join as join27 } from "node:path";
10127
10210
 
@@ -10129,11 +10212,11 @@ import { join as join27 } from "node:path";
10129
10212
  import {
10130
10213
  cpSync as cpSync3,
10131
10214
  existsSync as existsSync18,
10132
- mkdirSync as mkdirSync13,
10133
- mkdtempSync as mkdtempSync6,
10134
- readFileSync as readFileSync11,
10215
+ mkdirSync as mkdirSync12,
10216
+ mkdtempSync as mkdtempSync5,
10217
+ readFileSync as readFileSync10,
10135
10218
  readdirSync as readdirSync8,
10136
- rmSync as rmSync12,
10219
+ rmSync as rmSync11,
10137
10220
  statSync as statSync7,
10138
10221
  writeFileSync as writeFileSync9
10139
10222
  } from "node:fs";
@@ -10179,9 +10262,9 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
10179
10262
  const format = plan2.dimensions.format;
10180
10263
  const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
10181
10264
  if (!existsSync18(dirname12(outputPath))) {
10182
- mkdirSync13(dirname12(outputPath), { recursive: true });
10265
+ mkdirSync12(dirname12(outputPath), { recursive: true });
10183
10266
  }
10184
- const workDir = mkdtempSync6(`${outputPath}.assemble-work-`);
10267
+ const workDir = mkdtempSync5(`${outputPath}.assemble-work-`);
10185
10268
  const fps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
10186
10269
  const stageMs = {};
10187
10270
  const ctx = {
@@ -10212,7 +10295,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
10212
10295
  });
10213
10296
  } finally {
10214
10297
  try {
10215
- rmSync12(workDir, { recursive: true, force: true });
10298
+ rmSync11(workDir, { recursive: true, force: true });
10216
10299
  } catch (err) {
10217
10300
  log.warn("[assemble] failed to remove work dir", {
10218
10301
  workDir,
@@ -10234,13 +10317,13 @@ function readAssemblePlan(planDir, chunkPaths) {
10234
10317
  if (!existsSync18(planJsonPath)) {
10235
10318
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
10236
10319
  }
10237
- const plan2 = JSON.parse(readFileSync11(planJsonPath, "utf-8"));
10320
+ const plan2 = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
10238
10321
  readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
10239
10322
  validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
10240
10323
  if (!existsSync18(chunksJsonPath)) {
10241
10324
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
10242
10325
  }
10243
- const chunks = JSON.parse(readFileSync11(chunksJsonPath, "utf-8"));
10326
+ const chunks = JSON.parse(readFileSync10(chunksJsonPath, "utf-8"));
10244
10327
  if (chunkPaths.length !== chunks.length) {
10245
10328
  throw new Error(
10246
10329
  `[assemble] chunkPaths length (${chunkPaths.length}) does not match chunks.json length (${chunks.length}). Adapters must pass one path per chunk, ordered by index.`
@@ -10383,13 +10466,13 @@ function stitchesSeparateAudio(planDir) {
10383
10466
  return lockedAudio(planDir).separateAudio === true;
10384
10467
  }
10385
10468
  function planFormat(planDir) {
10386
- const plan2 = JSON.parse(readFileSync11(join25(planDir, "plan.json"), "utf-8"));
10469
+ const plan2 = JSON.parse(readFileSync10(join25(planDir, "plan.json"), "utf-8"));
10387
10470
  return plan2.dimensions.format;
10388
10471
  }
10389
10472
  function lockedAudio(planDir) {
10390
10473
  const encoderJsonPath = join25(planDir, "meta", "encoder.json");
10391
10474
  if (!existsSync18(encoderJsonPath)) return {};
10392
- return JSON.parse(readFileSync11(encoderJsonPath, "utf-8"));
10475
+ return JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
10393
10476
  }
10394
10477
  function readCfrEncoder(planDir, format) {
10395
10478
  if (format !== "mp4") {
@@ -10401,7 +10484,7 @@ function readCfrEncoder(planDir, format) {
10401
10484
  if (!existsSync18(encoderJsonPath)) {
10402
10485
  throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
10403
10486
  }
10404
- const encoderJson = JSON.parse(readFileSync11(encoderJsonPath, "utf-8"));
10487
+ const encoderJson = JSON.parse(readFileSync10(encoderJsonPath, "utf-8"));
10405
10488
  if (encoderJson.encoder === "libx265-software") {
10406
10489
  throw new Error(
10407
10490
  `[assemble] cfr=true is not yet supported with codec: "h265". The cfr re-encode pass uses libx264 and would silently transcode the h265 chunks. Either disable cfr or render with codec: "h264".`
@@ -10410,8 +10493,8 @@ function readCfrEncoder(planDir, format) {
10410
10493
  return encoderJson;
10411
10494
  }
10412
10495
  function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, startTimeMs) {
10413
- if (existsSync18(outputPath)) rmSync12(outputPath, { recursive: true, force: true });
10414
- mkdirSync13(outputPath, { recursive: true });
10496
+ if (existsSync18(outputPath)) rmSync11(outputPath, { recursive: true, force: true });
10497
+ mkdirSync12(outputPath, { recursive: true });
10415
10498
  let globalIdx = 0;
10416
10499
  for (const chunkDir of chunkPaths) {
10417
10500
  if (!statSync7(chunkDir).isDirectory()) {
@@ -10455,7 +10538,7 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
10455
10538
 
10456
10539
  // src/services/distributed/renderChunk.ts
10457
10540
  import { randomBytes } from "node:crypto";
10458
- import { existsSync as existsSync19, mkdirSync as mkdirSync14, readFileSync as readFileSync12, readdirSync as readdirSync9, rmSync as rmSync13, writeFileSync as writeFileSync10 } from "node:fs";
10541
+ import { existsSync as existsSync19, mkdirSync as mkdirSync13, readFileSync as readFileSync11, readdirSync as readdirSync9, rmSync as rmSync12, writeFileSync as writeFileSync10 } from "node:fs";
10459
10542
  import { cpus } from "node:os";
10460
10543
  import { join as join26 } from "node:path";
10461
10544
  import {
@@ -10573,10 +10656,10 @@ async function beginFrameSessionNeedsScreenshotFallback(session, probe = probeBe
10573
10656
  return !await probe(session.page, timeoutMs, probeTick, session.beginFrameIntervalMs);
10574
10657
  }
10575
10658
  function hashChunkOutput(outputPath, kind) {
10576
- if (kind === "file") return sha256Hex(readFileSync12(outputPath));
10659
+ if (kind === "file") return sha256Hex(readFileSync11(outputPath));
10577
10660
  const entries = readdirSync9(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
10578
10661
  const lines = entries.map(
10579
- (name) => `${name}\0${sha256Hex(readFileSync12(join26(outputPath, name)))}`
10662
+ (name) => `${name}\0${sha256Hex(readFileSync11(join26(outputPath, name)))}`
10580
10663
  );
10581
10664
  return sha256Hex(lines.join("\0"));
10582
10665
  }
@@ -10602,7 +10685,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10602
10685
  `[renderChunk] planDir is missing required artifact: ${planJsonPath}`
10603
10686
  );
10604
10687
  }
10605
- const plan2 = JSON.parse(readFileSync12(planJsonPath, "utf-8"));
10688
+ const plan2 = JSON.parse(readFileSync11(planJsonPath, "utf-8"));
10606
10689
  readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.chunk);
10607
10690
  const planHashStarted = Date.now();
10608
10691
  const v2Materialization = readValidatedPlanV2Materialization(planDir, {
@@ -10619,13 +10702,13 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10619
10702
  );
10620
10703
  }
10621
10704
  }
10622
- const encoder = JSON.parse(readFileSync12(encoderJsonPath, "utf-8"));
10623
- const chunks = JSON.parse(readFileSync12(chunksJsonPath, "utf-8"));
10705
+ const encoder = JSON.parse(readFileSync11(encoderJsonPath, "utf-8"));
10706
+ const chunks = JSON.parse(readFileSync11(chunksJsonPath, "utf-8"));
10624
10707
  const videosJsonPath = join26(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
10625
10708
  let planVideos = null;
10626
10709
  if (existsSync19(videosJsonPath)) {
10627
10710
  try {
10628
- planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync12(videosJsonPath, "utf-8")));
10711
+ planVideos = validatePlanVideosForChunk(JSON.parse(readFileSync11(videosJsonPath, "utf-8")));
10629
10712
  } catch (err) {
10630
10713
  if (err instanceof RenderChunkValidationError) throw err;
10631
10714
  throw new RenderChunkValidationError(
@@ -10710,9 +10793,9 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10710
10793
  forceScreenshotExplicitlyOptedOut: !encoder.forceScreenshot
10711
10794
  };
10712
10795
  const workDir = `${outputChunkPath}.work.${process.pid}.${randomBytes(4).toString("hex")}`;
10713
- mkdirSync14(workDir, { recursive: true });
10796
+ mkdirSync13(workDir, { recursive: true });
10714
10797
  const framesDir = join26(workDir, "captured-frames");
10715
- mkdirSync14(framesDir, { recursive: true });
10798
+ mkdirSync13(framesDir, { recursive: true });
10716
10799
  const videoFramesDir = `${workDir}.video-frames`;
10717
10800
  const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
10718
10801
  const chunkFps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
@@ -10736,7 +10819,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10736
10819
  dimensions: plan2.dimensions,
10737
10820
  encoder,
10738
10821
  videoCount: planVideos?.videos.length ?? 0,
10739
- html: readFileSync12(join26(compiledDir, "index.html"), "utf-8"),
10822
+ html: readFileSync11(join26(compiledDir, "index.html"), "utf-8"),
10740
10823
  // The plan ships a deferred source only to chunks that show it; don't wait on the rest.
10741
10824
  skipReadinessVideoIds: deferredVideos.filter(
10742
10825
  (video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
@@ -10859,10 +10942,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10859
10942
  const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
10860
10943
  const videoOnlyPath = encoder.chunksCarryAudio ? `${outputChunkPath}.video.mp4` : outputChunkPath;
10861
10944
  if (isPngSequence) {
10862
- if (!existsSync19(outputChunkPath)) mkdirSync14(outputChunkPath, { recursive: true });
10945
+ if (!existsSync19(outputChunkPath)) mkdirSync13(outputChunkPath, { recursive: true });
10863
10946
  } else {
10864
10947
  const outDir = join26(outputChunkPath, "..");
10865
- if (!existsSync19(outDir)) mkdirSync14(outDir, { recursive: true });
10948
+ if (!existsSync19(outDir)) mkdirSync13(outDir, { recursive: true });
10866
10949
  }
10867
10950
  const encodeInput = {
10868
10951
  job,
@@ -10965,8 +11048,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10965
11048
  return observedChunkCaptureMode(capturePerfs);
10966
11049
  },
10967
11050
  resetForScreenshotRetry: () => {
10968
- rmSync13(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
10969
- mkdirSync14(framesDir, { recursive: true });
11051
+ rmSync12(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
11052
+ mkdirSync13(framesDir, { recursive: true });
10970
11053
  capturePerfs.length = 0;
10971
11054
  captureAttempts.length = 0;
10972
11055
  job.framesRendered = 0;
@@ -11008,8 +11091,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11008
11091
  fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
11009
11092
  timeoutMs: cfg.ffmpegProcessTimeout
11010
11093
  });
11011
- rmSync13(videoOnlyPath, { force: true });
11012
- rmSync13(audioScratchPath, { force: true });
11094
+ rmSync12(videoOnlyPath, { force: true });
11095
+ rmSync12(audioScratchPath, { force: true });
11013
11096
  }
11014
11097
  encodeStageMs = Date.now() - encodeStarted;
11015
11098
  } finally {
@@ -11057,8 +11140,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11057
11140
  writeFileSync10(perfPath, `${JSON.stringify(perfPayload, null, 2)}
11058
11141
  `, "utf-8");
11059
11142
  try {
11060
- rmSync13(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
11061
- rmSync13(videoFramesDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
11143
+ rmSync12(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
11144
+ rmSync12(videoFramesDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
11062
11145
  } catch (err) {
11063
11146
  log.warn("[renderChunk] failed to remove work dir", {
11064
11147
  workDir,
@@ -11087,17 +11170,17 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11087
11170
 
11088
11171
  // src/services/distributed/planV2Execution.ts
11089
11172
  async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
11090
- const workRoot = mkdtempSync7(join27(tmpdir2(), "hf-plan-v2-chunk-"));
11173
+ const workRoot = mkdtempSync6(join27(tmpdir2(), "hf-plan-v2-chunk-"));
11091
11174
  const materializedPlanDir = join27(workRoot, "plan");
11092
11175
  try {
11093
11176
  materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
11094
11177
  return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
11095
11178
  } finally {
11096
- rmSync14(workRoot, { recursive: true, force: true });
11179
+ rmSync13(workRoot, { recursive: true, force: true });
11097
11180
  }
11098
11181
  }
11099
11182
  async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
11100
- const workRoot = mkdtempSync7(join27(tmpdir2(), "hf-plan-v2-assembler-"));
11183
+ const workRoot = mkdtempSync6(join27(tmpdir2(), "hf-plan-v2-assembler-"));
11101
11184
  const materializedPlanDir = join27(workRoot, "plan");
11102
11185
  try {
11103
11186
  const materialized = materializePlanV2Target(
@@ -11113,7 +11196,7 @@ async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
11113
11196
  options
11114
11197
  );
11115
11198
  } finally {
11116
- rmSync14(workRoot, { recursive: true, force: true });
11199
+ rmSync13(workRoot, { recursive: true, force: true });
11117
11200
  }
11118
11201
  }
11119
11202
 
@@ -11147,7 +11230,6 @@ var ALLOWED_RUNTIME_CAPS = ["lambda", "temporal", "cloud-run-job", "k8s-job", "n
11147
11230
  var ALLOWED_HDR_MODES = ["auto", "force-sdr"];
11148
11231
  var MAX_DIMENSION = 7680;
11149
11232
  var MIN_DIMENSION = 16;
11150
- var MAX_CHUNK_SIZE = 3600;
11151
11233
  function validateDistributedRenderConfig(config) {
11152
11234
  if (config === null || typeof config !== "object") {
11153
11235
  throw new InvalidConfigError("config", "must be an object");
@@ -11363,7 +11445,7 @@ function validateIntDimension(field, value) {
11363
11445
  }
11364
11446
 
11365
11447
  // src/services/distributed/projectHash.ts
11366
- import { closeSync as closeSync5, openSync as openSync5, readdirSync as readdirSync10, readSync as readSync3, realpathSync as realpathSync2, statSync as statSync8 } from "node:fs";
11448
+ import { closeSync as closeSync4, openSync as openSync4, readdirSync as readdirSync10, readSync as readSync3, realpathSync as realpathSync2, statSync as statSync8 } from "node:fs";
11367
11449
  import { createHash as createHash6 } from "node:crypto";
11368
11450
  import { join as join28 } from "node:path";
11369
11451
  var SITE_ID_SCHEME = "site-v2\0";
@@ -11404,14 +11486,14 @@ function hashProjectDir(projectDir, files = listSiteFiles(projectDir)) {
11404
11486
  for (const rel of files) {
11405
11487
  hash.update(rel);
11406
11488
  hash.update("\0");
11407
- const fd = openSync5(join28(projectDir, rel), "r");
11489
+ const fd = openSync4(join28(projectDir, rel), "r");
11408
11490
  try {
11409
11491
  let read;
11410
11492
  while ((read = readSync3(fd, chunk, 0, chunk.length, null)) > 0) {
11411
11493
  hash.update(chunk.subarray(0, read));
11412
11494
  }
11413
11495
  } finally {
11414
- closeSync5(fd);
11496
+ closeSync4(fd);
11415
11497
  }
11416
11498
  }
11417
11499
  return hash.digest("hex").slice(0, 16);