@hyperframes/producer 0.8.179 → 0.8.180

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.
@@ -33,8 +33,8 @@ export { buildChunkSlices, measurePlanDirBytes, plan, rejectUnsupportedDistribut
33
33
  export { createPlanV2FromExecutionPlan, createPlanV2FromV1, getPlanV2ExecutionPlanHash, isPlanV2DeferredSourceArtifact, listPlanV2ArtifactsForTarget, materializePlanV2Target, planV2, planV2WithPublisher, publishPlanV2FromExecutionPlan, publishPlanV2FromV1, readPlanV2Manifest, validatePlanV2MaterializedTarget, PLAN_V2_INTEGRITY_UNRECOVERABLE, PLAN_V2_MATERIALIZATION_MARKER, PlanV2IntegrityError, type PlanV2Artifact, type PlanV2Limitations, type PlanV2Manifest, type PlanV2MaterializeOptions, type PlanV2MaterializationResult, type PlanV2MaterializationTarget, type PlanV2RemoteSources, type PlanV2Result, type PlanV2WithPublisherOptions, } from "./services/distributed/planV2.js";
34
34
  export { LocalPlanV2ArtifactPublisher, type LocalPlanV2ArtifactPublisherOptions, type PlanV2ArtifactPublisher, type PlanV2PublishBlob, } from "./services/distributed/planV2Publisher.js";
35
35
  export { assembleV2, renderChunkV2 } from "./services/distributed/planV2Execution.js";
36
- export { applyRuntimeEnvSnapshot, readWebGlVendorInfoFromCanvas, renderChunk, type ChunkRenderer, type ChunkResult, type EffectiveChunkResult, FFMPEG_VERSION_MISMATCH, INVALID_VIDEO_METADATA, PLAN_HASH_MISMATCH, RenderChunkValidationError, } from "./services/distributed/renderChunk.js";
37
- export { assemble, chunksAreStitchedMp4, type AssembleResult, } from "./services/distributed/assemble.js";
36
+ export { applyRuntimeEnvSnapshot, readWebGlVendorInfoFromCanvas, renderChunk, type ChunkFrameRange, type ChunkRenderer, type ChunkResult, type EffectiveChunkResult, type RenderChunkOptions, CHUNK_FRAME_RANGE_INVALID, FFMPEG_VERSION_MISMATCH, INVALID_VIDEO_METADATA, PLAN_HASH_MISMATCH, RenderChunkValidationError, } from "./services/distributed/renderChunk.js";
37
+ export { assemble, chunksAreStitchedMp4, type AssembleChunkPaths, type AssembleResult, } from "./services/distributed/assemble.js";
38
38
  export { muxChunkWithAudio } from "./services/distributed/chunkAudio.js";
39
39
  export { buildStitchedHeader, readMp4Layout, type Mp4Layout, type ReadRange, } from "./services/distributed/mp4Stitch.js";
40
40
  export { InvalidConfigError, type SerializableDistributedRenderConfig, validateDistributedRenderConfig, validateVariablesPayload, } from "./services/distributed/renderConfigValidation.js";
@@ -6773,6 +6773,7 @@ var FFMPEG_VERSION_MISMATCH = "FFMPEG_VERSION_MISMATCH";
6773
6773
  var PLAN_HASH_MISMATCH = "PLAN_HASH_MISMATCH";
6774
6774
  var MISSING_PLAN_ARTIFACT = "MISSING_PLAN_ARTIFACT";
6775
6775
  var CHUNK_INDEX_OUT_OF_RANGE = "CHUNK_INDEX_OUT_OF_RANGE";
6776
+ var CHUNK_FRAME_RANGE_INVALID = "CHUNK_FRAME_RANGE_INVALID";
6776
6777
  var MISSING_RUNTIME_ENV_SNAPSHOT = "MISSING_RUNTIME_ENV_SNAPSHOT";
6777
6778
  var RenderChunkValidationError = class extends Error {
6778
6779
  code;
@@ -7024,7 +7025,8 @@ var DISTRIBUTED_RENDER_CAPABILITIES = Object.freeze({
7024
7025
  accepts: Object.freeze([PLAN_PROTOCOL_V1, PLAN_PROTOCOL_V2]),
7025
7026
  acceptsLegacyV1WithoutDescriptor: true
7026
7027
  })
7027
- })
7028
+ }),
7029
+ chunkFrameRange: true
7028
7030
  });
7029
7031
  function getDistributedRenderCapabilities() {
7030
7032
  return DISTRIBUTED_RENDER_CAPABILITIES;
@@ -7739,6 +7741,18 @@ function audioCutForChunk(grid, chunks, index, fps) {
7739
7741
  const durationSeconds = end === grid.packetCount ? null : cutSeconds(end) - (seekSeconds ?? 0);
7740
7742
  return { seekSeconds, durationSeconds, firstPacket: first, packetCount: end - first };
7741
7743
  }
7744
+ function chunksWithSubRange(chunks, index, range) {
7745
+ const slice = chunks[index];
7746
+ const parts = [
7747
+ { startFrame: slice.startFrame, endFrame: range.startFrame },
7748
+ range,
7749
+ { startFrame: range.endFrame, endFrame: slice.endFrame }
7750
+ ].filter((part) => part.endFrame > part.startFrame);
7751
+ const split = [...chunks.slice(0, index), ...parts, ...chunks.slice(index + 1)].map(
7752
+ (chunk, i) => ({ index: i, startFrame: chunk.startFrame, endFrame: chunk.endFrame })
7753
+ );
7754
+ return { chunks: split, index: range.startFrame > slice.startFrame ? index + 1 : index };
7755
+ }
7742
7756
  async function probeAacPacketGrid(audioPath) {
7743
7757
  const probe = await runFfprobeJson([
7744
7758
  "-v",
@@ -9699,11 +9713,12 @@ function cfrRateControlArgs(locked) {
9699
9713
  }
9700
9714
  return ["-preset", preset.preset, "-crf", String(locked.crf ?? preset.quality)];
9701
9715
  }
9702
- async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
9716
+ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
9703
9717
  const start = Date.now();
9704
9718
  const log = options?.logger ?? defaultLogger;
9705
9719
  const cfr = options?.cfr === true;
9706
- const plan2 = readAssemblePlan(planDir, chunkPaths);
9720
+ const plan2 = readAssemblePlan(planDir, chunkOutputs);
9721
+ const chunkPaths = chunkOutputs.flat();
9707
9722
  if (plan2.dimensions.format === "png-sequence") {
9708
9723
  return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
9709
9724
  }
@@ -9786,7 +9801,12 @@ function readAssemblePlan(planDir, chunkPaths) {
9786
9801
  `[assemble] chunkPaths length (${chunkPaths.length}) does not match chunks.json length (${chunks.length}). Adapters must pass one path per chunk, ordered by index.`
9787
9802
  );
9788
9803
  }
9789
- for (const path of chunkPaths) {
9804
+ for (const [index, entry] of chunkPaths.entries()) {
9805
+ if (typeof entry !== "string" && entry.length === 0) {
9806
+ throw new Error(`[assemble] chunk ${index} has an empty list of parts`);
9807
+ }
9808
+ }
9809
+ for (const path of chunkPaths.flat()) {
9790
9810
  if (!existsSync18(path)) {
9791
9811
  throw new Error(`[assemble] chunk path does not exist: ${path}`);
9792
9812
  }
@@ -10005,6 +10025,17 @@ function validatePlanVideosForChunk(value) {
10005
10025
  );
10006
10026
  }
10007
10027
  }
10028
+ function resolveChunkFrameRange(slice, chunkIndex, frameRange) {
10029
+ if (frameRange === void 0) return { startFrame: slice.startFrame, endFrame: slice.endFrame };
10030
+ const { startFrame, endFrame } = frameRange;
10031
+ if (!Number.isSafeInteger(startFrame) || !Number.isSafeInteger(endFrame) || startFrame < slice.startFrame || endFrame > slice.endFrame || endFrame <= startFrame) {
10032
+ throw new RenderChunkValidationError(
10033
+ CHUNK_FRAME_RANGE_INVALID,
10034
+ `[renderChunk] frameRange ${JSON.stringify(frameRange)} must be a non-empty integer range inside chunk ${chunkIndex}'s slice [${slice.startFrame}, ${slice.endFrame})`
10035
+ );
10036
+ }
10037
+ return { startFrame, endFrame };
10038
+ }
10008
10039
  var distributedCaptureSessionDependencies = {
10009
10040
  createCaptureSession: createCaptureSession9,
10010
10041
  assertSwiftShader,
@@ -10075,7 +10106,7 @@ function resolveLockedVp9CpuUsed(lockedEncoder) {
10075
10106
  if (lockedEncoder.encoder !== "libvpx-vp9-software") return void 0;
10076
10107
  return lockedEncoder.vp9CpuUsed ?? LEGACY_DISTRIBUTED_VP9_CPU_USED;
10077
10108
  }
10078
- async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10109
+ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
10079
10110
  const start = Date.now();
10080
10111
  const log = defaultLogger;
10081
10112
  const planJsonPath = join27(planDir, "plan.json");
@@ -10129,13 +10160,15 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10129
10160
  if (slice === void 0) {
10130
10161
  throw new RenderChunkValidationError(CHUNK_INDEX_OUT_OF_RANGE, "[renderChunk] missing slice");
10131
10162
  }
10132
- const framesInChunk = slice.endFrame - slice.startFrame;
10133
- if (framesInChunk <= 0) {
10163
+ const sliceFrames = slice.endFrame - slice.startFrame;
10164
+ if (sliceFrames <= 0) {
10134
10165
  throw new RenderChunkValidationError(
10135
10166
  CHUNK_INDEX_OUT_OF_RANGE,
10136
- `[renderChunk] chunk ${chunkIndex} has non-positive frame count: ${framesInChunk}`
10167
+ `[renderChunk] chunk ${chunkIndex} has non-positive frame count: ${sliceFrames}`
10137
10168
  );
10138
10169
  }
10170
+ const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
10171
+ const framesInChunk = range.endFrame - range.startFrame;
10139
10172
  const compiledDir = join27(planDir, "compiled");
10140
10173
  if (!existsSync19(compiledDir)) {
10141
10174
  throw new RenderChunkValidationError(
@@ -10200,10 +10233,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10200
10233
  const deferredVideoFrames = planVideos ? await extractDeferredVideoFramesForChunk({
10201
10234
  planDir,
10202
10235
  planVideos,
10203
- frames: Array.from(
10204
- { length: slice.endFrame - slice.startFrame },
10205
- (_, i) => slice.startFrame + i
10206
- ),
10236
+ frames: Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i),
10207
10237
  fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
10208
10238
  outputRoot: videoFramesDir,
10209
10239
  cfg,
@@ -10359,7 +10389,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10359
10389
  abortSignal: void 0,
10360
10390
  assertNotAborted: () => {
10361
10391
  },
10362
- frameRange: { startFrame: slice.startFrame, endFrame: slice.endFrame }
10392
+ frameRange: range
10363
10393
  });
10364
10394
  const observedModes = new Set(capturePerfs.map((perf) => perf.captureMode));
10365
10395
  if (observedModes.size !== 1 || ![...observedModes].every(isCaptureMode)) {
@@ -10453,12 +10483,13 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10453
10483
  });
10454
10484
  if (encoder.chunksCarryAudio) {
10455
10485
  const audioScratchPath = `${outputChunkPath}.audio.m4a`;
10486
+ const audioChunks = options?.frameRange ? chunksWithSubRange(chunks, chunkIndex, range) : { chunks, index: chunkIndex };
10456
10487
  await muxChunkWithAudio({
10457
10488
  videoPath: videoOnlyPath,
10458
10489
  audioPath: chunkAudioSource(planDir, chunkIndex, audioScratchPath),
10459
10490
  outputPath: outputChunkPath,
10460
- chunks,
10461
- chunkIndex,
10491
+ chunks: audioChunks.chunks,
10492
+ chunkIndex: audioChunks.index,
10462
10493
  fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
10463
10494
  timeoutMs: cfg.ffmpegProcessTimeout
10464
10495
  });
@@ -10487,8 +10518,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10487
10518
  const perfPayload = {
10488
10519
  planHash: plan2.planHash,
10489
10520
  chunkIndex,
10490
- startFrame: slice.startFrame,
10491
- endFrame: slice.endFrame,
10521
+ startFrame: range.startFrame,
10522
+ endFrame: range.endFrame,
10492
10523
  framesEncoded,
10493
10524
  durationMs,
10494
10525
  planHashMs,
@@ -10517,6 +10548,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10517
10548
  outputPath: outputChunkPath,
10518
10549
  outputKind,
10519
10550
  framesEncoded,
10551
+ frameRange: range,
10520
10552
  sha256,
10521
10553
  durationMs,
10522
10554
  planHashMs,
@@ -10533,12 +10565,12 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
10533
10565
  }
10534
10566
 
10535
10567
  // src/services/distributed/planV2Execution.ts
10536
- async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath) {
10568
+ async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
10537
10569
  const workRoot = mkdtempSync7(join28(tmpdir2(), "hf-plan-v2-chunk-"));
10538
10570
  const materializedPlanDir = join28(workRoot, "plan");
10539
10571
  try {
10540
10572
  materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
10541
- return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath);
10573
+ return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
10542
10574
  } finally {
10543
10575
  rmSync13(workRoot, { recursive: true, force: true });
10544
10576
  }
@@ -10852,6 +10884,7 @@ function hashProjectDir(projectDir, files = listSiteFiles(projectDir)) {
10852
10884
  }
10853
10885
  export {
10854
10886
  CHUNK_EXCEEDS_WORKER_TIMEOUT,
10887
+ CHUNK_FRAME_RANGE_INVALID,
10855
10888
  CURRENT_PLAN_PROTOCOL,
10856
10889
  ChunkExceedsWorkerTimeoutError,
10857
10890
  DEFAULT_CHUNK_SIZE,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "0.1.0",
3
3
  "buildId": "dev",
4
- "sha256": "5da92c0e03e3d47df672f23707742908357e94fb7b39ed0f518d4c37400f433d",
4
+ "sha256": "2ae4b2eb24c5dea85f83bd9af6c14abc153ad59fc3f338d1ca9142d9df0c662e",
5
5
  "artifacts": {
6
6
  "iife": "hyperframe.runtime.iife.js",
7
7
  "esm": "hyperframe.runtime.mjs"