@hyperframes/producer 0.9.26 → 0.9.28-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ import {
67
67
  referenceBackgroundResult,
68
68
  createReferenceBackgroundRecorder
69
69
  } from "@hyperframes/engine";
70
- import { join as join31, dirname as dirname13, resolve as resolve8 } from "path";
70
+ import { join as join30, dirname as dirname13, resolve as resolve8 } from "path";
71
71
  import { totalmem as totalmem2 } from "node:os";
72
72
  import { randomUUID } from "crypto";
73
73
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -1557,7 +1557,7 @@ var RenderExecutionContext = class {
1557
1557
 
1558
1558
  // src/services/render/artifactTransaction.ts
1559
1559
  import { closeSync as closeSync2, existsSync as existsSync6, fstatSync as fstatSync2, openSync as openSync2, readSync, readdirSync as readdirSync2, rmSync as rmSync3 } from "node:fs";
1560
- import { basename as basename3, dirname as dirname4, extname as extname2, join as join5, resolve as resolve4 } from "node:path";
1560
+ import { basename as basename4, dirname as dirname4, extname as extname2, join as join5, resolve as resolve4 } from "node:path";
1561
1561
  import { HLS_MASTER_PLAYLIST, HLS_VIDEO_PLAYLIST, renameWithRetry } from "@hyperframes/engine";
1562
1562
 
1563
1563
  // src/utils/ffprobe.ts
@@ -1571,7 +1571,6 @@ import {
1571
1571
  import {
1572
1572
  existsSync as existsSync5,
1573
1573
  lstatSync,
1574
- mkdtempSync,
1575
1574
  readFileSync as readFileSync2,
1576
1575
  readdirSync,
1577
1576
  readlinkSync,
@@ -1579,8 +1578,9 @@ import {
1579
1578
  writeFileSync as writeFileSync2
1580
1579
  } from "node:fs";
1581
1580
  import { hostname, uptime } from "node:os";
1582
- import { dirname as dirname3, join as join4 } from "node:path";
1581
+ import { basename as basename3, dirname as dirname3, join as join4 } from "node:path";
1583
1582
  import { RENDER_TEMP_DIR } from "@hyperframes/core/project-folders";
1583
+ import { createStagingDir } from "@hyperframes/core/atomic-file";
1584
1584
  var OWNER_FILE = "owner.json";
1585
1585
  var TRANSACTION_BACKUP = "backup";
1586
1586
  var RENDER_JOB_DIR = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/;
@@ -1600,7 +1600,7 @@ function pidScope() {
1600
1600
  };
1601
1601
  }
1602
1602
  function createOwnedRenderDir(prefix) {
1603
- const dir = mkdtempSync(prefix);
1603
+ const dir = createStagingDir(dirname3(prefix), basename3(prefix));
1604
1604
  const owner = { pid: process.pid, ...pidScope() };
1605
1605
  writeFileSync2(join4(dir, OWNER_FILE), JSON.stringify(owner));
1606
1606
  return dir;
@@ -1710,7 +1710,7 @@ function buildArtifactExpectation(input) {
1710
1710
  function createSiblingTransactionDirectory(destination) {
1711
1711
  const parent = dirname4(destination);
1712
1712
  const extension = extname2(destination);
1713
- const stem = extension ? basename3(destination, extension) : basename3(destination);
1713
+ const stem = extension ? basename4(destination, extension) : basename4(destination);
1714
1714
  return createOwnedRenderDir(join5(parent, `.${stem}.hf-transaction-`));
1715
1715
  }
1716
1716
  function assertReadableNonEmptyFile(path) {
@@ -1786,7 +1786,7 @@ var ArtifactTransaction = class {
1786
1786
  this.logger = logger;
1787
1787
  this.destinationPath = resolve4(destinationPath);
1788
1788
  this.transactionDirectory = createSiblingTransactionDirectory(this.destinationPath);
1789
- this.stagingPath = join5(this.transactionDirectory, basename3(this.destinationPath));
1789
+ this.stagingPath = join5(this.transactionDirectory, basename4(this.destinationPath));
1790
1790
  this.backupPath = join5(this.transactionDirectory, TRANSACTION_BACKUP);
1791
1791
  this.durationProbe = durationProbe;
1792
1792
  }
@@ -1842,7 +1842,7 @@ var ArtifactTransaction = class {
1842
1842
  }
1843
1843
  if (expected.expectedFrames === void 0) return;
1844
1844
  const frameCount = files.filter(
1845
- (file) => dirname4(file) === this.stagingPath && /^frame_\d+\.png$/.test(basename3(file))
1845
+ (file) => dirname4(file) === this.stagingPath && /^frame_\d+\.png$/.test(basename4(file))
1846
1846
  ).length;
1847
1847
  if (frameCount === 0) {
1848
1848
  throw new Error(
@@ -2081,7 +2081,7 @@ function replanAfterFailure(plan2, failure) {
2081
2081
 
2082
2082
  // src/services/render/stages/captureSegmentedStage.ts
2083
2083
  import { existsSync as existsSync7, mkdirSync as mkdirSync3, rmSync as rmSync6, statSync as statSync3 } from "node:fs";
2084
- import { join as join10 } from "node:path";
2084
+ import { join as join9 } from "node:path";
2085
2085
  import {
2086
2086
  captureFrameToBuffer as captureFrameToBuffer2,
2087
2087
  closeCaptureSession as closeCaptureSession2,
@@ -2974,8 +2974,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
2974
2974
  }
2975
2975
 
2976
2976
  // src/services/render/stages/captureHdrResources.ts
2977
- import { mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, rmSync as rmSync5, statSync as statSync2, statfsSync } from "node:fs";
2978
- import { join as join8 } from "node:path";
2977
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync5, statSync as statSync2, statfsSync } from "node:fs";
2979
2978
  import {
2980
2979
  decodePngToRgb48le,
2981
2980
  extractMediaMetadata as extractMediaMetadata2,
@@ -3075,6 +3074,7 @@ function createHdrFrameWindows(opts) {
3075
3074
  }
3076
3075
 
3077
3076
  // src/services/render/stages/captureHdrResources.ts
3077
+ import { createStagingDir as createStagingDir2 } from "@hyperframes/core/atomic-file";
3078
3078
  function tempDirSafePrefix(id) {
3079
3079
  const safe = id.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 80);
3080
3080
  return safe || "video";
@@ -3332,7 +3332,7 @@ async function extractHdrVideoFrames(args) {
3332
3332
  if (!video || !planned) continue;
3333
3333
  const { window: window2, metadata } = planned;
3334
3334
  mkdirSync2(framesDir, { recursive: true });
3335
- const frameDir = mkdtempSync2(join8(framesDir, `hdr_${tempDirSafePrefix(videoId)}-`));
3335
+ const frameDir = createStagingDir2(framesDir, `hdr_${tempDirSafePrefix(videoId)}-`);
3336
3336
  createdFrameDirs.add(frameDir);
3337
3337
  const dims = prep.hdrExtractionDims.get(videoId) ?? { width, height };
3338
3338
  const frameSize = dims.width * dims.height * 6;
@@ -3787,7 +3787,7 @@ function isTargetLossError(error) {
3787
3787
  // src/services/render/stages/captureStreamingStage.ts
3788
3788
  import { mkdtemp, writeFile } from "node:fs/promises";
3789
3789
  import { tmpdir } from "node:os";
3790
- import { join as join9 } from "node:path";
3790
+ import { join as join8 } from "node:path";
3791
3791
  import {
3792
3792
  DrawElementVerificationError,
3793
3793
  captureFrameToBuffer,
@@ -4010,11 +4010,11 @@ async function verifyDrawElementSample(session, idx, buf, ctx) {
4010
4010
  return;
4011
4011
  }
4012
4012
  if (db < verifyMinDb) {
4013
- const dumpDir = await mkdtemp(join9(tmpdir(), "hf-de-verify-fail-")).catch(() => null);
4013
+ const dumpDir = await mkdtemp(join8(tmpdir(), "hf-de-verify-fail-")).catch(() => null);
4014
4014
  if (dumpDir) {
4015
4015
  await Promise.all([
4016
- writeFile(join9(dumpDir, `frame-${idx}-de.jpg`), buf),
4017
- writeFile(join9(dumpDir, `frame-${idx}-truth.jpg`), truth)
4016
+ writeFile(join8(dumpDir, `frame-${idx}-de.jpg`), buf),
4017
+ writeFile(join8(dumpDir, `frame-${idx}-truth.jpg`), truth)
4018
4018
  ]).catch(() => {
4019
4019
  });
4020
4020
  }
@@ -4585,7 +4585,7 @@ async function runCaptureStreamingStage(input) {
4585
4585
 
4586
4586
  // src/services/render/stages/captureSegmentedStage.ts
4587
4587
  function segmentOutputPath(segmentDir, index) {
4588
- return join10(segmentDir, `segment_${String(index).padStart(5, "0")}.mp4`);
4588
+ return join9(segmentDir, `segment_${String(index).padStart(5, "0")}.mp4`);
4589
4589
  }
4590
4590
  function segmentEncoderOptions(base, segment) {
4591
4591
  return {
@@ -4913,7 +4913,7 @@ async function runCaptureSegmentedStage(input) {
4913
4913
  const { log, dedupPerfs, assertNotAborted } = input;
4914
4914
  const deps = { ...DEFAULT_DEPS, ...input.deps };
4915
4915
  const segments = planSegments(input.totalFrames, input.segmentFrames);
4916
- const segmentDir = input.segmentDir ?? join10(input.workDir, "segments");
4916
+ const segmentDir = input.segmentDir ?? join9(input.workDir, "segments");
4917
4917
  mkdirSync3(segmentDir, { recursive: true });
4918
4918
  const skip = input.completedSegments ?? /* @__PURE__ */ new Set();
4919
4919
  const pending = segments.filter((s) => !skip.has(s.index));
@@ -5060,7 +5060,7 @@ function startRenderEtaGuard(options) {
5060
5060
  }
5061
5061
 
5062
5062
  // src/services/render/captureCost.ts
5063
- import { join as join11 } from "node:path";
5063
+ import { join as join10 } from "node:path";
5064
5064
  import { fpsToNumber as fpsToNumber4 } from "@hyperframes/core";
5065
5065
  import {
5066
5066
  calculateOptimalWorkers,
@@ -5306,7 +5306,7 @@ async function runCaptureCalibration(input) {
5306
5306
  });
5307
5307
  let calibration;
5308
5308
  try {
5309
- calibration = await runOneCalibration(join11(workDir, "capture-calibration"), calibrationCfg);
5309
+ calibration = await runOneCalibration(join10(workDir, "capture-calibration"), calibrationCfg);
5310
5310
  } catch (error) {
5311
5311
  const shouldFallback = !forceScreenshot && shouldFallbackToScreenshotAfterCalibrationError(error);
5312
5312
  if (!shouldFallback) {
@@ -5340,7 +5340,7 @@ async function runCaptureCalibration(input) {
5340
5340
  const screenshotCfg = createCaptureCalibrationConfig({ ...cfg, forceScreenshot: true });
5341
5341
  try {
5342
5342
  calibration = await runOneCalibration(
5343
- join11(workDir, "capture-calibration-screenshot"),
5343
+ join10(workDir, "capture-calibration-screenshot"),
5344
5344
  screenshotCfg
5345
5345
  );
5346
5346
  } catch (fallbackError) {
@@ -5405,7 +5405,7 @@ function checkPageNeverReady(input) {
5405
5405
 
5406
5406
  // src/services/render/deferredVideoFrames.ts
5407
5407
  import { mkdirSync as mkdirSync4, rmSync as rmSync7 } from "node:fs";
5408
- import { dirname as dirname5, join as join12 } from "node:path";
5408
+ import { dirname as dirname5, join as join11 } from "node:path";
5409
5409
  import {
5410
5410
  createFrameLookupTable,
5411
5411
  extractVideoFramesRange,
@@ -5449,7 +5449,7 @@ async function extractDeferredFrames(input) {
5449
5449
  const shown = shownDeferredFrameIndexes(input, input.frames, input.fps);
5450
5450
  return Promise.all(
5451
5451
  deferred.map(async (video) => {
5452
- const outputDir = join12(input.outputRoot, video.videoId);
5452
+ const outputDir = join11(input.outputRoot, video.videoId);
5453
5453
  const indexes = [...shown.get(video.videoId) ?? []].sort((a, b) => a - b);
5454
5454
  if (indexes.length === 0) {
5455
5455
  return { ...video, outputDir, framePaths: /* @__PURE__ */ new Map(), ownedByLookup: false };
@@ -5518,13 +5518,13 @@ async function extractAllDeferredFrames(extracted, input) {
5518
5518
 
5519
5519
  // src/services/render/segmentVideoFrames.ts
5520
5520
  import { mkdirSync as mkdirSync5, rmSync as rmSync8 } from "node:fs";
5521
- import { join as join13 } from "node:path";
5521
+ import { join as join12 } from "node:path";
5522
5522
  import {
5523
5523
  createFrameLookupTable as createFrameLookupTable2,
5524
5524
  createVideoFrameInjector
5525
5525
  } from "@hyperframes/engine";
5526
5526
  function segmentFramesDir(rootDir, index) {
5527
- return join13(rootDir, "segment-frames", `segment_${String(index).padStart(5, "0")}`);
5527
+ return join12(rootDir, "segment-frames", `segment_${String(index).padStart(5, "0")}`);
5528
5528
  }
5529
5529
  function createSegmentVideoFrames(input) {
5530
5530
  const extractFrames = input.extractFrames ?? extractDeferredFrames;
@@ -5554,7 +5554,7 @@ function createSegmentVideoFrames(input) {
5554
5554
  let onDemandCalls = 0;
5555
5555
  const onDemandHook = () => Object.assign(
5556
5556
  async (page, time, heldVideoTime) => {
5557
- const dir = join13(
5557
+ const dir = join12(
5558
5558
  input.rootDir,
5559
5559
  "segment-frames",
5560
5560
  `on-demand_${String(onDemandCalls++).padStart(5, "0")}`
@@ -5571,7 +5571,7 @@ function createSegmentVideoFrames(input) {
5571
5571
  );
5572
5572
  return {
5573
5573
  async forFrames(frames, name) {
5574
- const dir = join13(input.rootDir, "segment-frames", name);
5574
+ const dir = join12(input.rootDir, "segment-frames", name);
5575
5575
  const release = () => rmSync8(dir, { recursive: true, force: true });
5576
5576
  try {
5577
5577
  release();
@@ -5624,7 +5624,7 @@ function createSegmentVideoFrames(input) {
5624
5624
 
5625
5625
  // src/services/render/videoFrameWindow.ts
5626
5626
  import { readdirSync as readdirSync3, statSync as statSync4 } from "node:fs";
5627
- import { join as join14 } from "node:path";
5627
+ import { join as join13 } from "node:path";
5628
5628
  function shouldWindowVideoFrames(args) {
5629
5629
  return args.segmented && args.env.HF_VIDEO_FRAME_WINDOW?.trim().toLowerCase() === "true";
5630
5630
  }
@@ -5637,7 +5637,7 @@ function directoryBytes(path) {
5637
5637
  return 0;
5638
5638
  }
5639
5639
  for (const entry of entries) {
5640
- const child3 = join14(path, entry.name);
5640
+ const child3 = join13(path, entry.name);
5641
5641
  try {
5642
5642
  bytes += entry.isDirectory() ? directoryBytes(child3) : statSync4(child3).size;
5643
5643
  } catch {
@@ -5655,7 +5655,7 @@ function trackSegmentFramePeak(frames, rootDir, onPeak) {
5655
5655
  ...worker,
5656
5656
  async prepare(segment) {
5657
5657
  await worker.prepare(segment);
5658
- const held = directoryBytes(join14(rootDir, "segment-frames"));
5658
+ const held = directoryBytes(join13(rootDir, "segment-frames"));
5659
5659
  if (held > peak) {
5660
5660
  peak = held;
5661
5661
  onPeak(peak);
@@ -5669,7 +5669,7 @@ function trackSegmentFramePeak(frames, rootDir, onPeak) {
5669
5669
  // src/services/render/segmentManifest.ts
5670
5670
  import { createHash as createHash2 } from "node:crypto";
5671
5671
  import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync4, statSync as statSync5, writeFileSync as writeFileSync3 } from "node:fs";
5672
- import { join as join15 } from "node:path";
5672
+ import { join as join14 } from "node:path";
5673
5673
  import { renameWithRetry as renameWithRetry2 } from "@hyperframes/engine";
5674
5674
  var MANIFEST_FILENAME = "segments.json";
5675
5675
  function computeSegmentPlanHash(input) {
@@ -5697,7 +5697,7 @@ function computeSegmentPlanHash(input) {
5697
5697
  return createHash2("sha256").update(ordered.join(" ")).digest("hex").slice(0, 16);
5698
5698
  }
5699
5699
  function segmentDirFor(projectRendersDir, planHash) {
5700
- return join15(projectRendersDir, ".hf-segments", planHash);
5700
+ return join14(projectRendersDir, ".hf-segments", planHash);
5701
5701
  }
5702
5702
  function hasNumber(value, key) {
5703
5703
  return key in value && typeof Reflect.get(value, key) === "number";
@@ -5715,7 +5715,7 @@ function isManifest(value) {
5715
5715
  return Reflect.get(value, "version") === 1 && hasString(value, "planHash") && hasNumber(value, "totalFrames") && hasNumber(value, "segmentFrames") && Array.isArray(completed) && completed.every(isEntry);
5716
5716
  }
5717
5717
  function readSegmentManifest(segmentDir) {
5718
- const path = join15(segmentDir, MANIFEST_FILENAME);
5718
+ const path = join14(segmentDir, MANIFEST_FILENAME);
5719
5719
  if (!existsSync8(path)) return null;
5720
5720
  try {
5721
5721
  const parsed = JSON.parse(readFileSync4(path, "utf-8"));
@@ -5726,9 +5726,9 @@ function readSegmentManifest(segmentDir) {
5726
5726
  }
5727
5727
  function writeSegmentManifest(segmentDir, manifest) {
5728
5728
  mkdirSync6(segmentDir, { recursive: true });
5729
- const tmp = join15(segmentDir, `${MANIFEST_FILENAME}.${process.pid}.tmp`);
5729
+ const tmp = join14(segmentDir, `${MANIFEST_FILENAME}.${process.pid}.tmp`);
5730
5730
  writeFileSync3(tmp, JSON.stringify(manifest, null, 2), "utf-8");
5731
- renameWithRetry2(tmp, join15(segmentDir, MANIFEST_FILENAME));
5731
+ renameWithRetry2(tmp, join14(segmentDir, MANIFEST_FILENAME));
5732
5732
  }
5733
5733
  async function probeSegmentFrameCount(path, probe) {
5734
5734
  try {
@@ -6325,7 +6325,7 @@ function countAuthoredTimedClips(html) {
6325
6325
 
6326
6326
  // src/services/render/stages/compileStage.ts
6327
6327
  import { existsSync as existsSync12, writeFileSync as writeFileSync5 } from "node:fs";
6328
- import { join as join19 } from "node:path";
6328
+ import { join as join18 } from "node:path";
6329
6329
  import { suggestMatchingPreset } from "@hyperframes/core";
6330
6330
  import { extractStandaloneEntryFromIndex, isTemplateEntry } from "@hyperframes/core/compiler";
6331
6331
  import { readTextFile as readTextFile2 } from "@hyperframes/parsers/asset-resolution";
@@ -6334,7 +6334,7 @@ import { readTextFile as readTextFile2 } from "@hyperframes/parsers/asset-resolu
6334
6334
  import { decodedUrlPath as decodedUrlPath2 } from "@hyperframes/parsers/asset-paths";
6335
6335
  import { createHash as createHash6 } from "node:crypto";
6336
6336
  import { createReadStream as createReadStream2, existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync7 } from "fs";
6337
- import { join as join18, dirname as dirname8, resolve as resolve7, basename as basename4, relative as relative2, sep as sep2 } from "path";
6337
+ import { join as join17, dirname as dirname8, resolve as resolve7, basename as basename5, relative as relative2, sep as sep2 } from "path";
6338
6338
  import { parseHTML as parseHTML5 } from "linkedom";
6339
6339
  import {
6340
6340
  COMPOSITION_SOURCE_URL,
@@ -6581,7 +6581,7 @@ import {
6581
6581
  // src/services/animatedGifPrep.ts
6582
6582
  import { createHash as createHash4 } from "node:crypto";
6583
6583
  import { copyFileSync as copyFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, rmSync as rmSync9, statSync as statSync6 } from "node:fs";
6584
- import { dirname as dirname6, isAbsolute as isAbsolute2, join as join16, resolve as resolve5 } from "node:path";
6584
+ import { dirname as dirname6, isAbsolute as isAbsolute2, join as join15, resolve as resolve5 } from "node:path";
6585
6585
  import { parseHTML as parseHTML3 } from "linkedom";
6586
6586
  import { parseAnimatedGifMetadata } from "@hyperframes/core";
6587
6587
  import { DEFAULT_VP9_CPU_USED, runFfmpeg as runFfmpeg2, renameWithRetry as renameWithRetry3 } from "@hyperframes/engine";
@@ -6824,7 +6824,7 @@ function replaceImageWithVideo(input) {
6824
6824
  return video;
6825
6825
  }
6826
6826
  async function prepareAnimatedGifInputs(html, options) {
6827
- const outputDir = options.outputDir ?? join16(options.downloadDir, PREPARED_GIF_SUBDIR);
6827
+ const outputDir = options.outputDir ?? join15(options.downloadDir, PREPARED_GIF_SUBDIR);
6828
6828
  const outputSrcPrefix = normalizeRelPath(options.outputSrcPrefix ?? PREPARED_GIF_SUBDIR);
6829
6829
  const cacheDir = options.cacheDir ?? outputDir;
6830
6830
  const { document: document2 } = parseHTML3(html);
@@ -6851,8 +6851,8 @@ async function prepareAnimatedGifInputs(html, options) {
6851
6851
  );
6852
6852
  const hash = computePreparedGifHash(bytes, loopIterations, padSeconds);
6853
6853
  const filename = `${CACHE_SCHEMA}-${hash.slice(0, 24)}.webm`;
6854
- const cachePath = join16(cacheDir, filename);
6855
- const outputPath = join16(outputDir, filename);
6854
+ const cachePath = join15(cacheDir, filename);
6855
+ const outputPath = join15(outputDir, filename);
6856
6856
  const outputSrc = `${outputSrcPrefix}/${filename}`;
6857
6857
  await ensurePreparedWebm({
6858
6858
  sourcePath,
@@ -6897,7 +6897,7 @@ import {
6897
6897
  statSync as statSync7,
6898
6898
  writeFileSync as writeFileSync4
6899
6899
  } from "node:fs";
6900
- import { dirname as dirname7, join as join17, resolve as resolve6 } from "node:path";
6900
+ import { dirname as dirname7, join as join16, resolve as resolve6 } from "node:path";
6901
6901
  import { parseHTML as parseHTML4 } from "linkedom";
6902
6902
  import { renameWithRetry as renameWithRetry4, runFfmpeg as runFfmpeg3, runFfprobe } from "@hyperframes/engine";
6903
6903
 
@@ -7171,7 +7171,7 @@ async function ensurePreparedJpeg(source, cachePath, outputPath, options) {
7171
7171
  }
7172
7172
  }
7173
7173
  async function prepareHeifImageInputs(html, options) {
7174
- const outputDir = options.outputDir ?? join17(options.downloadDir, PREPARED_HEIF_SUBDIR);
7174
+ const outputDir = options.outputDir ?? join16(options.downloadDir, PREPARED_HEIF_SUBDIR);
7175
7175
  const outputSrcPrefix = normalizeRelPath(options.outputSrcPrefix ?? PREPARED_HEIF_SUBDIR);
7176
7176
  const cacheDir = options.cacheDir ?? outputDir;
7177
7177
  const preparedAssets = /* @__PURE__ */ new Map();
@@ -7192,7 +7192,7 @@ async function prepareHeifImageInputs(html, options) {
7192
7192
  await Promise.all(
7193
7193
  [...unique].map(
7194
7194
  ([filename, source]) => withMediaProbeSlot(
7195
- () => ensurePreparedJpeg(source, join17(cacheDir, filename), join17(outputDir, filename), options)
7195
+ () => ensurePreparedJpeg(source, join16(cacheDir, filename), join16(outputDir, filename), options)
7196
7196
  ).catch((error) => {
7197
7197
  if (!options.onFailure) throw error;
7198
7198
  failed.add(filename);
@@ -7204,8 +7204,8 @@ async function prepareHeifImageInputs(html, options) {
7204
7204
  if (failed.has(filename)) continue;
7205
7205
  const outputSrc = `${outputSrcPrefix}/${filename}`;
7206
7206
  img.setAttribute("src", outputSrc);
7207
- preparedAssets.set(outputSrc, join17(outputDir, filename));
7208
- preparedImages.push({ sourceSrc: src, outputSrc, outputPath: join17(outputDir, filename) });
7207
+ preparedAssets.set(outputSrc, join16(outputDir, filename));
7208
+ preparedImages.push({ sourceSrc: src, outputSrc, outputPath: join16(outputDir, filename) });
7209
7209
  }
7210
7210
  return { html: document2.toString(), preparedAssets, preparedImages };
7211
7211
  }
@@ -7541,7 +7541,7 @@ function detectShaderTransitionUsage(html) {
7541
7541
  async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, downloadDir, tagName, elementIdentity, log, urlByAbsentLocalPath, probes) {
7542
7542
  let filePath = src;
7543
7543
  if (isHttpUrl(src)) {
7544
- const remoteDir = join18(downloadDir, REMOTE_MEDIA_SUBDIR);
7544
+ const remoteDir = join17(downloadDir, REMOTE_MEDIA_SUBDIR);
7545
7545
  if (!existsSync11(remoteDir)) mkdirSync9(remoteDir, { recursive: true });
7546
7546
  try {
7547
7547
  filePath = await downloadToTemp(src, remoteDir, void 0, void 0, void 0, {
@@ -7552,7 +7552,7 @@ async function resolveMediaDuration(src, mediaStart, playbackRate, baseDir, down
7552
7552
  }
7553
7553
  } else {
7554
7554
  filePath = decodedUrlPath2(src);
7555
- if (!filePath.startsWith("/")) filePath = join18(baseDir, filePath);
7555
+ if (!filePath.startsWith("/")) filePath = join17(baseDir, filePath);
7556
7556
  filePath = urlByAbsentLocalPath?.get(filePath) ?? filePath;
7557
7557
  }
7558
7558
  if (!isHttpUrl(filePath) && !existsSync11(filePath)) {
@@ -8168,7 +8168,7 @@ async function downloadAndRewriteUrls(urlSet, html, remoteDir, warnLabel, logLab
8168
8168
  const remoteMediaAssets = /* @__PURE__ */ new Map();
8169
8169
  const urlToRelPath = /* @__PURE__ */ new Map();
8170
8170
  for (const [url, absPath] of urlToLocal) {
8171
- const relPath = `${REMOTE_MEDIA_SUBDIR}/${basename4(absPath)}`;
8171
+ const relPath = `${REMOTE_MEDIA_SUBDIR}/${basename5(absPath)}`;
8172
8172
  remoteMediaAssets.set(relPath, absPath);
8173
8173
  urlToRelPath.set(url, relPath);
8174
8174
  }
@@ -8192,7 +8192,7 @@ async function localizeRemoteMediaSources(html, downloadDir) {
8192
8192
  return downloadAndRewriteUrls(
8193
8193
  urlSet,
8194
8194
  html,
8195
- join18(downloadDir, REMOTE_MEDIA_SUBDIR),
8195
+ join17(downloadDir, REMOTE_MEDIA_SUBDIR),
8196
8196
  "Remote media download failed",
8197
8197
  "Localized remote media source(s)"
8198
8198
  );
@@ -8207,7 +8207,7 @@ async function localizeRemoteImageSources(html, downloadDir) {
8207
8207
  return downloadAndRewriteUrls(
8208
8208
  urlSet,
8209
8209
  html,
8210
- join18(downloadDir, REMOTE_MEDIA_SUBDIR),
8210
+ join17(downloadDir, REMOTE_MEDIA_SUBDIR),
8211
8211
  "Remote image download failed",
8212
8212
  "Localized remote image source(s)"
8213
8213
  );
@@ -8223,7 +8223,7 @@ async function localizeRemoteBackgroundImages(html, downloadDir) {
8223
8223
  return downloadAndRewriteUrls(
8224
8224
  urlSet,
8225
8225
  html,
8226
- join18(downloadDir, REMOTE_MEDIA_SUBDIR),
8226
+ join17(downloadDir, REMOTE_MEDIA_SUBDIR),
8227
8227
  "Remote background-image download failed",
8228
8228
  "Localized remote background-image(s)",
8229
8229
  // Quoted url('..')/url("..") are rewritten by downloadAndRewriteUrls' default
@@ -8378,7 +8378,7 @@ function localizeFontFaceUrls(html, downloadDir) {
8378
8378
  return downloadAndRewriteUrls(
8379
8379
  collectFontFaceUrls(html),
8380
8380
  html,
8381
- join18(downloadDir, REMOTE_MEDIA_SUBDIR),
8381
+ join17(downloadDir, REMOTE_MEDIA_SUBDIR),
8382
8382
  "Remote font download failed",
8383
8383
  "Localized remote font face(s)",
8384
8384
  (h, url, relPath) => h.replaceAll(`url(${url})`, `url("${relPath}")`)
@@ -9055,10 +9055,10 @@ function adaptAspectAgnosticResolution(requested, aspectAgnostic, width, height,
9055
9055
  }
9056
9056
  function resolveEntryHtmlPath(input) {
9057
9057
  const { projectDir, workDir, entryFile, log } = input;
9058
- const htmlPath = join19(projectDir, entryFile);
9058
+ const htmlPath = join18(projectDir, entryFile);
9059
9059
  const rawEntry = readTextFile2(htmlPath);
9060
9060
  if (entryFile === "index.html" || !isTemplateEntry(rawEntry)) return htmlPath;
9061
- const projectIndexPath = join19(projectDir, "index.html");
9061
+ const projectIndexPath = join18(projectDir, "index.html");
9062
9062
  if (!existsSync12(projectIndexPath)) {
9063
9063
  throw new Error(
9064
9064
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
@@ -9074,7 +9074,7 @@ function resolveEntryHtmlPath(input) {
9074
9074
  `Entry file "${entryFile}" is not mounted from index.html via data-composition-src, so it cannot be rendered independently.`
9075
9075
  );
9076
9076
  }
9077
- const wrapperPath = join19(workDir, "standalone-entry.html");
9077
+ const wrapperPath = join18(workDir, "standalone-entry.html");
9078
9078
  writeFileSync5(wrapperPath, standaloneHtml, "utf-8");
9079
9079
  log.info("Extracted standalone entry from index.html host context", { entryFile });
9080
9080
  return wrapperPath;
@@ -9095,7 +9095,7 @@ async function runCompileStage(input) {
9095
9095
  } = input;
9096
9096
  const htmlPath = resolveEntryHtmlPath({ projectDir, workDir, entryFile, log });
9097
9097
  const compileStart = Date.now();
9098
- const compiled = await compileForRender(projectDir, htmlPath, join19(workDir, "downloads"), {
9098
+ const compiled = await compileForRender(projectDir, htmlPath, join18(workDir, "downloads"), {
9099
9099
  log,
9100
9100
  failClosedFontFetch: failClosedFontFetch === true,
9101
9101
  allowSystemFontCapture,
@@ -9103,7 +9103,7 @@ async function runCompileStage(input) {
9103
9103
  variables: input.variables,
9104
9104
  urlByAbsentLocalPath: input.urlByAbsentLocalPath,
9105
9105
  pageMotionBlur: input.pageMotionBlur,
9106
- animatedGifCacheDir: cfg.extractCacheDir ? join19(cfg.extractCacheDir, "animated-gif") : void 0,
9106
+ animatedGifCacheDir: cfg.extractCacheDir ? join18(cfg.extractCacheDir, "animated-gif") : void 0,
9107
9107
  ffmpegProcessTimeout: cfg.ffmpegProcessTimeout
9108
9108
  });
9109
9109
  assertNotAborted();
@@ -9160,7 +9160,7 @@ async function runCompileStage(input) {
9160
9160
  };
9161
9161
  await preflightCompositionAssetMediaTypes({
9162
9162
  projectDir,
9163
- compiledDir: join19(workDir, "compiled"),
9163
+ compiledDir: join18(workDir, "compiled"),
9164
9164
  composition,
9165
9165
  signal: abortSignal
9166
9166
  });
@@ -9206,7 +9206,7 @@ async function runCompileStage(input) {
9206
9206
 
9207
9207
  // src/services/render/stages/probeStage.ts
9208
9208
  import { createHash as createHash7 } from "node:crypto";
9209
- import { basename as basename5, join as join20 } from "node:path";
9209
+ import { basename as basename6, join as join19 } from "node:path";
9210
9210
  import { parseHTML as parseHTML6 } from "linkedom";
9211
9211
  import {
9212
9212
  closeCaptureSession as closeCaptureSession4,
@@ -9356,7 +9356,7 @@ function probeRequiresBrowser(args) {
9356
9356
  function reportedLengthSource(source) {
9357
9357
  if (!source) return null;
9358
9358
  if (source.from !== "media") return { from: source.from };
9359
- const name = basename5(source.src.split(/[?#]/, 1)[0] ?? "");
9359
+ const name = basename6(source.src.split(/[?#]/, 1)[0] ?? "");
9360
9360
  const srcHash = createHash7("sha256").update(name).digest("hex").slice(0, 12);
9361
9361
  return { from: "media", tag: source.tag, trimmed: source.trimmed, srcHash };
9362
9362
  }
@@ -9415,7 +9415,7 @@ async function runProbeStage(input) {
9415
9415
  });
9416
9416
  fileServer = await createFileServer({
9417
9417
  projectDir,
9418
- compiledDir: join20(workDir, "compiled"),
9418
+ compiledDir: join19(workDir, "compiled"),
9419
9419
  port: 0,
9420
9420
  preHeadScripts: [VIRTUAL_TIME_SHIM],
9421
9421
  fps: job.config.fps
@@ -9445,7 +9445,7 @@ async function runProbeStage(input) {
9445
9445
  log.info("Creating capture session...", { attempt, maxAttempts: PROBE_MAX_ATTEMPTS });
9446
9446
  probeSession = await createCaptureSession4(
9447
9447
  fileServer.url,
9448
- join20(workDir, "probe"),
9448
+ join19(workDir, "probe"),
9449
9449
  captureOpts,
9450
9450
  null,
9451
9451
  probeCfg
@@ -9530,7 +9530,7 @@ async function runProbeStage(input) {
9530
9530
  });
9531
9531
  probeSession = await createCaptureSession4(
9532
9532
  fileServer.url,
9533
- join20(workDir, "probe-screenshot"),
9533
+ join19(workDir, "probe-screenshot"),
9534
9534
  captureOpts,
9535
9535
  null,
9536
9536
  { ...probeCfg, forceScreenshot: true }
@@ -9568,7 +9568,7 @@ async function runProbeStage(input) {
9568
9568
  compiled,
9569
9569
  resolutions,
9570
9570
  projectDir,
9571
- join20(workDir, "downloads")
9571
+ join19(workDir, "downloads")
9572
9572
  );
9573
9573
  assertNotAborted();
9574
9574
  composition.videos = compiled.videos;
@@ -9759,7 +9759,7 @@ async function runProbeStage(input) {
9759
9759
  }
9760
9760
  await preflightCompositionAssetMediaTypes({
9761
9761
  projectDir,
9762
- compiledDir: join20(workDir, "compiled"),
9762
+ compiledDir: join19(workDir, "compiled"),
9763
9763
  composition,
9764
9764
  signal: abortSignal
9765
9765
  });
@@ -9926,7 +9926,7 @@ function validateDistributedDuration(input) {
9926
9926
 
9927
9927
  // src/services/render/stages/extractVideosStage.ts
9928
9928
  import { existsSync as existsSync13 } from "node:fs";
9929
- import { join as join21 } from "node:path";
9929
+ import { join as join20 } from "node:path";
9930
9930
  import {
9931
9931
  classifyVideoExtractionError,
9932
9932
  createFrameLookupTable as createFrameLookupTable3,
@@ -10272,14 +10272,14 @@ async function runExtractVideosStage(input) {
10272
10272
  // because short boundary counts can differ by one frame.
10273
10273
  {
10274
10274
  fps: job.config.fps,
10275
- outputDir: join21(compiledDir, "__hyperframes_video_frames"),
10275
+ outputDir: join20(compiledDir, "__hyperframes_video_frames"),
10276
10276
  format: job.config.videoFrameFormat ?? "auto",
10277
10277
  toneMapHdrToSdr: rendersSdrOnly(job.config, composition),
10278
10278
  timelineEnd: composition.duration,
10279
10279
  maxTransientRetries: extractionPolicy.maxTransientRetries,
10280
10280
  collectProbeFailures: extractionPolicy.failureMode === "enforce",
10281
10281
  deferRangeExtraction,
10282
- contentKeyedDirs: [join21(compiledDir, REMOTE_MEDIA_SUBDIR)],
10282
+ contentKeyedDirs: [join20(compiledDir, REMOTE_MEDIA_SUBDIR)],
10283
10283
  urlByAbsentLocalPath,
10284
10284
  onProgress: ({ planned = 0, done = 0 }) => {
10285
10285
  framesPlanned += planned;
@@ -10462,7 +10462,7 @@ async function planVideoLayerPassthrough(input) {
10462
10462
 
10463
10463
  // src/services/render/stages/audioStage.ts
10464
10464
  import { existsSync as existsSync16 } from "node:fs";
10465
- import { join as join24 } from "node:path";
10465
+ import { join as join23 } from "node:path";
10466
10466
  import {
10467
10467
  MIXED_AUDIO_FILENAME,
10468
10468
  audioFailureDiagnostics,
@@ -10473,7 +10473,7 @@ import {
10473
10473
 
10474
10474
  // src/services/render/audioDeliveryLimit.ts
10475
10475
  import { existsSync as existsSync15 } from "node:fs";
10476
- import { dirname as dirname10, join as join23 } from "node:path";
10476
+ import { dirname as dirname10, join as join22 } from "node:path";
10477
10477
  import {
10478
10478
  applyAudioFxChain,
10479
10479
  describeFfmpegFailure as describeFfmpegFailure3,
@@ -10483,8 +10483,7 @@ import {
10483
10483
 
10484
10484
  // src/services/render/audioPadTrim.ts
10485
10485
  import { spawn } from "node:child_process";
10486
- import { mkdtempSync as mkdtempSync3 } from "node:fs";
10487
- import { dirname as dirname9, join as join22 } from "node:path";
10486
+ import { dirname as dirname9, join as join21 } from "node:path";
10488
10487
  import {
10489
10488
  DEFAULT_CONFIG,
10490
10489
  describeFfmpegFailure as describeFfmpegFailure2,
@@ -10591,6 +10590,7 @@ async function measureTruePeakDbfs(audioPath, options) {
10591
10590
  }
10592
10591
 
10593
10592
  // src/services/render/audioPadTrim.ts
10593
+ import { createStagingDir as createStagingDir3 } from "@hyperframes/core/atomic-file";
10594
10594
  var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
10595
10595
  var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
10596
10596
  var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
@@ -10763,7 +10763,7 @@ async function constrainAacTruePeak(input) {
10763
10763
  }
10764
10764
  async function cutSource(input, scratchDir, attenuationDb) {
10765
10765
  if (!input.sourcePath || !input.rewriteSource) return true;
10766
- const cutPath = join22(scratchDir, "source.wav");
10766
+ const cutPath = join21(scratchDir, "source.wav");
10767
10767
  try {
10768
10768
  const result = await input.rewriteSource(input.sourcePath, cutPath, gainFilter(attenuationDb));
10769
10769
  if (!result.success) throw new Error(result.error);
@@ -10777,8 +10777,8 @@ async function cutSource(input, scratchDir, attenuationDb) {
10777
10777
  async function enforceAacTruePeak(input) {
10778
10778
  let scratchDir;
10779
10779
  try {
10780
- scratchDir = mkdtempSync3(join22(dirname9(input.audioPath), ".true-peak-"));
10781
- const correctedPath = join22(scratchDir, "audio.m4a");
10780
+ scratchDir = createStagingDir3(dirname9(input.audioPath), ".true-peak-");
10781
+ const correctedPath = join21(scratchDir, "audio.m4a");
10782
10782
  const measurements = [];
10783
10783
  let attenuationDb = 0;
10784
10784
  let sourcePeakDbfs;
@@ -10988,7 +10988,7 @@ async function limitDeliveryPeaks(input, deps = {
10988
10988
  const peak = await deps.measure(audioPath, { timeoutMs, signal });
10989
10989
  if (peak <= AAC_DELIVERY_TRUE_PEAK_DBFS) return { success: true };
10990
10990
  const alternating = ["a", "b"].map(
10991
- (k) => join23(dirname10(sourcePath), `audio-source-limited-${k}.wav`)
10991
+ (k) => join22(dirname10(sourcePath), `audio-source-limited-${k}.wav`)
10992
10992
  );
10993
10993
  let encodedFrom;
10994
10994
  let ceiling = AAC_DELIVERY_TRUE_PEAK_DBFS;
@@ -11060,7 +11060,7 @@ function runAudioStage(input) {
11060
11060
  }
11061
11061
  async function runAudioStageScoped(input) {
11062
11062
  const stageStart = Date.now();
11063
- const pcmSourcePath = join24(input.workDir, "audio-source.wav");
11063
+ const pcmSourcePath = join23(input.workDir, "audio-source.wav");
11064
11064
  const duration = input.totalFrames * input.fps.den / input.fps.num;
11065
11065
  let deliverySourcePath;
11066
11066
  try {
@@ -11125,7 +11125,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
11125
11125
  assertNotAborted,
11126
11126
  log
11127
11127
  } = input;
11128
- const audioOutputPath = join24(workDir, MIXED_AUDIO_FILENAME);
11128
+ const audioOutputPath = join23(workDir, MIXED_AUDIO_FILENAME);
11129
11129
  let hasAudio = false;
11130
11130
  let audioError;
11131
11131
  let audioFailures;
@@ -11136,7 +11136,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
11136
11136
  audioResult = await processCompositionAudio(
11137
11137
  audios,
11138
11138
  projectDir,
11139
- join24(workDir, "audio-work"),
11139
+ join23(workDir, "audio-work"),
11140
11140
  audioOutputPath,
11141
11141
  duration,
11142
11142
  abortSignal,
@@ -11205,7 +11205,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
11205
11205
 
11206
11206
  // src/services/render/stages/captureStage.ts
11207
11207
  import { existsSync as existsSync17, readdirSync as readdirSync4, statfsSync as statfsSync2 } from "node:fs";
11208
- import { join as join25 } from "node:path";
11208
+ import { join as join24 } from "node:path";
11209
11209
  import {
11210
11210
  classifyCaptureFailure as classifyCaptureFailure2,
11211
11211
  frameFileExtension,
@@ -11278,13 +11278,13 @@ function measureCaptureFrameBytes(workDir, framesDir) {
11278
11278
  if (!existsSync17(workDir)) return total;
11279
11279
  for (const attempt of readdirSync4(workDir)) {
11280
11280
  if (/^retry-\d+-batch-\d+-worker-\d+$/.test(attempt)) {
11281
- total += sampleDirectoryBytes(join25(workDir, attempt));
11281
+ total += sampleDirectoryBytes(join24(workDir, attempt));
11282
11282
  continue;
11283
11283
  }
11284
11284
  if (!/^capture-attempt-\d+$/.test(attempt)) continue;
11285
- const attemptDir = join25(workDir, attempt);
11285
+ const attemptDir = join24(workDir, attempt);
11286
11286
  for (const name of readdirSync4(attemptDir)) {
11287
- if (/^worker-\d+$/.test(name)) total += sampleDirectoryBytes(join25(attemptDir, name));
11287
+ if (/^worker-\d+$/.test(name)) total += sampleDirectoryBytes(join24(attemptDir, name));
11288
11288
  }
11289
11289
  }
11290
11290
  return total;
@@ -11583,7 +11583,7 @@ async function captureSessionFrames(session, { input, rangeStart, rangeEnd, resu
11583
11583
 
11584
11584
  // src/services/render/stages/captureHdrStage.ts
11585
11585
  import { existsSync as existsSync19, mkdirSync as mkdirSync10 } from "node:fs";
11586
- import { join as join29 } from "node:path";
11586
+ import { join as join28 } from "node:path";
11587
11587
  import {
11588
11588
  closeCaptureSession as closeCaptureSession7,
11589
11589
  cloneCaptureWarnings as cloneCaptureWarnings2,
@@ -11655,7 +11655,7 @@ function createHdrImageTransferCache(options = {}) {
11655
11655
  }
11656
11656
 
11657
11657
  // src/services/render/stages/captureHdrSequentialLoop.ts
11658
- import { join as join26 } from "node:path";
11658
+ import { join as join25 } from "node:path";
11659
11659
  import {
11660
11660
  TRANSITIONS,
11661
11661
  crossfade
@@ -11780,7 +11780,7 @@ async function runSequentialLayeredFrameLoop(input) {
11780
11780
  );
11781
11781
  if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
11782
11782
  writeFileExclusiveSync(
11783
- join26(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
11783
+ join25(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
11784
11784
  normalCanvas
11785
11785
  );
11786
11786
  }
@@ -11812,7 +11812,7 @@ async function runSequentialLayeredFrameLoop(input) {
11812
11812
  }
11813
11813
 
11814
11814
  // src/services/render/stages/captureHdrHybridLoop.ts
11815
- import { join as join28 } from "node:path";
11815
+ import { join as join27 } from "node:path";
11816
11816
  import {
11817
11817
  TRANSITIONS as TRANSITIONS2,
11818
11818
  closeCaptureSession as closeCaptureSession6,
@@ -11826,7 +11826,7 @@ import {
11826
11826
  // src/services/shaderTransitionWorkerPool.ts
11827
11827
  import { Worker } from "node:worker_threads";
11828
11828
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
11829
- import { dirname as dirname11, join as join27 } from "node:path";
11829
+ import { dirname as dirname11, join as join26 } from "node:path";
11830
11830
  import { createRequire } from "node:module";
11831
11831
  import { existsSync as existsSync18 } from "node:fs";
11832
11832
  import { cpus as cpus2 } from "node:os";
@@ -11840,9 +11840,9 @@ function resolveWorkerEntry(explicit) {
11840
11840
  return { path: override, isTs };
11841
11841
  }
11842
11842
  const moduleDir = dirname11(fileURLToPath3(import.meta.url));
11843
- const jsPath = join27(moduleDir, "shaderTransitionWorker.js");
11843
+ const jsPath = join26(moduleDir, "shaderTransitionWorker.js");
11844
11844
  if (existsSync18(jsPath)) return { path: jsPath, isTs: false };
11845
- const tsPath = join27(moduleDir, "shaderTransitionWorker.ts");
11845
+ const tsPath = join26(moduleDir, "shaderTransitionWorker.ts");
11846
11846
  return { path: tsPath, isTs: true };
11847
11847
  }
11848
11848
  function buildExecArgv(entryIsTs) {
@@ -12210,7 +12210,7 @@ async function runHybridLayeredFrameLoop(input) {
12210
12210
  );
12211
12211
  if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
12212
12212
  writeFileExclusiveSync(
12213
- join28(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
12213
+ join27(debugDumpDir, `frame_${String(i).padStart(4, "0")}_final_rgb48le.bin`),
12214
12214
  canvas
12215
12215
  );
12216
12216
  }
@@ -12401,7 +12401,7 @@ async function runCaptureHdrStage(input) {
12401
12401
  if (hdrVideoFrameSources.has(v.id)) hdrVideoEndTimes.set(v.id, v.end);
12402
12402
  }
12403
12403
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
12404
- const debugDumpDir = debugDumpEnabled ? join29(framesDir, "debug-composite") : null;
12404
+ const debugDumpDir = debugDumpEnabled ? join28(framesDir, "debug-composite") : null;
12405
12405
  if (debugDumpDir && !existsSync19(debugDumpDir)) {
12406
12406
  mkdirSync10(debugDumpDir, { recursive: true });
12407
12407
  }
@@ -12568,7 +12568,7 @@ import {
12568
12568
  writeFileSync as writeFileSync6
12569
12569
  } from "node:fs";
12570
12570
  import { readFile as readFile2 } from "node:fs/promises";
12571
- import { dirname as dirname12, join as join30 } from "node:path";
12571
+ import { dirname as dirname12, join as join29 } from "node:path";
12572
12572
  import {
12573
12573
  encodeFramesChunkedConcat,
12574
12574
  encodeFramesFromDir,
@@ -12779,7 +12779,7 @@ function encodeWhileCapturing(input, totalFrames) {
12779
12779
  await new Promise((resolve13) => wake = resolve13);
12780
12780
  }
12781
12781
  if (signal.aborted) return;
12782
- const mergedPath = join30(input.framesDir, formatCaptureFrameName(next, "jpg"));
12782
+ const mergedPath = join29(input.framesDir, formatCaptureFrameName(next, "jpg"));
12783
12783
  const frame = await readLandedFrame(landed.get(next), mergedPath);
12784
12784
  landed.delete(next);
12785
12785
  if (!await stream.writeFrame(frame)) {
@@ -12862,11 +12862,11 @@ async function runEncodeStage(input) {
12862
12862
  );
12863
12863
  }
12864
12864
  captured.forEach((name, i) => {
12865
- const dst = join30(outputPath, formatExportFrameName(i, "png"));
12866
- copyFileSync4(join30(framesDir, name), dst);
12865
+ const dst = join29(outputPath, formatExportFrameName(i, "png"));
12866
+ copyFileSync4(join29(framesDir, name), dst);
12867
12867
  });
12868
12868
  if (hasAudio && audioOutputPath && existsSync20(audioOutputPath)) {
12869
- copyFileSync4(audioOutputPath, join30(outputPath, MIXED_AUDIO_FILENAME2));
12869
+ copyFileSync4(audioOutputPath, join29(outputPath, MIXED_AUDIO_FILENAME2));
12870
12870
  log.info(
12871
12871
  `[Render] png-sequence: ${MIXED_AUDIO_FILENAME2} sidecar written to ${outputPath}/${MIXED_AUDIO_FILENAME2}`
12872
12872
  );
@@ -12886,7 +12886,7 @@ async function runEncodeStage(input) {
12886
12886
  const encodeResult2 = await encodeGifFromDir(framesDir, framePattern2, outputPath, {
12887
12887
  fps: job.config.fps,
12888
12888
  loop,
12889
- palettePath: join30(dirname12(videoOnlyPath), "gif-palette.png"),
12889
+ palettePath: join29(dirname12(videoOnlyPath), "gif-palette.png"),
12890
12890
  preserveAlpha: needsAlpha,
12891
12891
  signal: abortSignal,
12892
12892
  timeout: engineCfg.ffmpegEncodeTimeout
@@ -13097,7 +13097,7 @@ function sampleDirectoryBytes(dir) {
13097
13097
  continue;
13098
13098
  }
13099
13099
  for (const name of entries) {
13100
- const full = join31(current, name);
13100
+ const full = join30(current, name);
13101
13101
  try {
13102
13102
  const st = statSync9(full);
13103
13103
  if (st.isDirectory()) {
@@ -13253,7 +13253,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
13253
13253
  const ranges = [];
13254
13254
  let rangeStart = null;
13255
13255
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
13256
- const framePath = join31(framesDir, formatCaptureFrameName(frameIndex, frameExt));
13256
+ const framePath = join30(framesDir, formatCaptureFrameName(frameIndex, frameExt));
13257
13257
  const missing = !existsSync21(framePath) || statSync9(framePath).size <= 8;
13258
13258
  if (missing && rangeStart === null) {
13259
13259
  rangeStart = frameIndex;
@@ -13270,7 +13270,7 @@ function findMissingFrameRanges(totalFrames, framesDir, frameExt) {
13270
13270
  function buildMissingFrameRetryBatches(ranges, maxWorkers, workDir, attempt, rangeStart = 0, stride = 1) {
13271
13271
  const workersPerBatch = Math.max(1, Math.floor(maxWorkers));
13272
13272
  const batches = [];
13273
- const outputDirFor = (batchIndex, workerId) => join31(workDir, `retry-${attempt}-batch-${batchIndex}-worker-${workerId}`);
13273
+ const outputDirFor = (batchIndex, workerId) => join30(workDir, `retry-${attempt}-batch-${batchIndex}-worker-${workerId}`);
13274
13274
  if (stride > 1) {
13275
13275
  const spans = /* @__PURE__ */ new Map();
13276
13276
  for (const range of ranges) {
@@ -13330,8 +13330,8 @@ function getNextRetryWorkerCount(currentWorkers) {
13330
13330
  return Math.max(1, Math.floor(currentWorkers / 2));
13331
13331
  }
13332
13332
  function resolveRenderWorkDirPrefix(outputPath, jobId, platform2 = process.platform, systemTempDir = tmpdir2()) {
13333
- if (platform2 === "win32" || platform2 === "darwin") return join31(systemTempDir, "hf-render-");
13334
- return join31(dirname13(outputPath), `work-${jobId}-`);
13333
+ if (platform2 === "win32" || platform2 === "darwin") return join30(systemTempDir, "hf-render-");
13334
+ return join30(dirname13(outputPath), `work-${jobId}-`);
13335
13335
  }
13336
13336
  var MAX_TRANSIENT_CAPTURE_RETRIES = 1;
13337
13337
  function isTransientCaptureRetryEligible(failureKind, missing, retriesUsed) {
@@ -13378,7 +13378,7 @@ The composition is too large for the available memory. To reduce memory pressure
13378
13378
  function countCapturedFrames(totalFrames, framesDir, frameExt) {
13379
13379
  let captured = 0;
13380
13380
  for (let frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
13381
- const framePath = join31(framesDir, formatCaptureFrameName(frameIndex, frameExt));
13381
+ const framePath = join30(framesDir, formatCaptureFrameName(frameIndex, frameExt));
13382
13382
  if (existsSync21(framePath)) captured++;
13383
13383
  }
13384
13384
  return captured;
@@ -13404,7 +13404,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
13404
13404
  reason: attempt === 0 ? "initial" : pendingTransientRetry ? "transient-retry" : "retry"
13405
13405
  });
13406
13406
  pendingTransientRetry = false;
13407
- const attemptWorkDir = join31(options.workDir, `capture-attempt-${attempt}`);
13407
+ const attemptWorkDir = join30(options.workDir, `capture-attempt-${attempt}`);
13408
13408
  const batches = missingRanges ? buildMissingFrameRetryBatches(
13409
13409
  missingRanges,
13410
13410
  currentWorkers,
@@ -14037,7 +14037,7 @@ function deVerifyFallbackTelemetry(err) {
14037
14037
  }
14038
14038
  function resolveRenderDebugDir() {
14039
14039
  const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve8(process.env.PRODUCER_RENDERS_DIR, "..") : resolve8(dirname13(fileURLToPath4(import.meta.url)), "../..");
14040
- return join31(producerRoot, ".debug");
14040
+ return join30(producerRoot, ".debug");
14041
14041
  }
14042
14042
  async function executeRenderJob(job, projectDir, outputPath, progressSink, abortSignal, assertRenderActive) {
14043
14043
  validateHlsRenderConfig(job.config);
@@ -14045,10 +14045,10 @@ async function executeRenderJob(job, projectDir, outputPath, progressSink, abort
14045
14045
  const debugDir = resolveRenderDebugDir();
14046
14046
  const outputDir = dirname13(outputPath);
14047
14047
  if (!existsSync21(outputDir)) mkdirSync12(outputDir, { recursive: true });
14048
- const workDir = job.config.debug ? join31(debugDir, job.id) : createRenderWorkDir(resolveRenderWorkDirPrefix(outputPath, job.id), outputDir);
14048
+ const workDir = job.config.debug ? join30(debugDir, job.id) : createRenderWorkDir(resolveRenderWorkDirPrefix(outputPath, job.id), outputDir);
14049
14049
  const pipelineStart = Date.now();
14050
14050
  const baseLog = job.config.logger ?? defaultLogger;
14051
- const logPath = job.config.debug ? join31(workDir, "render.log") : null;
14051
+ const logPath = job.config.debug ? join30(workDir, "render.log") : null;
14052
14052
  const execution = new RenderExecutionContext({
14053
14053
  request: { renderJobId: job.id, projectDir, outputPath },
14054
14054
  logger: logPath ? createRenderFileLogger(logPath, baseLog) : baseLog,
@@ -14110,7 +14110,7 @@ async function executeRenderPipeline(input) {
14110
14110
  imageDecodeFailures: 0
14111
14111
  };
14112
14112
  let hdrPerf;
14113
- const perfOutputPath = join31(workDir, "perf-summary.json");
14113
+ const perfOutputPath = join30(workDir, "perf-summary.json");
14114
14114
  const cfg = { ...job.config.producerConfig ?? resolveConfig2() };
14115
14115
  const observability = new RenderObservabilityRecorder({
14116
14116
  pipelineStartMs: pipelineStart,
@@ -14215,7 +14215,7 @@ async function executeRenderPipeline(input) {
14215
14215
  requestedWorkers: job.config.workers ?? "auto"
14216
14216
  });
14217
14217
  const entryFile = job.config.entryFile || "index.html";
14218
- const htmlPath = join31(projectDir, entryFile);
14218
+ const htmlPath = join30(projectDir, entryFile);
14219
14219
  if (!existsSync21(htmlPath)) {
14220
14220
  throw new Error(`Entry file not found: ${htmlPath}`);
14221
14221
  }
@@ -14392,7 +14392,7 @@ async function executeRenderPipeline(input) {
14392
14392
  canvas: { width, height },
14393
14393
  page: probeSession.page,
14394
14394
  projectDir,
14395
- compiledDir: join31(workDir, "compiled")
14395
+ compiledDir: join30(workDir, "compiled")
14396
14396
  });
14397
14397
  if (videoLayerPlan.videoId === void 0) {
14398
14398
  log.info(`[Render] Video layer passthrough off: ${videoLayerPlan.reason}`);
@@ -14410,7 +14410,7 @@ async function executeRenderPipeline(input) {
14410
14410
  updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress, {
14411
14411
  code: "extract_video"
14412
14412
  });
14413
- const compiledDir = join31(workDir, "compiled");
14413
+ const compiledDir = join30(workDir, "compiled");
14414
14414
  const segmentsCapture = (layeredOrEffectRoute) => shouldSegmentCapture({
14415
14415
  env: process.env,
14416
14416
  durationSeconds: probeResult.duration,
@@ -14541,7 +14541,7 @@ async function executeRenderPipeline(input) {
14541
14541
  try {
14542
14542
  fileServer = await createFileServer({
14543
14543
  projectDir,
14544
- compiledDir: join31(workDir, "compiled"),
14544
+ compiledDir: join30(workDir, "compiled"),
14545
14545
  port: 0,
14546
14546
  preHeadScripts: [VIRTUAL_TIME_SHIM],
14547
14547
  fps: job.config.fps
@@ -14559,7 +14559,7 @@ async function executeRenderPipeline(input) {
14559
14559
  if (!activeFileServer) {
14560
14560
  throw new Error("File server failed to initialize before frame capture");
14561
14561
  }
14562
- const framesDir = join31(workDir, "captured-frames");
14562
+ const framesDir = join30(workDir, "captured-frames");
14563
14563
  if (!existsSync21(framesDir)) mkdirSync12(framesDir, { recursive: true });
14564
14564
  updateJobStatus(job, "rendering", "Checking browser GPU", 25, onProgress, {
14565
14565
  code: "start_browsers"
@@ -15123,7 +15123,7 @@ async function executeRenderPipeline(input) {
15123
15123
  hls: ".mp4"
15124
15124
  };
15125
15125
  const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
15126
- const videoOnlyPath = join31(workDir, `video-only${videoExt}`);
15126
+ const videoOnlyPath = join30(workDir, `video-only${videoExt}`);
15127
15127
  const usePageSideCompositingForTransitions = (cfg.enablePageSideCompositing || isGif) && compiled.hasShaderTransitions && !hasHdrContent && outputSupportsPageSideShaderCompositing(outputFormat);
15128
15128
  if (usePageSideCompositingForTransitions) {
15129
15129
  activeFileServer.addPreHeadScript(HF_PAGE_SIDE_COMPOSITING_STUB);
@@ -15409,7 +15409,7 @@ async function executeRenderPipeline(input) {
15409
15409
  pageMotionBlur: job.config.pageMotionBlur,
15410
15410
  captureQuality: captureOptions.quality
15411
15411
  });
15412
- const segmentDir = segmentDirFor(join31(projectDir, "renders"), segmentPlanHash);
15412
+ const segmentDir = segmentDirFor(join30(projectDir, "renders"), segmentPlanHash);
15413
15413
  let completedSegments = /* @__PURE__ */ new Set();
15414
15414
  if (job.config.resumeSegments === true) {
15415
15415
  const existing = readSegmentManifest(segmentDir);
@@ -16032,7 +16032,7 @@ async function executeRenderPipeline(input) {
16032
16032
  }
16033
16033
  if (job.config.debug) {
16034
16034
  if (!isPngSequence && !isHls && existsSync21(stagedOutputPath)) {
16035
- const debugOutput = join31(workDir, `output${videoExt}`);
16035
+ const debugOutput = join30(workDir, `output${videoExt}`);
16036
16036
  copyFileSync5(stagedOutputPath, debugOutput);
16037
16037
  }
16038
16038
  }
@@ -16146,16 +16146,17 @@ import {
16146
16146
  REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD4,
16147
16147
  referenceBackgroundResult as referenceBackgroundResult6
16148
16148
  } from "@hyperframes/engine";
16149
- import { mkdirSync as mkdirSync20, mkdtempSync as mkdtempSync7, readFileSync as readFileSync14, rmSync as rmSync18 } from "node:fs";
16150
- import { join as join45 } from "node:path";
16149
+ import { mkdirSync as mkdirSync20, mkdtempSync, readFileSync as readFileSync14, rmSync as rmSync18 } from "node:fs";
16150
+ import { join as join44 } from "node:path";
16151
16151
  import { tmpdir as tmpdir4 } from "node:os";
16152
16152
 
16153
16153
  // src/services/distributed/mp4Stitch.ts
16154
- import { createReadStream as createReadStream3, createWriteStream, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync13 } from "node:fs";
16154
+ import { createReadStream as createReadStream3, createWriteStream, mkdirSync as mkdirSync13, rmSync as rmSync13 } from "node:fs";
16155
16155
  import { open } from "node:fs/promises";
16156
16156
  import { renameWithRetry as renameWithRetry7 } from "@hyperframes/engine";
16157
- import { dirname as dirname14, join as join32 } from "node:path";
16157
+ import { basename as basename7, dirname as dirname14, join as join31 } from "node:path";
16158
16158
  import { finished, pipeline } from "node:stream/promises";
16159
+ import { createStagingDir as createStagingDir4 } from "@hyperframes/core/atomic-file";
16159
16160
  function boxAt(src, off, at, limit) {
16160
16161
  let size = src.readUInt32BE(off);
16161
16162
  let bodyStart = at + 8;
@@ -16519,14 +16520,14 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
16519
16520
  const layouts = await Promise.all(sourcePaths.map((path) => readMp4Layout(fileRange(path))));
16520
16521
  const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
16521
16522
  mkdirSync13(dirname14(outputPath), { recursive: true });
16522
- const workDir = mkdtempSync4(`${outputPath}.stitch-`);
16523
- const out = createWriteStream(join32(workDir, "out.mp4"));
16523
+ const workDir = createStagingDir4(dirname14(outputPath), `${basename7(outputPath)}.stitch-`);
16524
+ const out = createWriteStream(join31(workDir, "out.mp4"));
16524
16525
  try {
16525
16526
  out.write(header);
16526
16527
  for (const [i, path] of sourcePaths.entries()) await copyPayload(path, layouts[i], i, out);
16527
16528
  out.end();
16528
16529
  await finished(out);
16529
- renameWithRetry7(join32(workDir, "out.mp4"), outputPath);
16530
+ renameWithRetry7(join31(workDir, "out.mp4"), outputPath);
16530
16531
  } finally {
16531
16532
  out.destroy();
16532
16533
  rmSync13(workDir, { recursive: true, force: true });
@@ -16549,7 +16550,7 @@ import {
16549
16550
  rmSync as rmSync14,
16550
16551
  writeFileSync as writeFileSync10
16551
16552
  } from "node:fs";
16552
- import { extname as extname6, isAbsolute as isAbsolute3, join as join40, relative as relative5, sep as sep3 } from "node:path";
16553
+ import { extname as extname6, isAbsolute as isAbsolute3, join as join39, relative as relative5, sep as sep3 } from "node:path";
16553
16554
  import {
16554
16555
  fpsToNumber as fpsToNumber9,
16555
16556
  HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR2
@@ -16565,7 +16566,7 @@ import {
16565
16566
  } from "@hyperframes/engine";
16566
16567
 
16567
16568
  // src/services/distributed/planFrameCost.ts
16568
- import { join as join35 } from "node:path";
16569
+ import { join as join34 } from "node:path";
16569
16570
  import {
16570
16571
  closeCaptureSession as closeCaptureSession9,
16571
16572
  createCaptureSession as createCaptureSession9,
@@ -16575,7 +16576,7 @@ import {
16575
16576
 
16576
16577
  // src/services/distributed/chunkFrames.ts
16577
16578
  import { existsSync as existsSync23, readdirSync as readdirSync7 } from "node:fs";
16578
- import { extname as extname4, join as join34 } from "node:path";
16579
+ import { extname as extname4, join as join33 } from "node:path";
16579
16580
  import {
16580
16581
  compositionRequiresWebGpu as compositionRequiresWebGpu3,
16581
16582
  createVideoFrameInjector as createVideoFrameInjector3
@@ -16583,7 +16584,7 @@ import {
16583
16584
 
16584
16585
  // src/services/distributed/shared.ts
16585
16586
  import { execFile as execFileCallback } from "node:child_process";
16586
- import { dirname as dirname15, join as join33 } from "node:path";
16587
+ import { dirname as dirname15, join as join32 } from "node:path";
16587
16588
  import { existsSync as existsSync22, readFileSync as readFileSync9 } from "node:fs";
16588
16589
  import { fileURLToPath as fileURLToPath5 } from "node:url";
16589
16590
  import { promisify as promisify2 } from "node:util";
@@ -16599,7 +16600,7 @@ function isPlanAudioArtifactPath(path) {
16599
16600
  }
16600
16601
  function resolvePlanAudioPath(planDir) {
16601
16602
  for (const name of [PLAN_AUDIO_RELATIVE_PATH, PLAN_AUDIO_LEGACY_RELATIVE_PATH]) {
16602
- const candidate = join33(planDir, name);
16603
+ const candidate = join32(planDir, name);
16603
16604
  if (existsSync22(candidate)) return candidate;
16604
16605
  }
16605
16606
  return null;
@@ -16850,7 +16851,7 @@ function buildSyntheticRenderJob(input) {
16850
16851
  strictness: input.strictness,
16851
16852
  producerConfig: input.producerConfig,
16852
16853
  variables: input.variables,
16853
- pageMotionBlur: "off"
16854
+ pageMotionBlur: input.pageMotionBlur
16854
16855
  };
16855
16856
  return createRenderJob(renderConfig);
16856
16857
  }
@@ -16860,7 +16861,7 @@ function readProducerVersion() {
16860
16861
  const startDir = dirname15(fileURLToPath5(import.meta.url));
16861
16862
  let current = startDir;
16862
16863
  for (let i = 0; i < 10; i++) {
16863
- const candidate = join33(current, "package.json");
16864
+ const candidate = join32(current, "package.json");
16864
16865
  if (existsSync22(candidate)) {
16865
16866
  try {
16866
16867
  const pkg = JSON.parse(readFileSync9(candidate, "utf-8"));
@@ -16915,7 +16916,7 @@ function frameNumberFromFileName(name) {
16915
16916
  function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v1") {
16916
16917
  const result = [];
16917
16918
  for (const v of videos) {
16918
- const outputDir = join34(planDir, "video-frames", v.videoId);
16919
+ const outputDir = join33(planDir, "video-frames", v.videoId);
16919
16920
  if (!existsSync23(outputDir)) {
16920
16921
  throw new Error(
16921
16922
  `[renderChunk] planDir missing extracted video frames for ${JSON.stringify(v.videoId)}: ${outputDir} not present. plan() should have written frames here; the planDir is malformed.`
@@ -16934,7 +16935,7 @@ function rebuildExtractedFramesFromPlanDir(planDir, videos, indexMode = "dense-v
16934
16935
  if (!frameName) continue;
16935
16936
  const frameNumber = indexMode === "sparse-v2" ? frameNumberFromFileName(frameName) : null;
16936
16937
  const frameIndex = frameNumber === null ? i : frameNumber - 1;
16937
- framePaths.set(frameIndex, join34(outputDir, frameName));
16938
+ framePaths.set(frameIndex, join33(outputDir, frameName));
16938
16939
  }
16939
16940
  result.push({
16940
16941
  videoId: v.videoId,
@@ -16967,7 +16968,7 @@ function buildChunkCaptureOptions(input) {
16967
16968
  skipReadinessVideoIds: input.skipReadinessVideoIds,
16968
16969
  videoMetadataHints: input.videoMetadataHints,
16969
16970
  ...videoCaptureBeyondViewport !== void 0 ? { captureBeyondViewport: videoCaptureBeyondViewport } : {},
16970
- pageMotionBlur: encoder.pageMotionBlur ?? "distributed-render",
16971
+ pageMotionBlur: encoder.pageMotionBlur,
16971
16972
  // A fixed warmup count keeps `beginFrameTimeTicks` host-independent.
16972
16973
  lockWarmupTicks: true,
16973
16974
  requiresWebGpu: compositionRequiresWebGpu3(input.html)
@@ -17014,7 +17015,7 @@ async function extractDeferredVideoFramesForChunk(input) {
17014
17015
  sourceOf: (video) => {
17015
17016
  const range = planned.get(video.videoId).deferredRange;
17016
17017
  const remoteUrl = remoteSources[range.sourcePath];
17017
- const sourcePath = remoteUrl ?? join34(input.planDir, ...range.sourcePath.split("/"));
17018
+ const sourcePath = remoteUrl ?? join33(input.planDir, ...range.sourcePath.split("/"));
17018
17019
  if (remoteUrl === void 0 && !existsSync23(sourcePath)) {
17019
17020
  throw new RenderChunkValidationError(
17020
17021
  MISSING_PLAN_ARTIFACT,
@@ -17045,12 +17046,12 @@ async function measurePlanSecondsPerFrame(input) {
17045
17046
  planVideos,
17046
17047
  frames: sampled,
17047
17048
  fps: fpsRatio,
17048
- outputRoot: join35(workDir, "frame-cost-video-frames"),
17049
+ outputRoot: join34(workDir, "frame-cost-video-frames"),
17049
17050
  cfg: input.cfg
17050
17051
  })
17051
17052
  ];
17052
17053
  const lookup = extracted.length > 0 ? createFrameLookupTable4(planVideos.videos, extracted, resolveRenderFpsConfig(fpsRatio).value) : null;
17053
- const compiledDir = join35(planDir, "compiled");
17054
+ const compiledDir = join34(planDir, "compiled");
17054
17055
  const fileServer = await createFileServer({
17055
17056
  projectDir: compiledDir,
17056
17057
  compiledDir,
@@ -17062,7 +17063,7 @@ async function measurePlanSecondsPerFrame(input) {
17062
17063
  try {
17063
17064
  session = await createCaptureSession9(
17064
17065
  fileServer.url,
17065
- join35(workDir, "frame-cost"),
17066
+ join34(workDir, "frame-cost"),
17066
17067
  buildChunkCaptureOptions({
17067
17068
  dimensions: { ...input, fpsNum: fps, fpsDen: 1 },
17068
17069
  encoder: input,
@@ -17159,7 +17160,7 @@ function buildWeightedChunkSlices(weights, chunkCount, minFrames, maxFrames) {
17159
17160
  }
17160
17161
 
17161
17162
  // src/services/render/planReferenceBackground.ts
17162
- import { join as join36 } from "node:path";
17163
+ import { join as join35 } from "node:path";
17163
17164
  import {
17164
17165
  closeCaptureSession as closeCaptureSession10,
17165
17166
  createCaptureSession as createCaptureSession10,
@@ -17172,14 +17173,14 @@ async function readPlanReferenceBackground(input) {
17172
17173
  try {
17173
17174
  server = await createFileServer({
17174
17175
  projectDir: input.projectDir,
17175
- compiledDir: join36(input.workDir, "compiled"),
17176
+ compiledDir: join35(input.workDir, "compiled"),
17176
17177
  port: 0,
17177
17178
  preHeadScripts: [VIRTUAL_TIME_SHIM],
17178
17179
  fps: input.options.fps
17179
17180
  });
17180
17181
  session = await createCaptureSession10(
17181
17182
  server.url,
17182
- join36(input.workDir, "reference"),
17183
+ join35(input.workDir, "reference"),
17183
17184
  {
17184
17185
  ...input.options,
17185
17186
  requiresWebGpu: false
@@ -17216,7 +17217,7 @@ async function readPlanReferenceBackground(input) {
17216
17217
 
17217
17218
  // src/services/render/stages/freezePlan.ts
17218
17219
  import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync10, readdirSync as readdirSync8, writeFileSync as writeFileSync8 } from "node:fs";
17219
- import { join as join37, relative as relative3, resolve as resolve9 } from "node:path";
17220
+ import { join as join36, relative as relative3, resolve as resolve9 } from "node:path";
17220
17221
  import {
17221
17222
  REFERENCE_BACKGROUND_FIELD,
17222
17223
  referenceBackgroundResult as referenceBackgroundResult3
@@ -17434,7 +17435,7 @@ function listPlanFiles(planDir) {
17434
17435
  function walk(dir) {
17435
17436
  const entries = readdirSync8(dir, { withFileTypes: true });
17436
17437
  for (const entry of entries) {
17437
- const full = join37(dir, entry.name);
17438
+ const full = join36(dir, entry.name);
17438
17439
  if (entry.isDirectory()) {
17439
17440
  walk(full);
17440
17441
  } else if (entry.isFile()) {
@@ -17475,15 +17476,15 @@ var PLAN_REMOTE_FILES_RELATIVE_PATH = "meta/remote-files.json";
17475
17476
  function writePlanRemoteFiles(planDir, files) {
17476
17477
  if (files.length === 0) return;
17477
17478
  const sorted = [...files].sort((a, b) => a.path < b.path ? -1 : 1);
17478
- writeFileSync8(join37(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
17479
+ writeFileSync8(join36(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
17479
17480
  }
17480
17481
  function readPlanRemoteFiles(planDir) {
17481
- const path = join37(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
17482
+ const path = join36(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
17482
17483
  return existsSync24(path) ? JSON.parse(readFileSync10(path, "utf-8")) : [];
17483
17484
  }
17484
17485
  function recomputePlanHashFromPlanDir(planDir, digests) {
17485
- const planJsonPath = join37(planDir, "plan.json");
17486
- const encoderJsonPath = join37(planDir, "meta", "encoder.json");
17486
+ const planJsonPath = join36(planDir, "plan.json");
17487
+ const encoderJsonPath = join36(planDir, "meta", "encoder.json");
17487
17488
  if (!existsSync24(planJsonPath)) {
17488
17489
  throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
17489
17490
  }
@@ -17520,18 +17521,18 @@ async function freezePlan(input) {
17520
17521
  if (!existsSync24(planDir)) {
17521
17522
  throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
17522
17523
  }
17523
- const metaDir = join37(planDir, "meta");
17524
+ const metaDir = join36(planDir, "meta");
17524
17525
  if (!existsSync24(metaDir)) mkdirSync14(metaDir, { recursive: true });
17525
17526
  writeFileSync8(
17526
- join37(metaDir, "composition.json"),
17527
+ join36(metaDir, "composition.json"),
17527
17528
  `${JSON.stringify(composition, null, 2)}
17528
17529
  `,
17529
17530
  "utf-8"
17530
17531
  );
17531
17532
  const encoderForCanonical = stripUndefined(encoder);
17532
17533
  const encoderConfigCanonicalJson = canonicalJsonStringify(encoderForCanonical);
17533
- writeFileSync8(join37(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
17534
- writeFileSync8(join37(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
17534
+ writeFileSync8(join36(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
17535
+ writeFileSync8(join36(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
17535
17536
  `, "utf-8");
17536
17537
  const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
17537
17538
  const planHash = computePlanHash({
@@ -17556,7 +17557,7 @@ async function freezePlan(input) {
17556
17557
  duration: durationSeconds,
17557
17558
  hasAudio
17558
17559
  };
17559
- const planJsonPath = join37(planDir, "plan.json");
17560
+ const planJsonPath = join36(planDir, "plan.json");
17560
17561
  writeFileSync8(planJsonPath, `${JSON.stringify(planJson, null, 2)}
17561
17562
  `, "utf-8");
17562
17563
  return { planJsonPath, planHash };
@@ -17600,7 +17601,7 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
17600
17601
  // src/services/distributed/chunkAudio.ts
17601
17602
  import { closeSync as closeSync6, existsSync as existsSync25, ftruncateSync, mkdirSync as mkdirSync15, openSync as openSync6, readFileSync as readFileSync11 } from "node:fs";
17602
17603
  import { writeFileSync as writeFileSync9, writeSync } from "node:fs";
17603
- import { join as join38 } from "node:path";
17604
+ import { join as join37 } from "node:path";
17604
17605
  import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
17605
17606
  function audioCutForChunk(grid, chunks, index, fps) {
17606
17607
  const firstPacketAt = (frame) => Math.min(
@@ -17688,7 +17689,7 @@ async function writeChunkAudioSlices(input) {
17688
17689
  });
17689
17690
  const bytes = readFileSync11(input.audioPath);
17690
17691
  const layout = { sizeBytes: bytes.length, payloadStart, payloadEnd, partStarts: {} };
17691
- mkdirSync15(join38(input.planDir, SLICE_DIR), { recursive: true });
17692
+ mkdirSync15(join37(input.planDir, SLICE_DIR), { recursive: true });
17692
17693
  input.chunks.forEach((_, index) => {
17693
17694
  const cut = audioCutForChunk(grid, input.chunks, index, input.fps);
17694
17695
  if (!cut) return;
@@ -17696,17 +17697,17 @@ async function writeChunkAudioSlices(input) {
17696
17697
  const start = offsets[cut.firstPacket];
17697
17698
  layout.partStarts[index] = start;
17698
17699
  const end = offsets[last] + track.sizes[last];
17699
- writeFileSync9(join38(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
17700
+ writeFileSync9(join37(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
17700
17701
  });
17701
17702
  const frame = [bytes.subarray(0, payloadStart), bytes.subarray(payloadEnd)];
17702
- writeFileSync9(join38(input.planDir, SLICE_FRAME), Buffer.concat(frame));
17703
- writeFileSync9(join38(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
17703
+ writeFileSync9(join37(input.planDir, SLICE_FRAME), Buffer.concat(frame));
17704
+ writeFileSync9(join37(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
17704
17705
  }
17705
17706
  function chunkAudioSource(planDir, chunkIndex, scratchPath) {
17706
- const layoutPath = join38(planDir, SLICE_LAYOUT);
17707
+ const layoutPath = join37(planDir, SLICE_LAYOUT);
17707
17708
  if (!existsSync25(layoutPath)) return resolvePlanAudioPath(planDir);
17708
17709
  const layout = JSON.parse(readFileSync11(layoutPath, "utf-8"));
17709
- const frame = readFileSync11(join38(planDir, SLICE_FRAME));
17710
+ const frame = readFileSync11(join37(planDir, SLICE_FRAME));
17710
17711
  const fd = openSync6(scratchPath, "w");
17711
17712
  try {
17712
17713
  writeSync(fd, frame, 0, layout.payloadStart, 0);
@@ -17719,7 +17720,7 @@ function chunkAudioSource(planDir, chunkIndex, scratchPath) {
17719
17720
  );
17720
17721
  const start = layout.partStarts[chunkIndex];
17721
17722
  if (start !== void 0) {
17722
- const part = readFileSync11(join38(planDir, chunkAudioSlicePath(chunkIndex)));
17723
+ const part = readFileSync11(join37(planDir, chunkAudioSlicePath(chunkIndex)));
17723
17724
  writeSync(fd, part, 0, part.length, start);
17724
17725
  }
17725
17726
  ftruncateSync(fd, layout.sizeBytes);
@@ -17775,7 +17776,7 @@ async function muxChunkWithAudio(input) {
17775
17776
  // src/services/distributed/planSize.ts
17776
17777
  import { createHash as createHash9 } from "node:crypto";
17777
17778
  import { lstatSync as lstatSync2, readdirSync as readdirSync9 } from "node:fs";
17778
- import { extname as extname5, join as join39, relative as relative4 } from "node:path";
17779
+ import { extname as extname5, join as join38, relative as relative4 } from "node:path";
17779
17780
  var MAX_TOP_COMPONENTS = 10;
17780
17781
  var SOURCE_MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
17781
17782
  ".aac",
@@ -17887,7 +17888,7 @@ function walkRegularFiles(dir, visit) {
17887
17888
  return;
17888
17889
  }
17889
17890
  for (const entry of entries) {
17890
- const full = join39(dir, entry.name);
17891
+ const full = join38(dir, entry.name);
17891
17892
  if (entry.isDirectory()) {
17892
17893
  walkRegularFiles(full, visit);
17893
17894
  } else if (entry.isFile()) {
@@ -18103,13 +18104,13 @@ function assertPositiveInteger2(name, value) {
18103
18104
  }
18104
18105
  var FREEZE_OWNED_PLAN_FILES = [
18105
18106
  "plan.json",
18106
- join40("meta", "composition.json"),
18107
- join40("meta", "encoder.json"),
18108
- join40("meta", "chunks.json")
18107
+ join39("meta", "composition.json"),
18108
+ join39("meta", "encoder.json"),
18109
+ join39("meta", "chunks.json")
18109
18110
  ];
18110
18111
  function removeFreezeOwnedPlanFiles(planDir) {
18111
18112
  for (const relativePath of FREEZE_OWNED_PLAN_FILES) {
18112
- rmSync14(join40(planDir, relativePath), { force: true });
18113
+ rmSync14(join39(planDir, relativePath), { force: true });
18113
18114
  }
18114
18115
  }
18115
18116
  function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
@@ -18264,19 +18265,19 @@ function createVideoSourceShipper(input) {
18264
18265
  const known = shipped.get(srcPath);
18265
18266
  if (known) return known;
18266
18267
  const stagedRel = pathInside(input.workVideoFramesDir, srcPath);
18267
- const current = stagedRel === null ? srcPath : join40(input.planDir, "video-frames", stagedRel);
18268
+ const current = stagedRel === null ? srcPath : join39(input.planDir, "video-frames", stagedRel);
18268
18269
  let result = null;
18269
18270
  for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
18270
18271
  const rel = pathInside(root, srcPath);
18271
- if (rel !== null && (existsSync26(join40(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
18272
+ if (rel !== null && (existsSync26(join39(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
18272
18273
  result = ["compiled", ...rel.split(sep3)].join("/");
18273
18274
  break;
18274
18275
  }
18275
18276
  }
18276
18277
  if (result === null) {
18277
18278
  result = `video-sources/${shipped.size}${extname6(current)}`;
18278
- const destination = join40(input.planDir, ...result.split("/"));
18279
- mkdirSync16(join40(input.planDir, "video-sources"), { recursive: true });
18279
+ const destination = join39(input.planDir, ...result.split("/"));
18280
+ mkdirSync16(join39(input.planDir, "video-sources"), { recursive: true });
18280
18281
  try {
18281
18282
  linkSync(current, destination);
18282
18283
  } catch {
@@ -18322,17 +18323,18 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
18322
18323
  entryFile: config.entryFile ?? "index.html",
18323
18324
  logger: config.logger,
18324
18325
  producerConfig: cfg,
18325
- variables: config.variables
18326
+ variables: config.variables,
18327
+ pageMotionBlur: config.pageMotionBlur
18326
18328
  });
18327
18329
  const entryFile = config.entryFile ?? "index.html";
18328
- const htmlPath = join40(projectDir, entryFile);
18330
+ const htmlPath = join39(projectDir, entryFile);
18329
18331
  if (!existsSync26(htmlPath)) {
18330
18332
  throw new Error(`[plan] entry file not found: ${htmlPath}`);
18331
18333
  }
18332
- const workDir = join40(planDir, ".plan-work");
18334
+ const workDir = join39(planDir, ".plan-work");
18333
18335
  rmSync14(workDir, { recursive: true, force: true });
18334
18336
  mkdirSync16(workDir, { recursive: true });
18335
- const compiledDir = join40(workDir, "compiled");
18337
+ const compiledDir = join39(workDir, "compiled");
18336
18338
  mkdirSync16(compiledDir, { recursive: true });
18337
18339
  let stageStarted = Date.now();
18338
18340
  cpSync2(projectDir, compiledDir, {
@@ -18346,10 +18348,10 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
18346
18348
  }
18347
18349
  });
18348
18350
  logPlanStage(log, "copy", stageStarted);
18349
- const finalCompiledDir = join40(planDir, "compiled");
18351
+ const finalCompiledDir = join39(planDir, "compiled");
18350
18352
  const needsAlpha = outputNeedsAlpha(config.format);
18351
18353
  const remoteFiles = Object.entries(options.remoteFiles ?? {});
18352
- const remoteLocalPath = (rel) => join40(projectDir, ...rel.split("/"));
18354
+ const remoteLocalPath = (rel) => join39(projectDir, ...rel.split("/"));
18353
18355
  for (const [, file] of remoteFiles) {
18354
18356
  declareContentAddressedUrl(file.url, file.sha256);
18355
18357
  if (file.probeFactsUrl) declareProbeFactsUrl(file.url, file.probeFactsUrl);
@@ -18552,10 +18554,10 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18552
18554
  let stageStarted = Date.now();
18553
18555
  const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
18554
18556
  logPlanStage(log, "extract", stageStarted);
18555
- const stagedVideoFrames = join40(compiledDir, "__hyperframes_video_frames");
18556
- const videoFramesDst = join40(planDir, "video-frames");
18557
+ const stagedVideoFrames = join39(compiledDir, "__hyperframes_video_frames");
18558
+ const videoFramesDst = join39(planDir, "video-frames");
18557
18559
  if (existsSync26(videoFramesDst)) rmSync14(videoFramesDst, { recursive: true, force: true });
18558
- const videoSourcesDir = join40(planDir, "video-sources");
18560
+ const videoSourcesDir = join39(planDir, "video-sources");
18559
18561
  rmSync14(videoSourcesDir, { recursive: true, force: true });
18560
18562
  if (existsSync26(stagedVideoFrames)) {
18561
18563
  renameWithRetry8(stagedVideoFrames, videoFramesDst);
@@ -18592,7 +18594,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18592
18594
  };
18593
18595
  })
18594
18596
  });
18595
- mkdirSync16(join40(planDir, "meta"), { recursive: true });
18597
+ mkdirSync16(join39(planDir, "meta"), { recursive: true });
18596
18598
  writePlanRemoteFiles(
18597
18599
  planDir,
18598
18600
  remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
@@ -18602,7 +18604,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18602
18604
  }))
18603
18605
  );
18604
18606
  writeFileSync10(
18605
- join40(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
18607
+ join39(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
18606
18608
  JSON.stringify(planVideosJson, null, 2),
18607
18609
  "utf-8"
18608
18610
  );
@@ -18682,7 +18684,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
18682
18684
  if (audioResult?.audioError) {
18683
18685
  applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
18684
18686
  }
18685
- const planAudioPath = join40(planDir, PLAN_AUDIO_RELATIVE_PATH);
18687
+ const planAudioPath = join39(planDir, PLAN_AUDIO_RELATIVE_PATH);
18686
18688
  if (audioResult?.hasAudio && existsSync26(audioResult.audioOutputPath)) {
18687
18689
  renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
18688
18690
  }
@@ -18806,7 +18808,7 @@ async function plan(projectDir, config, planDir, options = {}) {
18806
18808
  import { randomBytes } from "node:crypto";
18807
18809
  import { existsSync as existsSync29, mkdirSync as mkdirSync19, readFileSync as readFileSync13, readdirSync as readdirSync11, rmSync as rmSync17, writeFileSync as writeFileSync13 } from "node:fs";
18808
18810
  import { cpus as cpus3 } from "node:os";
18809
- import { join as join44 } from "node:path";
18811
+ import { join as join43 } from "node:path";
18810
18812
  import {
18811
18813
  assertSwiftShader,
18812
18814
  BROWSER_GPU_NOT_SOFTWARE as BROWSER_GPU_NOT_SOFTWARE4,
@@ -18834,7 +18836,6 @@ import {
18834
18836
  existsSync as existsSync28,
18835
18837
  lstatSync as lstatSync3,
18836
18838
  mkdirSync as mkdirSync18,
18837
- mkdtempSync as mkdtempSync6,
18838
18839
  readFileSync as readFileSync12,
18839
18840
  readdirSync as readdirSync10,
18840
18841
  rmSync as rmSync16,
@@ -18842,7 +18843,7 @@ import {
18842
18843
  writeFileSync as writeFileSync12
18843
18844
  } from "node:fs";
18844
18845
  import { tmpdir as tmpdir3 } from "node:os";
18845
- import { dirname as dirname17, isAbsolute as isAbsolute4, join as join43, relative as relative6, resolve as resolve10, sep as sep4 } from "node:path";
18846
+ import { dirname as dirname17, isAbsolute as isAbsolute4, join as join42, relative as relative6, resolve as resolve10, sep as sep4 } from "node:path";
18846
18847
  import { DISTRIBUTED_FPS, isDistributedFps } from "@hyperframes/core";
18847
18848
  import { createFrameLookupTable as createFrameLookupTable5, renameWithRetry as renameWithRetry10 } from "@hyperframes/engine";
18848
18849
 
@@ -18852,13 +18853,12 @@ import {
18852
18853
  existsSync as existsSync27,
18853
18854
  linkSync as linkSync2,
18854
18855
  mkdirSync as mkdirSync17,
18855
- mkdtempSync as mkdtempSync5,
18856
18856
  rmSync as rmSync15,
18857
18857
  statSync as statSync10,
18858
18858
  writeFileSync as writeFileSync11
18859
18859
  } from "node:fs";
18860
18860
  import { renameWithRetry as renameWithRetry9 } from "@hyperframes/engine";
18861
- import { dirname as dirname16, join as join42 } from "node:path";
18861
+ import { dirname as dirname16, join as join41 } from "node:path";
18862
18862
 
18863
18863
  // src/services/distributed/planV2Errors.ts
18864
18864
  var PLAN_V2_INTEGRITY_UNRECOVERABLE = "PLAN_V2_INTEGRITY_UNRECOVERABLE";
@@ -18873,7 +18873,7 @@ var PlanV2IntegrityError = class extends Error {
18873
18873
  };
18874
18874
 
18875
18875
  // src/services/distributed/planV2Layout.ts
18876
- import { join as join41 } from "node:path";
18876
+ import { join as join40 } from "node:path";
18877
18877
  var SHA256_PATTERN = /^[0-9a-f]{64}$/;
18878
18878
  function assertPlanV2Sha256(value, field) {
18879
18879
  if (typeof value !== "string" || !SHA256_PATTERN.test(value)) {
@@ -18883,10 +18883,11 @@ function assertPlanV2Sha256(value, field) {
18883
18883
  }
18884
18884
  function planV2BlobPath(root, sha256) {
18885
18885
  const digest = assertPlanV2Sha256(sha256, "artifact sha256");
18886
- return join41(root, "artifacts", "sha256", digest.slice(0, 2), digest);
18886
+ return join40(root, "artifacts", "sha256", digest.slice(0, 2), digest);
18887
18887
  }
18888
18888
 
18889
18889
  // src/services/distributed/planV2Publisher.ts
18890
+ import { createStagingDir as createStagingDir5 } from "@hyperframes/core/atomic-file";
18890
18891
  function canFallbackToCopy(error) {
18891
18892
  if (!(error instanceof Error) || !("code" in error)) return false;
18892
18893
  const code = error.code;
@@ -18924,7 +18925,7 @@ var LocalPlanV2ArtifactPublisher = class {
18924
18925
  this.destinationDir = destinationDir;
18925
18926
  this.#linkFile = options.linkFile ?? linkSync2;
18926
18927
  mkdirSync17(dirname16(destinationDir), { recursive: true });
18927
- this.temporaryDir = mkdtempSync5(join42(dirname16(destinationDir), ".plan-v2-publish-"));
18928
+ this.temporaryDir = createStagingDir5(dirname16(destinationDir), ".plan-v2-publish-");
18928
18929
  }
18929
18930
  async putBlob(blob) {
18930
18931
  const digest = assertPlanV2Sha256(blob.sha256, "published blob sha256");
@@ -18937,8 +18938,8 @@ var LocalPlanV2ArtifactPublisher = class {
18937
18938
  const destinationPath = planV2BlobPath(this.temporaryDir, digest);
18938
18939
  if (existsSync27(destinationPath)) return;
18939
18940
  mkdirSync17(dirname16(destinationPath), { recursive: true });
18940
- const stagingDir = mkdtempSync5(join42(dirname16(destinationPath), ".plan-v2-blob-"));
18941
- const temporaryPath = join42(stagingDir, "blob");
18941
+ const stagingDir = createStagingDir5(dirname16(destinationPath), ".plan-v2-blob-");
18942
+ const temporaryPath = join41(stagingDir, "blob");
18942
18943
  try {
18943
18944
  try {
18944
18945
  this.#linkFile(blob.sourcePath, temporaryPath);
@@ -18959,7 +18960,7 @@ var LocalPlanV2ArtifactPublisher = class {
18959
18960
  );
18960
18961
  }
18961
18962
  }
18962
- writeFileSync11(join42(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
18963
+ writeFileSync11(join41(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
18963
18964
  renameWithRetry9(this.temporaryDir, this.destinationDir);
18964
18965
  this.#committed = true;
18965
18966
  }
@@ -18971,6 +18972,7 @@ var LocalPlanV2ArtifactPublisher = class {
18971
18972
  };
18972
18973
 
18973
18974
  // src/services/distributed/planV2.ts
18975
+ import { createStagingDir as createStagingDir6 } from "@hyperframes/core/atomic-file";
18974
18976
  var PLAN_V2_HASH_PREFIX = "hyperframes-plan-manifest-hash-v2\0";
18975
18977
  var EXTRACTION_CACHE_COMPLETE_SENTINEL = ".hf-complete";
18976
18978
  var PLAN_V2_MATERIALIZATION_MARKER = ".hyperframes-plan-v2.json";
@@ -19004,7 +19006,7 @@ function listFiles(root) {
19004
19006
  const rootResolved = resolve10(root);
19005
19007
  function walk(dir) {
19006
19008
  for (const entry of readdirSync10(dir, { withFileTypes: true })) {
19007
- const absolutePath = join43(dir, entry.name);
19009
+ const absolutePath = join42(dir, entry.name);
19008
19010
  if (entry.isDirectory()) {
19009
19011
  walk(absolutePath);
19010
19012
  } else if (entry.isFile()) {
@@ -19031,13 +19033,13 @@ function assertValidExtractionCacheCompleteSentinel(path) {
19031
19033
  }
19032
19034
  }
19033
19035
  function validateExtractionCacheCompleteSentinels(executionPlanDir) {
19034
- const videoRoot = join43(executionPlanDir, "video-frames");
19036
+ const videoRoot = join42(executionPlanDir, "video-frames");
19035
19037
  if (!existsSync28(videoRoot)) return;
19036
19038
  for (const videoEntry of readdirSync10(videoRoot, { withFileTypes: true })) {
19037
19039
  if (!videoEntry.isDirectory()) continue;
19038
- const videoDir = join43(videoRoot, videoEntry.name);
19040
+ const videoDir = join42(videoRoot, videoEntry.name);
19039
19041
  if (readdirSync10(videoDir).includes(EXTRACTION_CACHE_COMPLETE_SENTINEL)) {
19040
- const sentinelPath = join43(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
19042
+ const sentinelPath = join42(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
19041
19043
  assertValidExtractionCacheCompleteSentinel(sentinelPath);
19042
19044
  }
19043
19045
  }
@@ -19084,7 +19086,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
19084
19086
  if (video.deferredRange) {
19085
19087
  const framePaths2 = /* @__PURE__ */ new Map();
19086
19088
  for (let index = 0; index < video.totalFrames; index++) {
19087
- framePaths2.set(index, join43(outputDir, String(index)));
19089
+ framePaths2.set(index, join42(outputDir, String(index)));
19088
19090
  }
19089
19091
  return { ...video, outputDir, framePaths: framePaths2, ownedByLookup: false };
19090
19092
  }
@@ -19092,7 +19094,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
19092
19094
  const framePaths = /* @__PURE__ */ new Map();
19093
19095
  for (const frameName of frameNames) {
19094
19096
  if (frameName === EXTRACTION_CACHE_COMPLETE_SENTINEL) {
19095
- assertValidExtractionCacheCompleteSentinel(join43(outputDir, frameName));
19097
+ assertValidExtractionCacheCompleteSentinel(join42(outputDir, frameName));
19096
19098
  continue;
19097
19099
  }
19098
19100
  const match = /(\d+)(?=\.[^.]+$)/.exec(frameName);
@@ -19111,7 +19113,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
19111
19113
  `duplicate extracted frame index ${frameIndex} in ${outputDir}`
19112
19114
  );
19113
19115
  }
19114
- framePaths.set(frameIndex, join43(outputDir, frameName));
19116
+ framePaths.set(frameIndex, join42(outputDir, frameName));
19115
19117
  }
19116
19118
  return {
19117
19119
  ...video,
@@ -19132,7 +19134,7 @@ function parsePlanVideosJson2(value) {
19132
19134
  }
19133
19135
  }
19134
19136
  function materializeExtractedVideoDirectories(planDir) {
19135
- const videosPath = join43(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19137
+ const videosPath = join42(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19136
19138
  if (!existsSync28(videosPath)) return;
19137
19139
  const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
19138
19140
  for (const video of videos.extracted) {
@@ -19166,13 +19168,13 @@ function parseChunkSlices(value) {
19166
19168
  });
19167
19169
  }
19168
19170
  function buildVideoChunkDependencies(executionPlanDir, dimensions) {
19169
- const videoRoot = join43(executionPlanDir, "video-frames");
19171
+ const videoRoot = join42(executionPlanDir, "video-frames");
19170
19172
  const hasExtractedFrames = existsSync28(videoRoot) && listFiles(videoRoot).length > 0;
19171
- const videosPath = join43(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19173
+ const videosPath = join42(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19172
19174
  if (!existsSync28(videosPath)) {
19173
19175
  return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
19174
19176
  }
19175
- const chunksPath = join43(executionPlanDir, "meta", "chunks.json");
19177
+ const chunksPath = join42(executionPlanDir, "meta", "chunks.json");
19176
19178
  const videos = readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH);
19177
19179
  const chunks = readJsonFile(chunksPath, "meta/chunks.json");
19178
19180
  const parsedVideos = parsePlanVideosJson2(videos);
@@ -19228,8 +19230,8 @@ function computeManifestHash(manifest) {
19228
19230
  function writeBlob(sourcePath, destinationPath) {
19229
19231
  if (existsSync28(destinationPath)) return;
19230
19232
  mkdirSync18(dirname17(destinationPath), { recursive: true });
19231
- const temporaryDir = mkdtempSync6(join43(dirname17(destinationPath), ".plan-v2-blob-"));
19232
- const temporaryPath = join43(temporaryDir, "blob");
19233
+ const temporaryDir = createStagingDir6(dirname17(destinationPath), ".plan-v2-blob-");
19234
+ const temporaryPath = join42(temporaryDir, "blob");
19233
19235
  try {
19234
19236
  copyFileSync8(sourcePath, temporaryPath);
19235
19237
  renameWithRetry10(temporaryPath, destinationPath);
@@ -19265,7 +19267,7 @@ async function putTasks(tasks) {
19265
19267
  if (failure) throw failure.reason;
19266
19268
  }
19267
19269
  function buildPlanV2Publication(executionPlanDir, digests) {
19268
- const executionPlanPath = join43(executionPlanDir, "plan.json");
19270
+ const executionPlanPath = join42(executionPlanDir, "plan.json");
19269
19271
  if (!existsSync28(executionPlanPath)) {
19270
19272
  throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
19271
19273
  }
@@ -19293,7 +19295,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
19293
19295
  }
19294
19296
  validateExtractionCacheCompleteSentinels(executionPlanDir);
19295
19297
  const videoDependencyPlan = buildVideoChunkDependencies(executionPlanDir, dimensions);
19296
- const encoder = readJsonFile(join43(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
19298
+ const encoder = readJsonFile(join42(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
19297
19299
  const files = listFiles(executionPlanDir);
19298
19300
  const chunkAudio = !isRecord3(encoder) || encoder.chunksCarryAudio !== true ? "none" : files.some((file) => chunkAudioSliceTarget(file.path) !== null) ? "sliced" : "whole";
19299
19301
  for (const file of files) {
@@ -19354,13 +19356,13 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
19354
19356
  throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
19355
19357
  }
19356
19358
  mkdirSync18(dirname17(planV2Dir), { recursive: true });
19357
- const tempDir = mkdtempSync6(join43(dirname17(planV2Dir), ".plan-v2-build-"));
19359
+ const tempDir = createStagingDir6(dirname17(planV2Dir), ".plan-v2-build-");
19358
19360
  try {
19359
19361
  for (const blob of publication.blobs) {
19360
19362
  writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
19361
19363
  }
19362
19364
  writeFileSync12(
19363
- join43(tempDir, "plan.json"),
19365
+ join42(tempDir, "plan.json"),
19364
19366
  canonicalJsonStringify(publication.manifest),
19365
19367
  "utf-8"
19366
19368
  );
@@ -19401,7 +19403,7 @@ async function publishExecutionPlan(executionPlanDir, publisher, { digests, log
19401
19403
  }
19402
19404
  }
19403
19405
  async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
19404
- const stagingRoot = mkdtempSync6(join43(options.stagingParentDir ?? tmpdir3(), ".execution-plan-"));
19406
+ const stagingRoot = createStagingDir6(options.stagingParentDir ?? tmpdir3(), ".execution-plan-");
19405
19407
  const digests = /* @__PURE__ */ new Map();
19406
19408
  try {
19407
19409
  await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
@@ -19412,7 +19414,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
19412
19414
  // artifactTargets ships every compiled/ file to all chunks, so each is in the manifest.
19413
19415
  whileAudioMixes: () => putBlobs(
19414
19416
  publisher,
19415
- listFiles(join43(stagingRoot, "compiled")).map(
19417
+ listFiles(join42(stagingRoot, "compiled")).map(
19416
19418
  (file) => publishBlobFor(file.absolutePath, digests)
19417
19419
  )
19418
19420
  ),
@@ -19449,7 +19451,7 @@ function resultFromManifest(planV2Dir, manifest) {
19449
19451
  isRecord3(executionPlan) ? executionPlan[REFERENCE_BACKGROUND_FIELD3] : void 0
19450
19452
  ),
19451
19453
  planDir: planV2Dir,
19452
- manifestPath: join43(planV2Dir, "plan.json"),
19454
+ manifestPath: join42(planV2Dir, "plan.json"),
19453
19455
  planProtocol: PLAN_PROTOCOL_V2,
19454
19456
  planHash: manifest.planHash,
19455
19457
  sourcePlanV1Hash: getPlanV2ExecutionPlanHash(manifest),
@@ -19585,7 +19587,7 @@ function parsePlanV2Manifest(value) {
19585
19587
  return parsed;
19586
19588
  }
19587
19589
  function readPlanV2Manifest(planV2Dir) {
19588
- const manifestPath = join43(planV2Dir, "plan.json");
19590
+ const manifestPath = join42(planV2Dir, "plan.json");
19589
19591
  if (!existsSync28(manifestPath)) {
19590
19592
  throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
19591
19593
  }
@@ -19631,16 +19633,16 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
19631
19633
  sourcePath: verifyBlob(planV2Dir, artifact)
19632
19634
  }));
19633
19635
  mkdirSync18(dirname17(destinationDir), { recursive: true });
19634
- const tempDir = mkdtempSync6(join43(dirname17(destinationDir), ".plan-v2-materialize-"));
19636
+ const tempDir = createStagingDir6(dirname17(destinationDir), ".plan-v2-materialize-");
19635
19637
  try {
19636
19638
  for (const { artifact, sourcePath } of verified) {
19637
- const destinationPath = join43(tempDir, ...artifact.path.split("/"));
19639
+ const destinationPath = join42(tempDir, ...artifact.path.split("/"));
19638
19640
  mkdirSync18(dirname17(destinationPath), { recursive: true });
19639
19641
  copyFileSync8(sourcePath, destinationPath);
19640
19642
  }
19641
19643
  if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
19642
19644
  writeFileSync12(
19643
- join43(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
19645
+ join42(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
19644
19646
  canonicalJsonStringify({
19645
19647
  manifest,
19646
19648
  target,
@@ -19663,7 +19665,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
19663
19665
  // Join the artifact's OWN name, not the current constant: a plan written
19664
19666
  // before the container change carries the legacy name, and materializing it
19665
19667
  // under the new one would point at a file that was never written.
19666
- audioPath: target.role === "assembler" ? audioArtifact ? join43(destinationDir, audioArtifact.path) : null : null
19668
+ audioPath: target.role === "assembler" ? audioArtifact ? join42(destinationDir, audioArtifact.path) : null : null
19667
19669
  };
19668
19670
  }
19669
19671
  function assertRemoteSources(remoteSources, artifacts) {
@@ -19682,7 +19684,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
19682
19684
  return readValidatedPlanV2Materialization(planDir, expectedTarget)?.manifest ?? null;
19683
19685
  }
19684
19686
  function readValidatedPlanV2Materialization(planDir, expectedTarget) {
19685
- const markerPath = join43(planDir, PLAN_V2_MATERIALIZATION_MARKER);
19687
+ const markerPath = join42(planDir, PLAN_V2_MATERIALIZATION_MARKER);
19686
19688
  if (!existsSync28(markerPath)) return null;
19687
19689
  const marker = readJsonFile(markerPath, "materialization marker");
19688
19690
  if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
@@ -19700,7 +19702,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
19700
19702
  assertRemoteSources(remoteSources, required);
19701
19703
  for (const artifact of required) {
19702
19704
  if (Object.hasOwn(remoteSources, artifact.path)) continue;
19703
- const path = join43(planDir, ...artifact.path.split("/"));
19705
+ const path = join42(planDir, ...artifact.path.split("/"));
19704
19706
  if (!existsSync28(path) || statSync11(path).size !== artifact.sizeBytes) {
19705
19707
  throw new PlanV2IntegrityError(
19706
19708
  `materialized artifact missing or truncated: ${artifact.path}`
@@ -19832,7 +19834,7 @@ function hashChunkOutput(outputPath, kind) {
19832
19834
  if (kind === "file") return sha256Hex(readFileSync13(outputPath));
19833
19835
  const entries = readdirSync11(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
19834
19836
  const lines = entries.map(
19835
- (name) => `${name}\0${sha256Hex(readFileSync13(join44(outputPath, name)))}`
19837
+ (name) => `${name}\0${sha256Hex(readFileSync13(join43(outputPath, name)))}`
19836
19838
  );
19837
19839
  return sha256Hex(lines.join("\0"));
19838
19840
  }
@@ -19849,9 +19851,9 @@ function resolveLockedVp9CpuUsed(lockedEncoder) {
19849
19851
  async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19850
19852
  const start = Date.now();
19851
19853
  const log = defaultLogger;
19852
- const planJsonPath = join44(planDir, "plan.json");
19853
- const encoderJsonPath = join44(planDir, "meta", "encoder.json");
19854
- const chunksJsonPath = join44(planDir, "meta", "chunks.json");
19854
+ const planJsonPath = join43(planDir, "plan.json");
19855
+ const encoderJsonPath = join43(planDir, "meta", "encoder.json");
19856
+ const chunksJsonPath = join43(planDir, "meta", "chunks.json");
19855
19857
  if (!existsSync29(planJsonPath)) {
19856
19858
  throw new RenderChunkValidationError(
19857
19859
  MISSING_PLAN_ARTIFACT,
@@ -19877,7 +19879,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19877
19879
  }
19878
19880
  const encoder = JSON.parse(readFileSync13(encoderJsonPath, "utf-8"));
19879
19881
  const chunks = JSON.parse(readFileSync13(chunksJsonPath, "utf-8"));
19880
- const videosJsonPath = join44(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19882
+ const videosJsonPath = join43(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
19881
19883
  let planVideos = null;
19882
19884
  if (existsSync29(videosJsonPath)) {
19883
19885
  try {
@@ -19909,7 +19911,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19909
19911
  }
19910
19912
  const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
19911
19913
  const framesInChunk = range.endFrame - range.startFrame;
19912
- const compiledDir = join44(planDir, "compiled");
19914
+ const compiledDir = join43(planDir, "compiled");
19913
19915
  if (!existsSync29(compiledDir)) {
19914
19916
  throw new RenderChunkValidationError(
19915
19917
  MISSING_PLAN_ARTIFACT,
@@ -19952,7 +19954,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19952
19954
  crf: encoder.crf,
19953
19955
  bitrate: encoder.bitrate,
19954
19956
  hdrMode: "force-sdr",
19955
- entryFile: "index.html"
19957
+ entryFile: "index.html",
19958
+ pageMotionBlur: encoder.pageMotionBlur
19956
19959
  });
19957
19960
  job.totalFrames = framesInChunk;
19958
19961
  job.duration = framesInChunk * plan2.dimensions.fpsDen / plan2.dimensions.fpsNum;
@@ -19967,7 +19970,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19967
19970
  };
19968
19971
  const workDir = `${outputChunkPath}.work.${process.pid}.${randomBytes(4).toString("hex")}`;
19969
19972
  mkdirSync19(workDir, { recursive: true });
19970
- const framesDir = join44(workDir, "captured-frames");
19973
+ const framesDir = join43(workDir, "captured-frames");
19971
19974
  mkdirSync19(framesDir, { recursive: true });
19972
19975
  const videoFramesDir = `${workDir}.video-frames`;
19973
19976
  const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
@@ -19992,7 +19995,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
19992
19995
  dimensions: plan2.dimensions,
19993
19996
  encoder,
19994
19997
  videoCount: planVideos?.videos.length ?? 0,
19995
- html: readFileSync13(join44(compiledDir, "index.html"), "utf-8"),
19998
+ html: readFileSync13(join43(compiledDir, "index.html"), "utf-8"),
19996
19999
  // The plan ships a deferred source only to chunks that show it; don't wait on the rest.
19997
20000
  skipReadinessVideoIds: deferredVideos.filter(
19998
20001
  (video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
@@ -20162,7 +20165,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
20162
20165
  if (isPngSequence) {
20163
20166
  if (!existsSync29(outputChunkPath)) mkdirSync19(outputChunkPath, { recursive: true });
20164
20167
  } else {
20165
- const outDir = join44(outputChunkPath, "..");
20168
+ const outDir = join43(outputChunkPath, "..");
20166
20169
  if (!existsSync29(outDir)) mkdirSync19(outDir, { recursive: true });
20167
20170
  }
20168
20171
  const encodeInput = {
@@ -20436,10 +20439,10 @@ async function renderSpan(projectDir, config, span, outputPath) {
20436
20439
  if (config.cfr === true) {
20437
20440
  throw new RenderSpanUnsupportedError("--start/--end cannot be combined with a cfr re-encode.");
20438
20441
  }
20439
- const workDir = mkdtempSync7(join45(tmpdir4(), "hf-render-span-"));
20442
+ const workDir = mkdtempSync(join44(tmpdir4(), "hf-render-span-"));
20440
20443
  try {
20441
- const planDir = join45(workDir, "plan");
20442
- const partsDir = join45(workDir, "parts");
20444
+ const planDir = join44(workDir, "plan");
20445
+ const partsDir = join44(workDir, "parts");
20443
20446
  mkdirSync20(partsDir, { recursive: true });
20444
20447
  const planned = await plan(
20445
20448
  projectDir,
@@ -20454,7 +20457,7 @@ async function renderSpan(projectDir, config, span, outputPath) {
20454
20457
  planned.totalFrames
20455
20458
  );
20456
20459
  const slices = JSON.parse(
20457
- readFileSync14(join45(planDir, "meta", "chunks.json"), "utf-8")
20460
+ readFileSync14(join44(planDir, "meta", "chunks.json"), "utf-8")
20458
20461
  );
20459
20462
  const parts = [];
20460
20463
  for (const slice of slices) {
@@ -20464,7 +20467,7 @@ async function renderSpan(projectDir, config, span, outputPath) {
20464
20467
  };
20465
20468
  if (range.endFrame <= range.startFrame) continue;
20466
20469
  throwIfAborted(config.abortSignal);
20467
- const part = join45(partsDir, `part-${String(parts.length).padStart(4, "0")}.mp4`);
20470
+ const part = join44(partsDir, `part-${String(parts.length).padStart(4, "0")}.mp4`);
20468
20471
  await renderChunk(planDir, slice.index, part, { frameRange: range });
20469
20472
  parts.push(part);
20470
20473
  }
@@ -21083,12 +21086,12 @@ import {
21083
21086
  existsSync as existsSync32,
21084
21087
  mkdirSync as mkdirSync21,
21085
21088
  statSync as statSync13,
21086
- mkdtempSync as mkdtempSync8,
21089
+ mkdtempSync as mkdtempSync2,
21087
21090
  writeFileSync as writeFileSync14,
21088
21091
  rmSync as rmSync19,
21089
21092
  createReadStream as createReadStream5
21090
21093
  } from "node:fs";
21091
- import { resolve as resolve12, dirname as dirname19, join as join48 } from "node:path";
21094
+ import { resolve as resolve12, dirname as dirname19, join as join47 } from "node:path";
21092
21095
  import { tmpdir as tmpdir5 } from "node:os";
21093
21096
  import { parseArgs } from "node:util";
21094
21097
  import crypto from "node:crypto";
@@ -21111,7 +21114,7 @@ import {
21111
21114
  closeSync as closeSync7,
21112
21115
  constants as constants3
21113
21116
  } from "node:fs";
21114
- import { resolve as resolve11, join as join46, relative as relative7, isAbsolute as isAbsolute5, sep as sep5 } from "node:path";
21117
+ import { resolve as resolve11, join as join45, relative as relative7, isAbsolute as isAbsolute5, sep as sep5 } from "node:path";
21115
21118
  import { lintHyperframeHtml } from "@hyperframes/lint";
21116
21119
  function isStringRecord(value) {
21117
21120
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -21179,7 +21182,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
21179
21182
  }
21180
21183
  }
21181
21184
  return {
21182
- error: `No HTML entry file found in project directory: ${join46(absProjectDir, preferredEntryFile || "index.html")}`
21185
+ error: `No HTML entry file found in project directory: ${join45(absProjectDir, preferredEntryFile || "index.html")}`
21183
21186
  };
21184
21187
  }
21185
21188
  function prepareHyperframeLintBody(body) {
@@ -21225,7 +21228,7 @@ async function runHyperframeLint(prepared) {
21225
21228
  // src/services/healthWorker.ts
21226
21229
  import { Worker as Worker2 } from "node:worker_threads";
21227
21230
  import { fileURLToPath as fileURLToPath6 } from "node:url";
21228
- import { dirname as dirname18, join as join47 } from "node:path";
21231
+ import { dirname as dirname18, join as join46 } from "node:path";
21229
21232
  import { existsSync as existsSync31 } from "node:fs";
21230
21233
  var DEFAULT_HEALTH_PORT = 9848;
21231
21234
  async function startHealthWorker(options = {}) {
@@ -21301,7 +21304,7 @@ function defaultLogger2() {
21301
21304
  }
21302
21305
  function resolveWorkerEntry2() {
21303
21306
  const here = dirname18(fileURLToPath6(import.meta.url));
21304
- const candidates = [join47(here, "healthWorkerThread.js"), join47(here, "healthWorkerThread.ts")];
21307
+ const candidates = [join46(here, "healthWorkerThread.js"), join46(here, "healthWorkerThread.ts")];
21305
21308
  for (const candidate of candidates) {
21306
21309
  if (existsSync31(candidate)) return candidate;
21307
21310
  }
@@ -21515,8 +21518,8 @@ async function resolveInlineRenderHtml(body) {
21515
21518
  }
21516
21519
  function materializeInlineProject(html, options) {
21517
21520
  const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir5();
21518
- const tempProjectDir = mkdtempSync8(join48(tempRoot, "producer-project-"));
21519
- writeFileSync14(join48(tempProjectDir, "index.html"), html, "utf-8");
21521
+ const tempProjectDir = mkdtempSync2(join47(tempRoot, "producer-project-"));
21522
+ writeFileSync14(join47(tempProjectDir, "index.html"), html, "utf-8");
21520
21523
  return {
21521
21524
  prepared: {
21522
21525
  input: { projectDir: tempProjectDir, ...options },
@@ -21985,9 +21988,9 @@ import {
21985
21988
  import { quantizeTimeToFrame, MEDIA_VISUAL_STYLE_PROPERTIES } from "@hyperframes/engine";
21986
21989
 
21987
21990
  // src/services/distributed/planV2Execution.ts
21988
- import { mkdtempSync as mkdtempSync10, rmSync as rmSync21 } from "node:fs";
21991
+ import { mkdtempSync as mkdtempSync3, rmSync as rmSync21 } from "node:fs";
21989
21992
  import { tmpdir as tmpdir6 } from "node:os";
21990
- import { join as join50 } from "node:path";
21993
+ import { join as join49 } from "node:path";
21991
21994
 
21992
21995
  // src/services/distributed/assemble.ts
21993
21996
  import {
@@ -21998,14 +22001,13 @@ import {
21998
22001
  cpSync as cpSync3,
21999
22002
  existsSync as existsSync33,
22000
22003
  mkdirSync as mkdirSync22,
22001
- mkdtempSync as mkdtempSync9,
22002
22004
  readFileSync as readFileSync16,
22003
22005
  readdirSync as readdirSync12,
22004
22006
  rmSync as rmSync20,
22005
22007
  statSync as statSync14,
22006
22008
  writeFileSync as writeFileSync15
22007
22009
  } from "node:fs";
22008
- import { dirname as dirname20, join as join49 } from "node:path";
22010
+ import { basename as basename8, dirname as dirname20, join as join48 } from "node:path";
22009
22011
  import {
22010
22012
  appendRateCapArgs as appendRateCapArgs2,
22011
22013
  appendRenderProvenanceArgs as appendRenderProvenanceArgs2,
@@ -22019,6 +22021,7 @@ import {
22019
22021
  renameWithRetry as renameWithRetry11
22020
22022
  } from "@hyperframes/engine";
22021
22023
  import { fpsToFfmpegArg as fpsToFfmpegArg3 } from "@hyperframes/core";
22024
+ import { createStagingDir as createStagingDir7 } from "@hyperframes/core/atomic-file";
22022
22025
  function cfrRateControlArgs(locked) {
22023
22026
  const preset = getEncoderPreset6(locked.quality ?? "standard", "mp4");
22024
22027
  if (locked.crf == null && locked.bitrate) {
@@ -22054,7 +22057,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
22054
22057
  if (!existsSync33(dirname20(outputPath))) {
22055
22058
  mkdirSync22(dirname20(outputPath), { recursive: true });
22056
22059
  }
22057
- const workDir = mkdtempSync9(`${outputPath}.assemble-work-`);
22060
+ const workDir = createStagingDir7(dirname20(outputPath), `${basename8(outputPath)}.assemble-work-`);
22058
22061
  const fps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
22059
22062
  const stageMs = {};
22060
22063
  const ctx = {
@@ -22074,7 +22077,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
22074
22077
  };
22075
22078
  try {
22076
22079
  const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
22077
- const finalPath = join49(workDir, `output.${format}`);
22080
+ const finalPath = join48(workDir, `output.${format}`);
22078
22081
  const audio = audioPath !== null && existsSync33(audioPath) ? audioPath : null;
22079
22082
  await writeJoined(ctx, videoSources, audio, finalPath);
22080
22083
  renameWithRetry11(finalPath, outputPath);
@@ -22103,8 +22106,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
22103
22106
  };
22104
22107
  }
22105
22108
  function readAssemblePlan(planDir, chunkPaths) {
22106
- const planJsonPath = join49(planDir, "plan.json");
22107
- const chunksJsonPath = join49(planDir, "meta", "chunks.json");
22109
+ const planJsonPath = join48(planDir, "plan.json");
22110
+ const chunksJsonPath = join48(planDir, "meta", "chunks.json");
22108
22111
  if (!existsSync33(planJsonPath)) {
22109
22112
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
22110
22113
  }
@@ -22155,7 +22158,7 @@ function cfrEncodeArgs(inputArgs, encoder, fpsArg) {
22155
22158
  return args;
22156
22159
  }
22157
22160
  async function reencodeCfr(ctx, chunkPaths, encoder) {
22158
- const cfrOutputPath = join49(ctx.workDir, `cfr.${ctx.format}`);
22161
+ const cfrOutputPath = join48(ctx.workDir, `cfr.${ctx.format}`);
22159
22162
  const cfrArgs = cfrEncodeArgs(videoInputArgs(ctx, chunkPaths), encoder, ctx.fpsArg);
22160
22163
  appendRenderProvenanceArgs2(cfrArgs, cfrOutputPath);
22161
22164
  cfrArgs.push("-y", cfrOutputPath);
@@ -22182,7 +22185,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
22182
22185
  );
22183
22186
  return;
22184
22187
  }
22185
- const paddedAudioPath = join49(ctx.workDir, "audio-padded.m4a");
22188
+ const paddedAudioPath = join48(ctx.workDir, "audio-padded.m4a");
22186
22189
  const padTrimResult = await ctx.timed(
22187
22190
  "audioMs",
22188
22191
  () => padOrTrimAudioToVideoFrameCount({
@@ -22222,7 +22225,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
22222
22225
  }
22223
22226
  }
22224
22227
  function concatDemuxerInput(chunkPaths, workDir, fpsArg) {
22225
- const listPath = join49(workDir, "concat-list.txt");
22228
+ const listPath = join48(workDir, "concat-list.txt");
22226
22229
  const body = chunkPaths.map((path) => `file '${path.replace(/'/g, "'\\''")}'`).join("\n");
22227
22230
  writeFileSync15(listPath, `${body}
22228
22231
  `, "utf-8");
@@ -22260,11 +22263,11 @@ function stitchesSeparateAudio(planDir) {
22260
22263
  return lockedAudio(planDir).separateAudio === true;
22261
22264
  }
22262
22265
  function planFormat(planDir) {
22263
- const plan2 = JSON.parse(readFileSync16(join49(planDir, "plan.json"), "utf-8"));
22266
+ const plan2 = JSON.parse(readFileSync16(join48(planDir, "plan.json"), "utf-8"));
22264
22267
  return plan2.dimensions.format;
22265
22268
  }
22266
22269
  function lockedAudio(planDir) {
22267
- const encoderJsonPath = join49(planDir, "meta", "encoder.json");
22270
+ const encoderJsonPath = join48(planDir, "meta", "encoder.json");
22268
22271
  if (!existsSync33(encoderJsonPath)) return {};
22269
22272
  return JSON.parse(readFileSync16(encoderJsonPath, "utf-8"));
22270
22273
  }
@@ -22274,7 +22277,7 @@ function readCfrEncoder(planDir, format) {
22274
22277
  `[assemble] cfr=true is only supported for format="mp4" (got "${format}"). Stream-copy paths for webm and mov already produce exact avg_frame_rate; cfr re-encode is not needed.`
22275
22278
  );
22276
22279
  }
22277
- const encoderJsonPath = join49(planDir, "meta", "encoder.json");
22280
+ const encoderJsonPath = join48(planDir, "meta", "encoder.json");
22278
22281
  if (!existsSync33(encoderJsonPath)) {
22279
22282
  throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
22280
22283
  }
@@ -22301,8 +22304,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
22301
22304
  throw new Error(`[assemble] png-sequence chunk has no frames: ${chunkDir}`);
22302
22305
  }
22303
22306
  for (const frame of frames) {
22304
- const dst = join49(outputPath, formatExportFrameName(globalIdx, "png"));
22305
- cpSync3(join49(chunkDir, frame), dst);
22307
+ const dst = join48(outputPath, formatExportFrameName(globalIdx, "png"));
22308
+ cpSync3(join48(chunkDir, frame), dst);
22306
22309
  globalIdx += 1;
22307
22310
  }
22308
22311
  }
@@ -22312,13 +22315,13 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
22312
22315
  );
22313
22316
  }
22314
22317
  if (audioPath !== null && existsSync33(audioPath)) {
22315
- const sidecar = join49(outputPath, MIXED_AUDIO_FILENAME4);
22318
+ const sidecar = join48(outputPath, MIXED_AUDIO_FILENAME4);
22316
22319
  cpSync3(audioPath, sidecar);
22317
22320
  }
22318
22321
  let fileSize = 0;
22319
22322
  for (const name of readdirSync12(outputPath)) {
22320
22323
  try {
22321
- fileSize += statSync14(join49(outputPath, name)).size;
22324
+ fileSize += statSync14(join48(outputPath, name)).size;
22322
22325
  } catch {
22323
22326
  }
22324
22327
  }
@@ -22332,8 +22335,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
22332
22335
 
22333
22336
  // src/services/distributed/planV2Execution.ts
22334
22337
  async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
22335
- const workRoot = mkdtempSync10(join50(tmpdir6(), "hf-plan-v2-chunk-"));
22336
- const materializedPlanDir = join50(workRoot, "plan");
22338
+ const workRoot = mkdtempSync3(join49(tmpdir6(), "hf-plan-v2-chunk-"));
22339
+ const materializedPlanDir = join49(workRoot, "plan");
22337
22340
  try {
22338
22341
  materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
22339
22342
  return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
@@ -22342,8 +22345,8 @@ async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
22342
22345
  }
22343
22346
  }
22344
22347
  async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
22345
- const workRoot = mkdtempSync10(join50(tmpdir6(), "hf-plan-v2-assembler-"));
22346
- const materializedPlanDir = join50(workRoot, "plan");
22348
+ const workRoot = mkdtempSync3(join49(tmpdir6(), "hf-plan-v2-assembler-"));
22349
+ const materializedPlanDir = join49(workRoot, "plan");
22347
22350
  try {
22348
22351
  const materialized = materializePlanV2Target(
22349
22352
  planV2Dir,