@hyperframes/producer 0.8.181 → 0.8.184

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.
@@ -48,6 +48,8 @@ import {
48
48
  extractMediaMetadata as extractMediaMetadata4,
49
49
  resolveConfig as resolveConfig2,
50
50
  closeCaptureSession as closeCaptureSession8,
51
+ createCaptureSession as createCaptureSession8,
52
+ initializeSession as initializeSession8,
51
53
  createVideoFrameInjector,
52
54
  getEncoderPreset as getEncoderPreset3,
53
55
  distributeFrames as distributeFrames2,
@@ -1421,7 +1423,7 @@ function pidScope() {
1421
1423
  return {
1422
1424
  host: hostname(),
1423
1425
  // Without /proc (macOS, Windows) the boot time, to the minute, stands in for the boot id.
1424
- boot: attempt(() => readFileSync2("/proc/sys/kernel/random/boot_id", "utf-8").trim()) ?? String(Math.round(Date.now() / 6e4 - uptime() / 60)),
1426
+ boot: attempt(() => readFileSync2("/proc/sys/kernel/random/boot_id", "utf-8").trim()) ?? attempt(() => String(Math.round(Date.now() / 6e4 - uptime() / 60))),
1425
1427
  pidns: attempt(() => readlinkSync("/proc/self/ns/pid"))
1426
1428
  };
1427
1429
  }
@@ -1439,9 +1441,14 @@ function alive(pid) {
1439
1441
  return error.code === "EPERM";
1440
1442
  }
1441
1443
  }
1442
- function inThisPidScope(owner) {
1444
+ function knownPidScope() {
1443
1445
  const scope = pidScope();
1444
- return owner.host === scope.host && owner.boot === scope.boot && owner.pidns === scope.pidns;
1446
+ const unknown = scope.boot === void 0 || process.platform === "linux" && scope.pidns === void 0;
1447
+ return unknown ? void 0 : scope;
1448
+ }
1449
+ function inThisPidScope(owner) {
1450
+ const scope = knownPidScope();
1451
+ return scope !== void 0 && owner.host === scope.host && owner.boot === scope.boot && owner.pidns === scope.pidns;
1445
1452
  }
1446
1453
  function ownerState(dir) {
1447
1454
  let owner;
@@ -1506,7 +1513,9 @@ async function defaultArtifactDurationProbe(path) {
1506
1513
  const meta = await extractMediaMetadata(path);
1507
1514
  return {
1508
1515
  durationSeconds: meta.durationSeconds,
1509
- frames: meta.frames
1516
+ frames: meta.frames,
1517
+ width: meta.width,
1518
+ height: meta.height
1510
1519
  };
1511
1520
  }
1512
1521
  function buildArtifactExpectation(input) {
@@ -1515,7 +1524,9 @@ function buildArtifactExpectation(input) {
1515
1524
  const expectation = {
1516
1525
  expectedDurationSeconds: input.durationSeconds,
1517
1526
  fps: input.fps,
1518
- expectedFrames: input.expectedFrames
1527
+ expectedFrames: input.expectedFrames,
1528
+ expectedWidth: input.width,
1529
+ expectedHeight: input.height
1519
1530
  };
1520
1531
  if (input.outputFormat !== "hls") return expectation;
1521
1532
  return {
@@ -1583,6 +1594,16 @@ function assertFrameCountWithinTolerance(expectedFrames, probedFrames, stagingPa
1583
1594
  `Render artifact is truncated: expected ${expectedFrames} frames, probed ${probedFrames} frames (shortfall ${shortfall} frames). Artifact: ${stagingPath}`
1584
1595
  );
1585
1596
  }
1597
+ function assertSizeMatches(expected, probed, stagingPath) {
1598
+ const { expectedWidth: width, expectedHeight: height } = expected;
1599
+ if (width === void 0 || height === void 0) return;
1600
+ if (probed.width === void 0 || probed.height === void 0) return;
1601
+ const fits = (want, got) => got === want || got === want + want % 2;
1602
+ if (fits(width, probed.width) && fits(height, probed.height)) return;
1603
+ throw new Error(
1604
+ `Render artifact has the wrong size: expected ${width}x${height}, probed ${probed.width}x${probed.height}. Artifact: ${stagingPath}`
1605
+ );
1606
+ }
1586
1607
  var ArtifactTransaction = class {
1587
1608
  constructor(destinationPath, kind, fileSystem = defaultFileSystem, durationProbe = defaultArtifactDurationProbe) {
1588
1609
  this.kind = kind;
@@ -1653,6 +1674,7 @@ var ArtifactTransaction = class {
1653
1674
  if (expected.expectedFrames !== void 0) {
1654
1675
  assertFrameCountWithinTolerance(expected.expectedFrames, probed.frames, probePath);
1655
1676
  }
1677
+ assertSizeMatches(expected, probed, probePath);
1656
1678
  }
1657
1679
  async runDurationProbe(probePath) {
1658
1680
  try {
@@ -3201,7 +3223,9 @@ function aggregateDrawElement(perfs, de) {
3201
3223
  if (perfs.length === 0) return void 0;
3202
3224
  const modes = [...new Set(perfs.map((p) => p.captureMode).filter(Boolean))].sort();
3203
3225
  const gateReasons = [
3204
- ...new Set(perfs.map((p) => p.deGateReason).filter((r) => !!r))
3226
+ ...new Set(
3227
+ [de.probeGateReason, ...perfs.map((p) => p.deGateReason)].filter((r) => !!r)
3228
+ )
3205
3229
  ].sort();
3206
3230
  const gpuRenderers = [
3207
3231
  ...new Set(perfs.map((p) => p.gpuRenderer).filter((r) => !!r))
@@ -8665,6 +8689,7 @@ async function runAudioStage(input) {
8665
8689
  audios,
8666
8690
  masterFxChain,
8667
8691
  urlByAbsentLocalPath,
8692
+ keepEncoderInputAt,
8668
8693
  abortSignal,
8669
8694
  assertNotAborted,
8670
8695
  log
@@ -8684,7 +8709,13 @@ async function runAudioStage(input) {
8684
8709
  audioOutputPath,
8685
8710
  duration,
8686
8711
  abortSignal,
8687
- { ffmpegProcessTimeout, audioGain, masterFxChain, urlByAbsentLocalPath },
8712
+ {
8713
+ ffmpegProcessTimeout,
8714
+ audioGain,
8715
+ masterFxChain,
8716
+ urlByAbsentLocalPath,
8717
+ keepEncoderInputAt
8718
+ },
8688
8719
  compiledDir
8689
8720
  );
8690
8721
  } catch (err) {
@@ -8798,13 +8829,29 @@ function inspectDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, free
8798
8829
  }
8799
8830
  return { available: false, estimatedBytes, freeBytes };
8800
8831
  }
8801
- function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis) {
8832
+ function diskCaptureRemedy(cfg, outputFormat, durationSeconds, workerCount) {
8833
+ const oneWorker = explainStreamingEncodeGate(cfg, outputFormat, 1, durationSeconds);
8834
+ if (workerCount > 1 && oneWorker.enabled) {
8835
+ return `This render stores frames because it captures with ${workerCount} workers. Free up disk space, or re-run this render with --workers 1 to stream frames into the encoder instead. One worker is slower, so keep the default worker count for renders that fit on disk.`;
8836
+ }
8837
+ switch (oneWorker.reason) {
8838
+ case "format_excluded":
8839
+ return `${outputFormat} output stores every frame at any worker count. Free up disk space or render to mp4.`;
8840
+ case "disabled_by_config":
8841
+ return "PRODUCER_ENABLE_STREAMING_ENCODE=false sends every render to disk. Free up disk space or unset it.";
8842
+ case "duration_cap":
8843
+ return "The streaming duration cap (PRODUCER_STREAMING_ENCODE_DURATION_CAP_ENABLED=true) sends renders longer than PRODUCER_STREAMING_ENCODE_MAX_DURATION_SECONDS to disk at any worker count. Free up disk space, unset the cap, or use --low-memory-mode, which streams past it on one worker.";
8844
+ default:
8845
+ return "Free up disk space.";
8846
+ }
8847
+ }
8848
+ function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis, remedy) {
8802
8849
  const basisNote = basis === "measured" ? ` (measured from the first ${DISK_PROJECTION_SAMPLE_FRAMES} frames)` : "";
8803
8850
  return new Error(
8804
- `Disk capture may need ~${(needBytes / 1e6).toFixed(1)} MB of temporary frame storage${basisNote}, but only ${(freeBytes / 1e6).toFixed(1)} MB is free at ${framesDir}. Disk capture stores every frame as an image file (JPEG, or PNG for alpha). mp4/mov renders stream instead: always at --workers 1, and multi-worker on Linux BeginFrame capture. This render landed on disk because the output is png-sequence or gif, because it is multi-worker screenshot capture (opt in with HF_CAPTURE_PARALLEL_STREAM=true), or because streaming was switched off: HF_CAPTURE_PARALLEL_STREAM=false, PRODUCER_ENABLE_STREAMING_ENCODE=false, or the duration cap (PRODUCER_STREAMING_ENCODE_DURATION_CAP_ENABLED=true) on a render longer than PRODUCER_STREAMING_ENCODE_MAX_DURATION_SECONDS. HDR and shader-transition renders never reach this check; they run their own compositor. Re-run with --workers 1, use --low-memory-mode, or free up disk space.`
8851
+ `Disk capture may need ~${(needBytes / 1e6).toFixed(1)} MB of temporary frame storage${basisNote}, but only ${(freeBytes / 1e6).toFixed(1)} MB is free at ${framesDir}. Disk capture stores every frame as an image file (JPEG, or PNG for alpha). ${remedy}`
8805
8852
  );
8806
8853
  }
8807
- function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeDiskBytes) {
8854
+ function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, remedy, freeDiskBytes) {
8808
8855
  const headroom = inspectDiskCaptureHeadroom(
8809
8856
  framesDir,
8810
8857
  totalFrames,
@@ -8816,7 +8863,8 @@ function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeD
8816
8863
  headroom.estimatedBytes,
8817
8864
  headroom.freeBytes,
8818
8865
  framesDir,
8819
- "estimate"
8866
+ "estimate",
8867
+ remedy
8820
8868
  );
8821
8869
  }
8822
8870
  function measureCaptureFrameBytes(workDir, framesDir) {
@@ -8836,7 +8884,7 @@ function measureCaptureFrameBytes(workDir, framesDir) {
8836
8884
  return total;
8837
8885
  }
8838
8886
  function createDiskCaptureProjection(input) {
8839
- const { framesDir, totalFrames, measureBytes, freeDiskBytes = freeDiskBytesAt } = input;
8887
+ const { framesDir, totalFrames, measureBytes, remedy, freeDiskBytes = freeDiskBytesAt } = input;
8840
8888
  let checked = false;
8841
8889
  return (capturedFrames) => {
8842
8890
  if (checked || capturedFrames < DISK_PROJECTION_SAMPLE_FRAMES) return;
@@ -8848,7 +8896,7 @@ function createDiskCaptureProjection(input) {
8848
8896
  if (remaining <= 0 || freeBytes === null) return;
8849
8897
  const needBytes = Math.ceil(measured / capturedFrames * remaining);
8850
8898
  if (needBytes > freeBytes * 0.9) {
8851
- throw diskCaptureShortfallError(needBytes, freeBytes, framesDir, "measured");
8899
+ throw diskCaptureShortfallError(needBytes, freeBytes, framesDir, "measured", remedy);
8852
8900
  }
8853
8901
  };
8854
8902
  }
@@ -8890,11 +8938,13 @@ async function runCaptureStage(input) {
8890
8938
  }
8891
8939
  }
8892
8940
  const captureOptions = buildCaptureOptions();
8893
- assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions);
8941
+ const remedy = diskCaptureRemedy(cfg, job.config.format ?? "mp4", job.duration ?? 0, workerCount);
8942
+ assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, remedy);
8894
8943
  const checkDiskProjection = createDiskCaptureProjection({
8895
8944
  framesDir,
8896
8945
  totalFrames,
8897
- measureBytes: () => measureCaptureFrameBytes(workDir, framesDir)
8946
+ measureBytes: () => measureCaptureFrameBytes(workDir, framesDir),
8947
+ remedy
8898
8948
  });
8899
8949
  if (workerCount > 1) {
8900
8950
  const attempts = await executeDiskCaptureWithAdaptiveRetry({
@@ -8915,6 +8965,7 @@ async function runCaptureStage(input) {
8915
8965
  if (progress.capturedFrames === 0) reportWorkerStartup(job, progress, onProgress);
8916
8966
  return;
8917
8967
  }
8968
+ if (progress.landedFrame) input.onFrameLanded?.(progress.landedFrame);
8918
8969
  job.framesRendered = progress.capturedFrames;
8919
8970
  checkDiskProjection(progress.capturedFrames);
8920
8971
  const frameProgress = progress.capturedFrames / progress.totalFrames;
@@ -10084,6 +10135,7 @@ import {
10084
10135
  statSync as statSync5,
10085
10136
  writeFileSync as writeFileSync4
10086
10137
  } from "node:fs";
10138
+ import { readFile as readFile2 } from "node:fs/promises";
10087
10139
  import { dirname as dirname8, join as join24 } from "node:path";
10088
10140
  import {
10089
10141
  encodeFramesChunkedConcat,
@@ -10091,7 +10143,8 @@ import {
10091
10143
  formatFfmpegError,
10092
10144
  MIXED_AUDIO_FILENAME as MIXED_AUDIO_FILENAME2,
10093
10145
  resolveConfig,
10094
- runFfmpeg as runFfmpeg3
10146
+ runFfmpeg as runFfmpeg3,
10147
+ spawnStreamingEncoder as spawnStreamingEncoder4
10095
10148
  } from "@hyperframes/engine";
10096
10149
  import {
10097
10150
  clearGifFramesBeforeNext,
@@ -10105,8 +10158,10 @@ function fpsToFfmpegArg2(fps) {
10105
10158
  }
10106
10159
  var KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA = ["-reinit_filter", "0"];
10107
10160
  var WRITE_EVERY_FRAME_WHOLE = ["-gifflags", "0"];
10161
+ var FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE = ["-xerror"];
10108
10162
  function framesInput(input, fpsArg) {
10109
10163
  return [
10164
+ ...FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE,
10110
10165
  "-framerate",
10111
10166
  fpsArg,
10112
10167
  ...KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA,
@@ -10226,6 +10281,124 @@ function startEncodeProgress(job, stage, onProgress) {
10226
10281
  });
10227
10282
  return (frames = total) => reportEncodeProgress(job, frames, total, onProgress, 75);
10228
10283
  }
10284
+ function resolveEngineConfig(input) {
10285
+ return input.engineConfig ?? input.job.config.producerConfig ?? resolveConfig();
10286
+ }
10287
+ function videoEncoderOptions(input, engineCfg) {
10288
+ const { job, preset } = input;
10289
+ return {
10290
+ fps: job.config.fps,
10291
+ width: input.width,
10292
+ height: input.height,
10293
+ codec: preset.codec,
10294
+ preset: preset.preset,
10295
+ quality: input.effectiveQuality,
10296
+ bitrate: input.effectiveBitrate,
10297
+ pixelFormat: preset.pixelFormat,
10298
+ vp9CpuUsed: engineCfg.vp9CpuUsed,
10299
+ useGpu: job.config.useGpu,
10300
+ hdr: preset.hdr,
10301
+ // Distributed chunk renders pass these so the encoder writes closed-GOP
10302
+ // keyframes that survive `-f concat -c copy` at assemble time. In-process
10303
+ // renders leave both undefined → preserves the existing open-GOP output.
10304
+ lockGopForChunkConcat: input.lockGopForChunkConcat === true,
10305
+ gopSize: input.gopSize
10306
+ };
10307
+ }
10308
+ function canEncodeWhileCapturing(input, workerCount, cpuCount) {
10309
+ return workerCount > 1 && workerCount < cpuCount && !input.isPngSequence && !input.isGif && !input.enableChunkedEncode && input.preset.codec === "h264" && !input.preset.hdr && input.job.config.useGpu !== true && input.captureImageFormat === "jpeg" && input.lockGopForChunkConcat !== true;
10310
+ }
10311
+ async function readLandedFrame(workerPath, mergedPath) {
10312
+ if (workerPath !== void 0) {
10313
+ try {
10314
+ return await readFile2(workerPath);
10315
+ } catch (error) {
10316
+ if (error.code !== "ENOENT") throw error;
10317
+ }
10318
+ }
10319
+ return readFile2(mergedPath);
10320
+ }
10321
+ function encodeWhileCapturing(input, totalFrames) {
10322
+ const engineCfg = resolveEngineConfig(input);
10323
+ const stop = new AbortController();
10324
+ const signal = input.abortSignal ? AbortSignal.any([input.abortSignal, stop.signal]) : stop.signal;
10325
+ const landed = /* @__PURE__ */ new Map();
10326
+ let captureDone = false;
10327
+ let framesFed = 0;
10328
+ let wake = null;
10329
+ const nudge = () => {
10330
+ wake?.();
10331
+ wake = null;
10332
+ };
10333
+ signal.addEventListener("abort", nudge, { once: true });
10334
+ let reportFed = null;
10335
+ const encoder = spawnStreamingEncoder4(
10336
+ input.videoOnlyPath,
10337
+ { ...videoEncoderOptions(input, engineCfg), imageFormat: "jpeg" },
10338
+ signal,
10339
+ engineCfg
10340
+ );
10341
+ const fed = (async () => {
10342
+ const stream = await encoder;
10343
+ for (let next = 0; next < totalFrames; next++) {
10344
+ while (!landed.has(next) && !captureDone && !signal.aborted) {
10345
+ await new Promise((resolve10) => wake = resolve10);
10346
+ }
10347
+ if (signal.aborted) return;
10348
+ const mergedPath = join24(input.framesDir, formatCaptureFrameName(next, "jpg"));
10349
+ const frame = await readLandedFrame(landed.get(next), mergedPath);
10350
+ landed.delete(next);
10351
+ if (!await stream.writeFrame(frame)) {
10352
+ throw new Error(stream.getExitError() ?? "encoder exited before the last frame");
10353
+ }
10354
+ framesFed++;
10355
+ reportFed?.(framesFed);
10356
+ }
10357
+ })().then(
10358
+ () => void 0,
10359
+ (error) => error ?? new Error("encode failed")
10360
+ );
10361
+ const closeEncoder = async () => (await encoder.catch(() => null))?.close();
10362
+ return {
10363
+ onFrameLanded: (frame) => {
10364
+ landed.set(frame.index, frame.path);
10365
+ nudge();
10366
+ },
10367
+ finish: async () => {
10368
+ const start = Date.now();
10369
+ captureDone = true;
10370
+ input.log.info("[Render] Encoded frames while capturing", {
10371
+ framesFed,
10372
+ totalFrames
10373
+ });
10374
+ const encoded = startEncodeProgress(input.job, "Encoding video", input.onProgress);
10375
+ reportFed = encoded;
10376
+ nudge();
10377
+ const failure = await fed;
10378
+ const result = await closeEncoder();
10379
+ input.assertNotAborted();
10380
+ if (failure === void 0 && result?.success) {
10381
+ encoded();
10382
+ return { encodeMs: Date.now() - start };
10383
+ }
10384
+ input.log.warn(
10385
+ "[Render] Encoding while capturing failed; encoding the frames after capture",
10386
+ {
10387
+ error: String(failure ?? result?.error)
10388
+ }
10389
+ );
10390
+ return runEncodeStage(input);
10391
+ },
10392
+ abort: async () => {
10393
+ stop.abort();
10394
+ await fed;
10395
+ await closeEncoder();
10396
+ },
10397
+ get framesFed() {
10398
+ return framesFed;
10399
+ }
10400
+ };
10401
+ }
10229
10402
  async function runEncodeStage(input) {
10230
10403
  const {
10231
10404
  job,
@@ -10233,16 +10406,11 @@ async function runEncodeStage(input) {
10233
10406
  outputPath,
10234
10407
  framesDir,
10235
10408
  videoOnlyPath,
10236
- width,
10237
- height,
10238
10409
  needsAlpha,
10239
10410
  hasAudio,
10240
10411
  audioOutputPath,
10241
10412
  isPngSequence,
10242
10413
  isGif,
10243
- preset,
10244
- effectiveQuality,
10245
- effectiveBitrate,
10246
10414
  enableChunkedEncode,
10247
10415
  chunkedEncodeSize,
10248
10416
  abortSignal,
@@ -10272,7 +10440,7 @@ async function runEncodeStage(input) {
10272
10440
  encoded();
10273
10441
  return { encodeMs: Date.now() - stage5Start };
10274
10442
  }
10275
- const engineCfg = input.engineConfig ?? job.config.producerConfig ?? resolveConfig();
10443
+ const engineCfg = resolveEngineConfig(input);
10276
10444
  if (isGif) {
10277
10445
  const encoded = startEncodeProgress(job, "Encoding GIF", onProgress);
10278
10446
  if (hasAudio) {
@@ -10302,24 +10470,7 @@ async function runEncodeStage(input) {
10302
10470
  const videoEngineCfg = scaledEncodeTimeout > engineCfg.ffmpegEncodeTimeout ? { ...engineCfg, ffmpegEncodeTimeout: scaledEncodeTimeout } : engineCfg;
10303
10471
  const frameExt = frameFileExtension2(input.captureImageFormat);
10304
10472
  const framePattern = `frame_%06d.${frameExt}`;
10305
- const encoderOpts = {
10306
- fps: job.config.fps,
10307
- width,
10308
- height,
10309
- codec: preset.codec,
10310
- preset: preset.preset,
10311
- quality: effectiveQuality,
10312
- bitrate: effectiveBitrate,
10313
- pixelFormat: preset.pixelFormat,
10314
- vp9CpuUsed: engineCfg.vp9CpuUsed,
10315
- useGpu: job.config.useGpu,
10316
- hdr: preset.hdr,
10317
- // Distributed chunk renders pass these so the encoder writes closed-GOP
10318
- // keyframes that survive `-f concat -c copy` at assemble time. In-process
10319
- // renders leave both undefined → preserves the existing open-GOP output.
10320
- lockGopForChunkConcat: input.lockGopForChunkConcat === true,
10321
- gopSize: input.gopSize
10322
- };
10473
+ const encoderOpts = videoEncoderOptions(input, engineCfg);
10323
10474
  const encodeResult = enableChunkedEncode ? await encodeFramesChunkedConcat(
10324
10475
  framesDir,
10325
10476
  framePattern,
@@ -10357,7 +10508,8 @@ import { dirname as dirname9, join as join25 } from "node:path";
10357
10508
  import {
10358
10509
  DEFAULT_CONFIG,
10359
10510
  describeFfmpegFailure as describeFfmpegFailure2,
10360
- extractAudioMetadata as extractAudioMetadata2,
10511
+ encodeAac,
10512
+ extractAudioMetadata as extractAudioMetadata3,
10361
10513
  getFfprobeBinary,
10362
10514
  ManagedChildProcess,
10363
10515
  runFfmpeg as runFfmpeg5,
@@ -10366,7 +10518,12 @@ import {
10366
10518
  import { redactKnownPaths, redactTelemetryString as redactTelemetryString3 } from "@hyperframes/core";
10367
10519
 
10368
10520
  // src/services/render/audioTruePeak.ts
10369
- import { aacSegmentCount, describeFfmpegFailure, runFfmpeg as runFfmpeg4 } from "@hyperframes/engine";
10521
+ import {
10522
+ aacSegmentCount,
10523
+ describeFfmpegFailure,
10524
+ extractAudioMetadata as extractAudioMetadata2,
10525
+ runFfmpeg as runFfmpeg4
10526
+ } from "@hyperframes/engine";
10370
10527
  var toDbfs = (token) => token.toLowerCase() === "-inf" ? Number.NEGATIVE_INFINITY : Number(token);
10371
10528
  function checkedDbfs(value) {
10372
10529
  if (Number.isNaN(value) || value === Number.POSITIVE_INFINITY) {
@@ -10404,12 +10561,13 @@ async function scanTruePeak(audioPath, trim, timeoutMs, signal) {
10404
10561
  };
10405
10562
  }
10406
10563
  async function measureTruePeakDbfs(audioPath, options) {
10407
- const { timeoutMs, signal, segments } = options;
10564
+ const { timeoutMs, signal } = options;
10408
10565
  const wholeFile = async () => (await scanTruePeak(audioPath, "", timeoutMs, signal)).peak;
10566
+ const { durationSeconds, sampleRate } = await extractAudioMetadata2(audioPath, { signal });
10409
10567
  const block = 4800;
10410
- const count = segments?.sampleRate === 48e3 ? aacSegmentCount(segments.durationSeconds) : 1;
10411
- if (!segments || count === 1) return wholeFile();
10412
- const cut = (k) => k * Math.floor(segments.durationSeconds * 10 / count) * block;
10568
+ const count = sampleRate === 48e3 && Number.isFinite(durationSeconds) ? aacSegmentCount(durationSeconds) : 1;
10569
+ if (count === 1) return wholeFile();
10570
+ const cut = (k) => k * Math.floor(durationSeconds * 10 / count) * block;
10413
10571
  const peers = new AbortController();
10414
10572
  const segmentSignal = signal ? AbortSignal.any([signal, peers.signal]) : peers.signal;
10415
10573
  const scans = await Promise.all(
@@ -10438,24 +10596,8 @@ var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
10438
10596
  var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
10439
10597
  var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
10440
10598
  var MAX_TRUE_PEAK_CORRECTION_PASSES = 3;
10441
- function buildAacTruePeakCorrectionArgs(inputPath, outputPath, targetDurationSeconds, attenuationDb) {
10442
- return [
10443
- "-i",
10444
- inputPath,
10445
- "-map",
10446
- "0:a:0",
10447
- "-vn",
10448
- "-af",
10449
- `volume=${attenuationDb.toFixed(3)}dB`,
10450
- "-t",
10451
- formatSeconds(targetDurationSeconds),
10452
- "-c:a",
10453
- "aac",
10454
- "-b:a",
10455
- "192k",
10456
- "-y",
10457
- outputPath
10458
- ];
10599
+ function aacTruePeakCorrectionFilter(targetDurationSeconds, attenuationDb) {
10600
+ return `volume=${attenuationDb.toFixed(3)}dB,apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
10459
10601
  }
10460
10602
  function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, targetDurationSeconds) {
10461
10603
  const delta = targetDurationSeconds - sourceDurationSeconds;
@@ -10470,53 +10612,13 @@ function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, tar
10470
10612
  if (delta > 0) {
10471
10613
  return {
10472
10614
  operation: "pad",
10473
- steps: [
10474
- {
10475
- kind: "normalize",
10476
- args: [
10477
- "-i",
10478
- audioPath,
10479
- "-af",
10480
- `apad,atrim=0:${targetSec}`,
10481
- "-t",
10482
- targetSec,
10483
- "-c:a",
10484
- "aac",
10485
- "-b:a",
10486
- "192k",
10487
- "-y",
10488
- outputPath
10489
- ]
10490
- }
10491
- ],
10615
+ steps: [{ kind: "normalize", filter: `apad,atrim=0:${targetSec}` }],
10492
10616
  cleanupPaths: []
10493
10617
  };
10494
10618
  }
10495
10619
  return {
10496
10620
  operation: "trim",
10497
- steps: [
10498
- {
10499
- kind: "trim",
10500
- args: [
10501
- "-i",
10502
- audioPath,
10503
- "-af",
10504
- `atrim=duration=${targetSec},asetpts=PTS-STARTPTS`,
10505
- // `atrim` limits decoded samples but does not cap muxer timestamps
10506
- // introduced by encoder delay/flush. The output duration contract
10507
- // is enforced at the container boundary as well; without `-t`, a
10508
- // long primed source can retain its original tail after re-encode.
10509
- "-t",
10510
- targetSec,
10511
- "-c:a",
10512
- "aac",
10513
- "-b:a",
10514
- "192k",
10515
- "-y",
10516
- outputPath
10517
- ]
10518
- }
10519
- ],
10621
+ steps: [{ kind: "trim", filter: `atrim=duration=${targetSec},asetpts=PTS-STARTPTS` }],
10520
10622
  cleanupPaths: []
10521
10623
  };
10522
10624
  }
@@ -10533,7 +10635,8 @@ async function padOrTrimAudioToVideoFrameCount(input) {
10533
10635
  const probeAudio = input.probeAudioInfo ?? defaultProbeAudioInfo;
10534
10636
  const timeoutMs = input.timeoutMs ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
10535
10637
  const runner = input.runFfmpeg ?? ((args) => defaultRunFfmpeg(args, timeoutMs, input.signal));
10536
- const probeTruePeak = input.probeAudioTruePeakDbfs ?? (input.runFfmpeg ? void 0 : (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }));
10638
+ const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal);
10639
+ const probeTruePeak = input.probeAudioTruePeakDbfs ?? (input.runFfmpeg || input.encodeAac ? void 0 : (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }));
10537
10640
  const [videoResult, audioResult] = await Promise.allSettled([
10538
10641
  probeVideo(input.videoPath),
10539
10642
  probeAudio(input.audioPath, input.signal)
@@ -10580,7 +10683,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
10580
10683
  );
10581
10684
  try {
10582
10685
  for (const step of plan.steps) {
10583
- const ffmpegResult = await runner(step.args);
10686
+ const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(input.audioPath, input.outputPath, targetDurationSeconds, step.filter);
10584
10687
  if (!ffmpegResult.success) {
10585
10688
  return {
10586
10689
  success: false,
@@ -10612,7 +10715,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
10612
10715
  targetDurationSeconds,
10613
10716
  signal: input.signal,
10614
10717
  probeTruePeak,
10615
- runner
10718
+ encode
10616
10719
  });
10617
10720
  if (!correction.success) {
10618
10721
  return {
@@ -10660,13 +10763,11 @@ async function enforceAacTruePeak(input) {
10660
10763
  }
10661
10764
  if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
10662
10765
  attenuationDb += correctionTargetDbfs - truePeakDbfs;
10663
- const result = await input.runner(
10664
- buildAacTruePeakCorrectionArgs(
10665
- input.audioPath,
10666
- correctedPath,
10667
- input.targetDurationSeconds,
10668
- attenuationDb
10669
- )
10766
+ const result = await input.encode(
10767
+ input.audioPath,
10768
+ correctedPath,
10769
+ input.targetDurationSeconds,
10770
+ aacTruePeakCorrectionFilter(input.targetDurationSeconds, attenuationDb)
10670
10771
  );
10671
10772
  if (!result.success) {
10672
10773
  return {
@@ -10761,7 +10862,7 @@ function parseFrameRate(rate) {
10761
10862
  return { fpsNum, fpsDen };
10762
10863
  }
10763
10864
  async function defaultProbeAudioInfo(audioPath, signal) {
10764
- const metadata = await extractAudioMetadata2(audioPath, { signal });
10865
+ const metadata = await extractAudioMetadata3(audioPath, { signal });
10765
10866
  return {
10766
10867
  durationSeconds: metadata.durationSeconds,
10767
10868
  sampleRate: metadata.sampleRate,
@@ -10770,7 +10871,18 @@ async function defaultProbeAudioInfo(audioPath, signal) {
10770
10871
  };
10771
10872
  }
10772
10873
  async function defaultRunFfmpeg(args, timeoutMs, signal) {
10773
- const result = await runFfmpeg5(args, { signal, timeout: timeoutMs });
10874
+ return toStepResult(await runFfmpeg5(args, { signal, timeout: timeoutMs }), timeoutMs);
10875
+ }
10876
+ function defaultAacEncoder(timeoutMs, signal, pcmSourcePath) {
10877
+ return async (inputPath, outputPath, durationSeconds, filter) => {
10878
+ const options = pcmSourcePath ? { signal, timeout: timeoutMs, filter } : { signal, timeout: timeoutMs, filter, segments: 1 };
10879
+ return toStepResult(
10880
+ await encodeAac(pcmSourcePath ?? inputPath, outputPath, durationSeconds, options),
10881
+ timeoutMs
10882
+ );
10883
+ };
10884
+ }
10885
+ function toStepResult(result, timeoutMs) {
10774
10886
  if (result.success) return { success: true };
10775
10887
  return {
10776
10888
  success: false,
@@ -10958,7 +11070,7 @@ function assertOutputScaleSupported(deviceScaleFactor, route) {
10958
11070
  const reason = UNSUPPORTED_REASON2[route];
10959
11071
  if (reason === null) return;
10960
11072
  throw new Error(
10961
- `[Render] --resolution other than the composition's size is not supported on the "${route}" capture route: ${reason}. Render at the composition's size, or as mp4 with page-side compositing.`
11073
+ `[Render] --resolution other than the composition's size is not supported on the "${route}" capture route: ${reason}. Render at the composition's size; or, for HDR footage, add --sdr to render this size in standard colour; or, for shader transitions, render as mp4.`
10962
11074
  );
10963
11075
  }
10964
11076
 
@@ -11175,7 +11287,7 @@ function getNextRetryWorkerCount(currentWorkers) {
11175
11287
  return Math.max(1, Math.floor(currentWorkers / 2));
11176
11288
  }
11177
11289
  function resolveRenderWorkDirPrefix(outputPath, jobId, platform2 = process.platform, systemTempDir = tmpdir2()) {
11178
- if (platform2 === "win32") return join26(systemTempDir, "hf-render-");
11290
+ if (platform2 === "win32" || platform2 === "darwin") return join26(systemTempDir, "hf-render-");
11179
11291
  return join26(dirname10(outputPath), `work-${jobId}-`);
11180
11292
  }
11181
11293
  var MAX_TRANSIENT_CAPTURE_RETRIES = 1;
@@ -11669,6 +11781,9 @@ function resolveDeShortBand(args) {
11669
11781
  function shouldPreferSingleWorkerDrawElement(args) {
11670
11782
  return args.workerCount > 1 && typeof args.requestedWorkers !== "number" && args.useDrawElement && !args.deCompileGate && !args.forceScreenshot && outputUsesH264Pipeline(args.outputFormat) && args.minFrames > 0 && args.totalFrames >= args.minFrames && args.singleWorkerStreamingOk && !args.layeredOrEffectRoute && !args.supersampling && !args.probeDeGated && !args.experimentalParallelDeOptIn;
11671
11783
  }
11784
+ function isProbeDeGated(session) {
11785
+ return session !== null && session.captureMode !== "drawelement" && !session.deInitDeferred;
11786
+ }
11672
11787
  function resolveInversionRetryPlan(args) {
11673
11788
  if (args.deWorkerInversion !== "inverted") return null;
11674
11789
  const workerCount = args.isMemoryExhaustion ? 1 : args.preInversionWorkerCount;
@@ -11750,7 +11865,8 @@ async function closeOrphanedProbeForRetry(probe, closer, log, retryContext) {
11750
11865
  }
11751
11866
  function resolveParallelCaptureMode(args) {
11752
11867
  const supersampling = (args.deviceScaleFactor ?? 1) !== 1;
11753
- return args.headlessShell && args.platform === "linux" && !args.forceScreenshot && !supersampling ? "beginframe" : "screenshot";
11868
+ const headlessShell = args.headlessShellPath !== void 0;
11869
+ return headlessShell && args.platform === "linux" && !args.forceScreenshot && !supersampling ? "beginframe" : "screenshot";
11754
11870
  }
11755
11871
  function isCaptureParallelStreamRouterEnabled(env, resolvedMode) {
11756
11872
  const raw = env.HF_CAPTURE_PARALLEL_STREAM?.trim().toLowerCase();
@@ -12358,6 +12474,7 @@ async function executeRenderPipeline(input) {
12358
12474
  );
12359
12475
  const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
12360
12476
  const hasHdrContent = Boolean(effectiveHdr && nativeHdrIds.size > 0);
12477
+ if (hasHdrContent) assertOutputScaleSupported(deviceScaleFactor, "hdr_layered");
12361
12478
  const deSingleMinFramesRaw = process.env.HF_DE_SINGLE_MIN_FRAMES;
12362
12479
  const deSingleMinFramesNum = deSingleMinFramesRaw === void 0 || deSingleMinFramesRaw.trim() === "" ? 900 : Number(deSingleMinFramesRaw);
12363
12480
  const deSingleMinFrames = Number.isFinite(deSingleMinFramesNum) ? deSingleMinFramesNum : 900;
@@ -12398,7 +12515,7 @@ async function executeRenderPipeline(input) {
12398
12515
  singleWorkerStreamingOk: shouldUseStreamingEncode(cfg, outputFormat, 1, job.duration),
12399
12516
  layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
12400
12517
  supersampling: deviceScaleFactor !== 1,
12401
- probeDeGated: probeSession !== null && probeSession.captureMode !== "drawelement" && !probeSession.deInitDeferred,
12518
+ probeDeGated: isProbeDeGated(probeSession),
12402
12519
  experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || // Verified parallel DE streaming (opt-in) wants its parallelism kept.
12403
12520
  process.env.HF_DE_PARALLEL_STREAM === "true"
12404
12521
  };
@@ -12407,14 +12524,14 @@ async function executeRenderPipeline(input) {
12407
12524
  ...deInversionArgs,
12408
12525
  minFrames: Math.min(deSingleMinFrames, deShortBandMinFrames)
12409
12526
  });
12410
- const deShortBand = resolveDeShortBand({
12527
+ let deShortBand = resolveDeShortBand({
12411
12528
  invertAtBaseFloor,
12412
12529
  invertAtBandFloor,
12413
12530
  bandEnabled: deShortBandEnabled,
12414
12531
  bandOpen: deShortBandOpen,
12415
12532
  elementCountSource: compositionElementCountSource
12416
12533
  });
12417
- const deInversionEligible = deShortBandRoute && deShortBand === "applied" ? invertAtBandFloor : invertAtBaseFloor;
12534
+ let deInversionEligible = deShortBandRoute && deShortBand === "applied" ? invertAtBandFloor : invertAtBaseFloor;
12418
12535
  const deInversionEffectiveMinFrames = deShortBandRoute && deShortBand === "applied" ? Math.min(deSingleMinFrames, deShortBandMinFrames) : deSingleMinFrames;
12419
12536
  const deParallelRouterEnabled = isDeParallelRouterEnabled(process.env);
12420
12537
  const deParallelMinFramesRaw = process.env.HF_DE_PARALLEL_MIN_FRAMES;
@@ -12423,7 +12540,7 @@ async function executeRenderPipeline(input) {
12423
12540
  const deParallelMinMemRaw = process.env.HF_DE_PARALLEL_MIN_MEM_MB;
12424
12541
  const deParallelMinMemNum = deParallelMinMemRaw === void 0 || deParallelMinMemRaw.trim() === "" ? 24576 : Number(deParallelMinMemRaw);
12425
12542
  const deParallelMinMemoryMb = Number.isFinite(deParallelMinMemNum) ? deParallelMinMemNum : 24576;
12426
- const deParallelRouterEligible = shouldPreferParallelDrawElement({
12543
+ let deParallelRouterEligible = shouldPreferParallelDrawElement({
12427
12544
  workerCount: WOULD_RESOLVE_MULTI_WORKER,
12428
12545
  requestedWorkers: job.config.workers,
12429
12546
  useDrawElement: cfg.useDrawElement,
@@ -12434,7 +12551,7 @@ async function executeRenderPipeline(input) {
12434
12551
  minFrames: deParallelMinFrames,
12435
12552
  layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
12436
12553
  supersampling: deviceScaleFactor !== 1,
12437
- probeDeGated: probeSession !== null && probeSession.captureMode !== "drawelement" && !probeSession.deInitDeferred,
12554
+ probeDeGated: isProbeDeGated(probeSession),
12438
12555
  experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || process.env.HF_DE_PARALLEL_STREAM === "true",
12439
12556
  routerEnabled: deParallelRouterEnabled,
12440
12557
  // Router pins 3 workers for the streaming path; don't pin when a
@@ -12450,6 +12567,35 @@ async function executeRenderPipeline(input) {
12450
12567
  totalMemoryMb: Math.round(totalmem2() / (1024 * 1024)),
12451
12568
  minMemoryMb: deParallelMinMemoryMb
12452
12569
  });
12570
+ if (probeSession === null && (deInversionEligible || deParallelRouterEligible)) {
12571
+ try {
12572
+ probeSession = await createCaptureSession8(
12573
+ activeFileServer.url,
12574
+ framesDir,
12575
+ buildCaptureOptions(),
12576
+ null,
12577
+ { ...cfg, forceScreenshot: captureForceScreenshot }
12578
+ );
12579
+ await initializeSession8(probeSession);
12580
+ } catch (error) {
12581
+ assertNotAborted();
12582
+ if (probeSession) {
12583
+ lastBrowserConsole = probeSession.browserConsoleBuffer;
12584
+ await closeCaptureSession8(probeSession).catch(() => {
12585
+ });
12586
+ probeSession = null;
12587
+ }
12588
+ log.warn("[Render] Fast capture gate check failed; routing without it.", {
12589
+ error: error instanceof Error ? error.message : String(error)
12590
+ });
12591
+ }
12592
+ if (isProbeDeGated(probeSession)) {
12593
+ deInversionEligible = false;
12594
+ deParallelRouterEligible = false;
12595
+ deShortBand = void 0;
12596
+ }
12597
+ }
12598
+ const deProbeGateReason = isProbeDeGated(probeSession) ? probeSession.deGateReason : void 0;
12453
12599
  let workerCount;
12454
12600
  const captureStageObservationData = (extra = {}) => ({
12455
12601
  stagePhase: "capturing",
@@ -12637,7 +12783,7 @@ async function executeRenderPipeline(input) {
12637
12783
  }
12638
12784
  const parallelCaptureMode = resolveParallelCaptureMode({
12639
12785
  platform: process.platform,
12640
- headlessShell: resolveHeadlessShellPath(cfg) !== null,
12786
+ headlessShellPath: resolveHeadlessShellPath(cfg),
12641
12787
  forceScreenshot: captureForceScreenshot,
12642
12788
  deviceScaleFactor: captureOptions.deviceScaleFactor
12643
12789
  });
@@ -13239,6 +13385,34 @@ async function executeRenderPipeline(input) {
13239
13385
  throw new Error(`Disk capture requires sdr_disk plan; got ${capturePlan.kind}`);
13240
13386
  }
13241
13387
  resetCaptureAttemptProgress(job);
13388
+ const encodeInput = {
13389
+ job,
13390
+ log,
13391
+ outputPath: stagedOutputPath,
13392
+ framesDir,
13393
+ videoOnlyPath,
13394
+ width,
13395
+ height,
13396
+ needsAlpha,
13397
+ captureImageFormat: captureOptions.format ?? "jpeg",
13398
+ hasAudio,
13399
+ audioOutputPath,
13400
+ isPngSequence,
13401
+ isGif,
13402
+ preset,
13403
+ effectiveQuality,
13404
+ effectiveBitrate,
13405
+ enableChunkedEncode,
13406
+ chunkedEncodeSize,
13407
+ engineConfig: cfg,
13408
+ // Same value the streaming encoder above spreads — the disk and
13409
+ // chunked-concat encoders need an identical GOP lock for HLS.
13410
+ ...hlsEncoderGopLock,
13411
+ abortSignal: executionSignal,
13412
+ assertNotAborted,
13413
+ onProgress
13414
+ };
13415
+ const overlap = !cfg.useDrawElement && workerSizing !== void 0 && canEncodeWhileCapturing(encodeInput, capturePlan.workerCount, workerSizing.cpuCount) ? encodeWhileCapturing(encodeInput, totalFrames) : null;
13242
13416
  const captureFrameStart = Date.now();
13243
13417
  const invokeDiskCapture = (diskPlan) => observeRenderStage(
13244
13418
  observability,
@@ -13260,13 +13434,15 @@ async function executeRenderPipeline(input) {
13260
13434
  createRenderVideoFrameInjector,
13261
13435
  abortSignal: executionSignal,
13262
13436
  assertNotAborted,
13263
- onProgress
13437
+ onProgress,
13438
+ onFrameLanded: (frame) => overlap?.onFrameLanded(frame)
13264
13439
  })
13265
13440
  );
13266
13441
  let captureRes;
13267
13442
  try {
13268
13443
  captureRes = await invokeDiskCapture(capturePlan);
13269
13444
  } catch (err) {
13445
+ await overlap?.abort();
13270
13446
  if (!isDrawElementVerificationError(err) && !isDrawElementCaptureError(err) || err instanceof RenderCancelledError || executionSignal?.aborted === true) {
13271
13447
  throw err;
13272
13448
  }
@@ -13335,33 +13511,7 @@ async function executeRenderPipeline(input) {
13335
13511
  isGif,
13336
13512
  chunkedEncode: enableChunkedEncode
13337
13513
  }),
13338
- () => runEncodeStage({
13339
- job,
13340
- log,
13341
- outputPath: stagedOutputPath,
13342
- framesDir,
13343
- videoOnlyPath,
13344
- width,
13345
- height,
13346
- needsAlpha,
13347
- captureImageFormat: captureOptions.format ?? "jpeg",
13348
- hasAudio,
13349
- audioOutputPath,
13350
- isPngSequence,
13351
- isGif,
13352
- preset,
13353
- effectiveQuality,
13354
- effectiveBitrate,
13355
- enableChunkedEncode,
13356
- chunkedEncodeSize,
13357
- engineConfig: cfg,
13358
- // Same value the streaming encoder above spreads — the disk and
13359
- // chunked-concat encoders need an identical GOP lock for HLS.
13360
- ...hlsEncoderGopLock,
13361
- abortSignal: executionSignal,
13362
- assertNotAborted,
13363
- onProgress
13364
- })
13514
+ () => overlap ? overlap.finish() : runEncodeStage(encodeInput)
13365
13515
  );
13366
13516
  perfStages.encodeMs = encodeRes.encodeMs;
13367
13517
  }
@@ -13409,7 +13559,9 @@ async function executeRenderPipeline(input) {
13409
13559
  outputFormat,
13410
13560
  durationSeconds: job.duration,
13411
13561
  fps: fpsToNumber9(job.config.fps),
13412
- expectedFrames: captureTotalFrames
13562
+ expectedFrames: captureTotalFrames,
13563
+ width: outputWidth,
13564
+ height: outputHeight
13413
13565
  })
13414
13566
  );
13415
13567
  const totalElapsed = Date.now() - pipelineStart;
@@ -13445,6 +13597,7 @@ async function executeRenderPipeline(input) {
13445
13597
  drawElement: {
13446
13598
  compileGate: deCompileGate,
13447
13599
  clampReason: deClampReason,
13600
+ probeGateReason: deProbeGateReason,
13448
13601
  workerInversion: deWorkerInversion,
13449
13602
  preInversionWorkers: deWorkerInversion ? preRoutingWorkerCount : void 0,
13450
13603
  compositionElementCount,
@@ -13846,9 +13999,9 @@ import {
13846
13999
  // src/services/distributed/planFrameCost.ts
13847
14000
  import {
13848
14001
  closeCaptureSession as closeCaptureSession9,
13849
- createCaptureSession as createCaptureSession8,
14002
+ createCaptureSession as createCaptureSession9,
13850
14003
  createFrameLookupTable as createFrameLookupTable3,
13851
- initializeSession as initializeSession8
14004
+ initializeSession as initializeSession9
13852
14005
  } from "@hyperframes/engine";
13853
14006
 
13854
14007
  // src/services/distributed/chunkFrames.ts