@hyperframes/producer 0.8.231 → 0.9.1

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.
@@ -2,8 +2,9 @@
2
2
  * `@hyperframes/producer/distributed` — the distributed render primitives.
3
3
  *
4
4
  * The distributed activities are pure functions over local file paths;
5
- * networking + orchestration live in adapters. New integrations should use
6
- * Plan v2; the v1 functions remain available for compatibility.
5
+ * networking + orchestration live in adapters. Plan v2 is the only public
6
+ * transport; chunk and assemble primitives consume its materialized execution
7
+ * directory.
7
8
  *
8
9
  * Adopters (AWS Lambda, Cloud Run Jobs, Temporal, K8s Jobs, plain SSH):
9
10
  *
@@ -29,8 +30,8 @@
29
30
  * No networking, no AWS SDK, no Temporal SDK — those live in adapter
30
31
  * packages. This module is library code only.
31
32
  */
32
- export { buildChunkSlices, measurePlanDirBytes, plan, rejectUnsupportedDistributedFormat, resolveChunkPlan, buildPlanAudio, plansSeparateAudio, type DistributedRenderConfig, type PlanResult, type RemoteProjectFile, DEFAULT_CHUNK_SIZE, DEFAULT_MAX_PARALLEL_CHUNKS, MIN_CHUNK_SIZE, PLAN_DIR_SIZE_LIMIT_BYTES, PLAN_PROJECT_DIR_SKIP_SEGMENTS, CHUNK_EXCEEDS_WORKER_TIMEOUT, ChunkExceedsWorkerTimeoutError, FORMAT_NOT_SUPPORTED_IN_DISTRIBUTED, FormatNotSupportedInDistributedError, PLAN_TOO_LARGE, PlanTooLargeError, } from "./services/distributed/plan.js";
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";
33
+ export { buildChunkSlices, measurePlanDirBytes, rejectUnsupportedDistributedFormat, resolveChunkPlan, buildPlanAudio, plansSeparateAudio, type DistributedRenderConfig, type RemoteProjectFile, DEFAULT_CHUNK_SIZE, DEFAULT_MAX_PARALLEL_CHUNKS, MIN_CHUNK_SIZE, PLAN_DIR_SIZE_LIMIT_BYTES, PLAN_PROJECT_DIR_SKIP_SEGMENTS, CHUNK_EXCEEDS_WORKER_TIMEOUT, ChunkExceedsWorkerTimeoutError, FORMAT_NOT_SUPPORTED_IN_DISTRIBUTED, FormatNotSupportedInDistributedError, } from "./services/distributed/plan.js";
34
+ export { createPlanV2FromExecutionPlan, getPlanV2ExecutionPlanHash, isPlanV2DeferredSourceArtifact, listPlanV2ArtifactsForTarget, materializePlanV2Target, planV2, planV2WithPublisher, publishPlanV2FromExecutionPlan, 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
35
  export { LocalPlanV2ArtifactPublisher, type LocalPlanV2ArtifactPublisherOptions, type PlanV2ArtifactPublisher, type PlanV2PublishBlob, } from "./services/distributed/planV2Publisher.js";
35
36
  export { assembleV2, renderChunkV2 } from "./services/distributed/planV2Execution.js";
36
37
  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";
@@ -41,7 +42,7 @@ export { InvalidConfigError, type SerializableDistributedRenderConfig, validateD
41
42
  export { hashProjectDir, listSiteFiles } from "./services/distributed/projectHash.js";
42
43
  export { AUDIO_SIDECAR_MIN_BYTES, buildAudioSidecar, wantsAudioSidecar, type AudioSidecarOutcome, } from "./services/distributed/audioSidecar.js";
43
44
  export { buildProbeFacts, wantsProbeFacts, type ProbeFactsOutcome, } from "./services/distributed/probeFacts.js";
44
- export { CURRENT_PLAN_PROTOCOL, DISTRIBUTED_RENDER_CAPABILITIES, getDistributedRenderCapabilities, PLAN_ARTIFACT_LAYOUT, PLAN_HASH_SCHEMA, PLAN_PROTOCOL_V1, PLAN_PROTOCOL_V2, PLAN_PROTOCOL_UNSUPPORTED, PLAN_SCHEMA_VERSION, PLAN_V2_ARTIFACT_LAYOUT, PLAN_V2_HASH_SCHEMA, PLAN_V2_SCHEMA_VERSION, PlanProtocolUnsupportedError, readPlanProtocol, readPlanProtocolV1, type DistributedRenderCapabilities, type PlanProtocolConsumerCapabilities, type PlanProtocolDescriptor, type PlanProtocolV1Descriptor, type PlanProtocolV2Descriptor, type SupportedPlanProtocolDescriptor, } from "./services/distributed/planProtocol.js";
45
+ export { PLAN_PROTOCOL_V2, PLAN_PROTOCOL_UNSUPPORTED, PLAN_V2_ARTIFACT_LAYOUT, PLAN_V2_HASH_SCHEMA, PLAN_V2_SCHEMA_VERSION, PlanProtocolUnsupportedError, type PlanProtocolDescriptor, type PlanProtocolV2Descriptor, } from "./services/distributed/planProtocol.js";
45
46
  export { PlanVideosMetadataError, type DistributedFormat } from "./services/distributed/shared.js";
46
47
  export { isPlanAudioArtifactPath, PLAN_AUDIO_LEGACY_RELATIVE_PATH, PLAN_AUDIO_RELATIVE_PATH, resolvePlanAudioPath, } from "./services/distributed/shared.js";
47
48
  export type { ChunkSliceJson, CompositionMetadataJson, LockedRenderConfig, } from "./services/render/stages/freezePlan.js";
@@ -6085,14 +6085,14 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6085
6085
  );
6086
6086
  }
6087
6087
  const targetDurationSeconds = videoInfo.frameCount * videoInfo.fpsDen / videoInfo.fpsNum;
6088
- const plan2 = buildPadTrimAudioPlan(
6088
+ const plan = buildPadTrimAudioPlan(
6089
6089
  input.audioPath,
6090
6090
  input.outputPath,
6091
6091
  audioInfo.durationSeconds,
6092
6092
  targetDurationSeconds
6093
6093
  );
6094
6094
  try {
6095
- for (const step of plan2.steps) {
6095
+ for (const step of plan.steps) {
6096
6096
  const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(input.audioPath, input.outputPath, targetDurationSeconds, step.filter);
6097
6097
  if (!ffmpegResult.success) {
6098
6098
  return {
@@ -6100,7 +6100,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6100
6100
  outputPath: input.outputPath,
6101
6101
  targetDurationSeconds,
6102
6102
  sourceDurationSeconds: audioInfo.durationSeconds,
6103
- operation: plan2.operation,
6103
+ operation: plan.operation,
6104
6104
  error: ffmpegResult.error,
6105
6105
  failureReason: ffmpegResult.failureReason
6106
6106
  };
@@ -6112,11 +6112,11 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6112
6112
  outputPath: input.outputPath,
6113
6113
  targetDurationSeconds,
6114
6114
  sourceDurationSeconds: audioInfo.durationSeconds,
6115
- operation: plan2.operation,
6116
- error: `audioPadTrim: failed to materialize ${plan2.operation}: ${err instanceof Error ? err.message : String(err)}`
6115
+ operation: plan.operation,
6116
+ error: `audioPadTrim: failed to materialize ${plan.operation}: ${err instanceof Error ? err.message : String(err)}`
6117
6117
  };
6118
6118
  } finally {
6119
- for (const path of plan2.cleanupPaths) removeScratch(path);
6119
+ for (const path of plan.cleanupPaths) removeScratch(path);
6120
6120
  }
6121
6121
  let loweredDb = 0;
6122
6122
  if (probeTruePeak) {
@@ -6133,7 +6133,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6133
6133
  outputPath: input.outputPath,
6134
6134
  targetDurationSeconds,
6135
6135
  sourceDurationSeconds: audioInfo.durationSeconds,
6136
- operation: plan2.operation,
6136
+ operation: plan.operation,
6137
6137
  error: correction.error,
6138
6138
  failureReason: correction.failureReason
6139
6139
  };
@@ -6145,7 +6145,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
6145
6145
  outputPath: input.outputPath,
6146
6146
  targetDurationSeconds,
6147
6147
  sourceDurationSeconds: audioInfo.durationSeconds,
6148
- operation: plan2.operation,
6148
+ operation: plan.operation,
6149
6149
  ...loweredDb > 0 ? { audioLoweredDb: loweredDb } : {}
6150
6150
  };
6151
6151
  }
@@ -6634,7 +6634,7 @@ async function runCaptureStage(input) {
6634
6634
  job,
6635
6635
  totalFrames,
6636
6636
  cfg,
6637
- plan: plan2,
6637
+ plan,
6638
6638
  log,
6639
6639
  captureAttempts,
6640
6640
  buildCaptureOptions,
@@ -6645,8 +6645,8 @@ async function runCaptureStage(input) {
6645
6645
  dedupPerfs
6646
6646
  } = input;
6647
6647
  let { probeSession } = input;
6648
- let { workerCount } = plan2;
6649
- const { forceScreenshot } = plan2;
6648
+ let { workerCount } = plan;
6649
+ const { forceScreenshot } = plan;
6650
6650
  let lastBrowserConsole = [];
6651
6651
  const workerPageErrors = [];
6652
6652
  let captureBeyondViewport = probeSession?.options.captureBeyondViewport;
@@ -8358,7 +8358,6 @@ var PLAN_PROTOCOL_V1 = Object.freeze({
8358
8358
  artifactLayout: PLAN_ARTIFACT_LAYOUT,
8359
8359
  hashSchema: PLAN_HASH_SCHEMA
8360
8360
  });
8361
- var CURRENT_PLAN_PROTOCOL = PLAN_PROTOCOL_V1;
8362
8361
  var PLAN_PROTOCOL_V2 = Object.freeze({
8363
8362
  schemaVersion: PLAN_V2_SCHEMA_VERSION,
8364
8363
  artifactLayout: PLAN_V2_ARTIFACT_LAYOUT,
@@ -8380,9 +8379,6 @@ var DISTRIBUTED_RENDER_CAPABILITIES = Object.freeze({
8380
8379
  }),
8381
8380
  chunkFrameRange: true
8382
8381
  });
8383
- function getDistributedRenderCapabilities() {
8384
- return DISTRIBUTED_RENDER_CAPABILITIES;
8385
- }
8386
8382
  var PlanProtocolUnsupportedError = class extends Error {
8387
8383
  // Public adapters inspect this typed code even though OSS producer does not.
8388
8384
  // fallow-ignore-next-line unused-class-member
@@ -8956,10 +8952,10 @@ function buildStbl(stsd, track) {
8956
8952
  );
8957
8953
  }
8958
8954
  var codecOf = (track) => track.stsd.toString("latin1", 20, 24);
8959
- var sameTrack = (track, plan2) => track.handler === plan2.handler && track.timescale === plan2.timescale && codecOf(track) === codecOf(plan2);
8960
- function planTracksOf(tracks, plan2, index) {
8955
+ var sameTrack = (track, plan) => track.handler === plan.handler && track.timescale === plan.timescale && codecOf(track) === codecOf(plan);
8956
+ function planTracksOf(tracks, plan, index) {
8961
8957
  let next = 0;
8962
- const matched = plan2.map((planTrack) => {
8958
+ const matched = plan.map((planTrack) => {
8963
8959
  const track = tracks[next];
8964
8960
  if (track && sameTrack(track, planTrack)) return tracks[next++];
8965
8961
  if (planTrack.handler === "soun") return null;
@@ -8980,22 +8976,22 @@ function sourceTracks(layouts, audio) {
8980
8976
  if (audio && (audioTracks.length !== 1 || audioTracks[0].handler !== "soun")) {
8981
8977
  throw new Error("[mp4Stitch] the separate audio file must hold one audio track");
8982
8978
  }
8983
- const plan2 = [...chunkPlan, ...audioTracks];
8979
+ const plan = [...chunkPlan, ...audioTracks];
8984
8980
  const chunks = layouts.map((layout, i) => {
8985
8981
  const tracks = readTracks(layout.moov);
8986
8982
  if (audio && tracks.some((track) => track.handler === "soun")) {
8987
8983
  throw new Error(`[mp4Stitch] chunk ${i} carries its own audio`);
8988
8984
  }
8989
- return planTracksOf(tracks, plan2, i);
8985
+ return planTracksOf(tracks, plan, i);
8990
8986
  });
8991
8987
  return {
8992
- plan: plan2,
8988
+ plan,
8993
8989
  chunkTrackCount: chunkPlan.length,
8994
8990
  sources: audio ? [[...chunkPlan.map(() => null), audioTracks[0]], ...chunks] : chunks
8995
8991
  };
8996
8992
  }
8997
8993
  function buildStitchedHeader(layouts, audio) {
8998
- const { plan: plan2, chunkTrackCount, sources } = sourceTracks(layouts, audio);
8994
+ const { plan, chunkTrackCount, sources } = sourceTracks(layouts, audio);
8999
8995
  const sourceLayouts = audio ? [audio, ...layouts] : layouts;
9000
8996
  const payloadBases = [];
9001
8997
  let payloadBytes = 0;
@@ -9007,10 +9003,10 @@ function buildStitchedHeader(layouts, audio) {
9007
9003
  const root = boxAt(template, 0, 0, template.length);
9008
9004
  const mvhd = child2(template, root, "mvhd");
9009
9005
  const movieTimescale = timescaleOf(template, mvhd);
9010
- const chunkTrackIds = plan2.slice(0, chunkTrackCount).map((track) => idOf(template, child2(template, track.trak, "tkhd")));
9006
+ const chunkTrackIds = plan.slice(0, chunkTrackCount).map((track) => idOf(template, child2(template, track.trak, "tkhd")));
9011
9007
  const audioTrackId = Math.max(...chunkTrackIds) + 1;
9012
9008
  const buildMoov = (dataStart2) => {
9013
- const traks = plan2.map((track, t) => {
9009
+ const traks = plan.map((track, t) => {
9014
9010
  const parts = sources.flatMap((tracks, chunk) => {
9015
9011
  const part = tracks[t];
9016
9012
  return part ? [{ ...part, chunk }] : [];
@@ -10297,22 +10293,6 @@ async function buildPlanAudio(projectDir, config, workRoot, outputPath, options
10297
10293
  rmSync7(c.workDir, { recursive: true, force: true });
10298
10294
  }
10299
10295
  }
10300
- async function plan(projectDir, config, planDir, options = {}) {
10301
- const executionPlan = await buildLocalExecutionPlan(projectDir, config, planDir, options);
10302
- return {
10303
- planDir: executionPlan.executionPlanDir,
10304
- planProtocol: PLAN_PROTOCOL_V1,
10305
- planHash: executionPlan.executionPlanHash,
10306
- chunkCount: executionPlan.chunkCount,
10307
- totalFrames: executionPlan.totalFrames,
10308
- fps: executionPlan.fps,
10309
- width: executionPlan.width,
10310
- height: executionPlan.height,
10311
- format: executionPlan.format,
10312
- ffmpegVersion: executionPlan.ffmpegVersion,
10313
- producerVersion: executionPlan.producerVersion
10314
- };
10315
- }
10316
10296
 
10317
10297
  // src/services/distributed/planV2.ts
10318
10298
  import {
@@ -10857,9 +10837,6 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
10857
10837
  throw error;
10858
10838
  }
10859
10839
  }
10860
- function createPlanV2FromV1(executionPlanDir, planV2Dir) {
10861
- return createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir);
10862
- }
10863
10840
  async function publishPlanV2FromExecutionPlan(executionPlanDir, publisher) {
10864
10841
  return publishExecutionPlan(executionPlanDir, publisher, {});
10865
10842
  }
@@ -10889,9 +10866,6 @@ async function publishExecutionPlan(executionPlanDir, publisher, { digests, log
10889
10866
  throw error;
10890
10867
  }
10891
10868
  }
10892
- async function publishPlanV2FromV1(executionPlanDir, publisher) {
10893
- return publishPlanV2FromExecutionPlan(executionPlanDir, publisher);
10894
- }
10895
10869
  async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
10896
10870
  const stagingRoot = mkdtempSync4(join26(options.stagingParentDir ?? tmpdir(), ".execution-plan-"));
10897
10871
  const digests = /* @__PURE__ */ new Map();
@@ -10951,8 +10925,8 @@ function resultFromManifest(planV2Dir, manifest) {
10951
10925
  limitations: manifest.limitations
10952
10926
  };
10953
10927
  }
10954
- function getPlanV2ExecutionPlanHash(plan2) {
10955
- return plan2.sourcePlanV1Hash;
10928
+ function getPlanV2ExecutionPlanHash(plan) {
10929
+ return plan.sourcePlanV1Hash;
10956
10930
  }
10957
10931
  function readString2(value, field) {
10958
10932
  if (typeof value !== "string" || value.length === 0) {
@@ -11242,10 +11216,10 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11242
11216
  const start = Date.now();
11243
11217
  const log = options?.logger ?? defaultLogger;
11244
11218
  const cfr = options?.cfr === true;
11245
- const plan2 = readAssemblePlan(planDir, chunkOutputs);
11219
+ const plan = readAssemblePlan(planDir, chunkOutputs);
11246
11220
  const chunkPaths = chunkOutputs.flat();
11247
- if (plan2.dimensions.format === "png-sequence") {
11248
- return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
11221
+ if (plan.dimensions.format === "png-sequence") {
11222
+ return mergePngFrameDirs(chunkPaths, outputPath, plan.totalFrames, audioPath, start);
11249
11223
  }
11250
11224
  if (chunksAreStitchedMp4(planDir, cfr)) {
11251
11225
  const separateAudio = stitchesSeparateAudio(planDir) && audioPath !== null;
@@ -11253,17 +11227,17 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11253
11227
  return {
11254
11228
  outputPath,
11255
11229
  durationMs: Date.now() - start,
11256
- framesEncoded: plan2.totalFrames,
11230
+ framesEncoded: plan.totalFrames,
11257
11231
  fileSize: statSync8(outputPath).size
11258
11232
  };
11259
11233
  }
11260
- const format = plan2.dimensions.format;
11234
+ const format = plan.dimensions.format;
11261
11235
  const cfrEncoder = cfr ? readCfrEncoder(planDir, format) : null;
11262
11236
  if (!existsSync19(dirname14(outputPath))) {
11263
11237
  mkdirSync13(dirname14(outputPath), { recursive: true });
11264
11238
  }
11265
11239
  const workDir = mkdtempSync5(`${outputPath}.assemble-work-`);
11266
- const fps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
11240
+ const fps = { num: plan.dimensions.fpsNum, den: plan.dimensions.fpsDen };
11267
11241
  const stageMs = {};
11268
11242
  const ctx = {
11269
11243
  workDir,
@@ -11305,7 +11279,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
11305
11279
  return {
11306
11280
  outputPath,
11307
11281
  durationMs: Date.now() - start,
11308
- framesEncoded: plan2.totalFrames,
11282
+ framesEncoded: plan.totalFrames,
11309
11283
  fileSize
11310
11284
  };
11311
11285
  }
@@ -11315,8 +11289,8 @@ function readAssemblePlan(planDir, chunkPaths) {
11315
11289
  if (!existsSync19(planJsonPath)) {
11316
11290
  throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
11317
11291
  }
11318
- const plan2 = JSON.parse(readFileSync9(planJsonPath, "utf-8"));
11319
- readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
11292
+ const plan = JSON.parse(readFileSync9(planJsonPath, "utf-8"));
11293
+ readPlanProtocolV1(plan, DISTRIBUTED_RENDER_CAPABILITIES.roles.assembler);
11320
11294
  validatePlanV2MaterializedTarget(planDir, { role: "assembler" });
11321
11295
  if (!existsSync19(chunksJsonPath)) {
11322
11296
  throw new Error(`[assemble] planDir missing meta/chunks.json: ${chunksJsonPath}`);
@@ -11337,7 +11311,7 @@ function readAssemblePlan(planDir, chunkPaths) {
11337
11311
  throw new Error(`[assemble] chunk path does not exist: ${path}`);
11338
11312
  }
11339
11313
  }
11340
- return plan2;
11314
+ return plan;
11341
11315
  }
11342
11316
  function videoInputArgs(ctx, videoSources) {
11343
11317
  return videoSources.length === 1 ? ["-i", videoSources[0]] : concatDemuxerInput(videoSources, ctx.workDir, ctx.fpsArg);
@@ -11467,8 +11441,8 @@ function stitchesSeparateAudio(planDir) {
11467
11441
  return lockedAudio(planDir).separateAudio === true;
11468
11442
  }
11469
11443
  function planFormat(planDir) {
11470
- const plan2 = JSON.parse(readFileSync9(join27(planDir, "plan.json"), "utf-8"));
11471
- return plan2.dimensions.format;
11444
+ const plan = JSON.parse(readFileSync9(join27(planDir, "plan.json"), "utf-8"));
11445
+ return plan.dimensions.format;
11472
11446
  }
11473
11447
  function lockedAudio(planDir) {
11474
11448
  const encoderJsonPath = join27(planDir, "meta", "encoder.json");
@@ -11691,8 +11665,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11691
11665
  `[renderChunk] planDir is missing required artifact: ${planJsonPath}`
11692
11666
  );
11693
11667
  }
11694
- const plan2 = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
11695
- readPlanProtocolV1(plan2, DISTRIBUTED_RENDER_CAPABILITIES.roles.chunk);
11668
+ const plan = JSON.parse(readFileSync10(planJsonPath, "utf-8"));
11669
+ readPlanProtocolV1(plan, DISTRIBUTED_RENDER_CAPABILITIES.roles.chunk);
11696
11670
  const planHashStarted = Date.now();
11697
11671
  const v2Materialization = readValidatedPlanV2Materialization(planDir, {
11698
11672
  role: "chunk",
@@ -11750,10 +11724,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11750
11724
  );
11751
11725
  }
11752
11726
  const ffmpegVersion = await readFfmpegVersion();
11753
- if (ffmpegVersion !== plan2.ffmpegVersion) {
11727
+ if (ffmpegVersion !== plan.ffmpegVersion) {
11754
11728
  throw new RenderChunkValidationError(
11755
11729
  FFMPEG_VERSION_MISMATCH,
11756
- `[renderChunk] ffmpeg version on this worker does not match planDir. planDir: ${JSON.stringify(plan2.ffmpegVersion)}; worker: ${JSON.stringify(ffmpegVersion)}. Distributed retries require byte-identical ffmpeg builds across workers. Re-plan from a worker matching this version, or run all renders on an image with the planDir's ffmpeg.`
11730
+ `[renderChunk] ffmpeg version on this worker does not match planDir. planDir: ${JSON.stringify(plan.ffmpegVersion)}; worker: ${JSON.stringify(ffmpegVersion)}. Distributed retries require byte-identical ffmpeg builds across workers. Re-plan from a worker matching this version, or run all renders on an image with the planDir's ffmpeg.`
11757
11731
  );
11758
11732
  }
11759
11733
  if (encoder.browserGpuMode !== "software") {
@@ -11762,12 +11736,12 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11762
11736
  `[renderChunk] planDir requires browserGpuMode=software, got ${JSON.stringify(encoder.browserGpuMode)}.`
11763
11737
  );
11764
11738
  }
11765
- const recomputedPlanHash = v2Manifest === null ? recomputePlanHashFromPlanDir(planDir) : plan2.planHash;
11739
+ const recomputedPlanHash = v2Manifest === null ? recomputePlanHashFromPlanDir(planDir) : plan.planHash;
11766
11740
  const planHashMs = Date.now() - planHashStarted;
11767
- if (recomputedPlanHash !== plan2.planHash) {
11741
+ if (recomputedPlanHash !== plan.planHash) {
11768
11742
  throw new RenderChunkValidationError(
11769
11743
  PLAN_HASH_MISMATCH,
11770
- `[renderChunk] planDir content fingerprint does not match plan.json.planHash. plan.json: ${plan2.planHash}; recomputed: ${recomputedPlanHash}. Likely a corrupted artifact (partial S3 download, manual tampering) or a planDir produced by an incompatible producer version. Re-plan and re-fan-out.`
11744
+ `[renderChunk] planDir content fingerprint does not match plan.json.planHash. plan.json: ${plan.planHash}; recomputed: ${recomputedPlanHash}. Likely a corrupted artifact (partial S3 download, manual tampering) or a planDir produced by an incompatible producer version. Re-plan and re-fan-out.`
11771
11745
  );
11772
11746
  }
11773
11747
  if (!encoder.runtimeEnv || typeof encoder.runtimeEnv !== "object") {
@@ -11779,16 +11753,16 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11779
11753
  const envRestore = applyRuntimeEnvSnapshot(encoder.runtimeEnv);
11780
11754
  try {
11781
11755
  const job = buildSyntheticRenderJob({
11782
- fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
11756
+ fps: { num: plan.dimensions.fpsNum, den: plan.dimensions.fpsDen },
11783
11757
  quality: encoder.quality,
11784
- format: plan2.dimensions.format,
11758
+ format: plan.dimensions.format,
11785
11759
  crf: encoder.crf,
11786
11760
  bitrate: encoder.bitrate,
11787
11761
  hdrMode: "force-sdr",
11788
11762
  entryFile: "index.html"
11789
11763
  });
11790
11764
  job.totalFrames = framesInChunk;
11791
- job.duration = framesInChunk * plan2.dimensions.fpsDen / plan2.dimensions.fpsNum;
11765
+ job.duration = framesInChunk * plan.dimensions.fpsDen / plan.dimensions.fpsNum;
11792
11766
  const cfg = {
11793
11767
  ...resolveConfig5(),
11794
11768
  browserGpuMode: "software",
@@ -11804,7 +11778,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11804
11778
  mkdirSync14(framesDir, { recursive: true });
11805
11779
  const videoFramesDir = `${workDir}.video-frames`;
11806
11780
  const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
11807
- const chunkFps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
11781
+ const chunkFps = { num: plan.dimensions.fpsNum, den: plan.dimensions.fpsDen };
11808
11782
  const deferredVideos = planVideos?.extracted.filter((video) => video.deferredRange) ?? [];
11809
11783
  const shownFrames = planVideos ? shownDeferredFrameIndexes(planVideos, chunkFrameNumbers, chunkFps) : /* @__PURE__ */ new Map();
11810
11784
  const remoteVideoIds = new Set(
@@ -11819,10 +11793,10 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11819
11793
  preHeadScripts: [buildVirtualTimeShim({ seedRandomFromFrame: true })],
11820
11794
  // These dimensions are frozen by the controller from the render job, so
11821
11795
  // chunk runtime seek quantization stays on the same fps grid as capture.
11822
- fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen }
11796
+ fps: { num: plan.dimensions.fpsNum, den: plan.dimensions.fpsDen }
11823
11797
  });
11824
11798
  const captureOptions = buildChunkCaptureOptions({
11825
- dimensions: plan2.dimensions,
11799
+ dimensions: plan.dimensions,
11826
11800
  encoder,
11827
11801
  videoCount: planVideos?.videos.length ?? 0,
11828
11802
  html: readFileSync10(join28(compiledDir, "index.html"), "utf-8"),
@@ -11979,9 +11953,9 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11979
11953
  videoFrameLookup,
11980
11954
  frameCacheOptions(cfg, chunkWorkerCount)
11981
11955
  );
11982
- const isPngSequence = plan2.dimensions.format === "png-sequence";
11956
+ const isPngSequence = plan.dimensions.format === "png-sequence";
11983
11957
  outputKind = isPngSequence ? "frame-dir" : "file";
11984
- const presetFormat = isPngSequence ? "mp4" : plan2.dimensions.format;
11958
+ const presetFormat = isPngSequence ? "mp4" : plan.dimensions.format;
11985
11959
  const basePreset = getEncoderPreset6(
11986
11960
  job.config.quality,
11987
11961
  presetFormat,
@@ -12004,9 +11978,9 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
12004
11978
  outputPath: videoOnlyPath,
12005
11979
  framesDir,
12006
11980
  videoOnlyPath,
12007
- width: Math.round(plan2.dimensions.width * encoder.deviceScaleFactor),
12008
- height: Math.round(plan2.dimensions.height * encoder.deviceScaleFactor),
12009
- needsAlpha: plan2.dimensions.format !== "mp4",
11981
+ width: Math.round(plan.dimensions.width * encoder.deviceScaleFactor),
11982
+ height: Math.round(plan.dimensions.height * encoder.deviceScaleFactor),
11983
+ needsAlpha: plan.dimensions.format !== "mp4",
12010
11984
  captureImageFormat: captureOptions.format ?? "jpeg",
12011
11985
  // The encoder writes video only; audio joins at assemble time or in the
12012
11986
  // chunk that carries audio. Suppressing `hasAudio` skips the png-sequence audio
@@ -12065,7 +12039,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
12065
12039
  useLayeredComposite: false,
12066
12040
  usePageSideCompositing: false,
12067
12041
  hasHdrContent: false,
12068
- needsAlpha: plan2.dimensions.format !== "mp4"
12042
+ needsAlpha: plan.dimensions.format !== "mp4"
12069
12043
  });
12070
12044
  if (capturePlan.kind !== "sdr_disk") {
12071
12045
  throw new Error(`Distributed chunk requires sdr_disk plan; got ${capturePlan.kind}`);
@@ -12155,7 +12129,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
12155
12129
  outputPath: outputChunkPath,
12156
12130
  chunks: audioChunks.chunks,
12157
12131
  chunkIndex: audioChunks.index,
12158
- fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
12132
+ fps: { num: plan.dimensions.fpsNum, den: plan.dimensions.fpsDen },
12159
12133
  timeoutMs: cfg.ffmpegProcessTimeout
12160
12134
  });
12161
12135
  rmSync11(videoOnlyPath, { force: true });
@@ -12185,7 +12159,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
12185
12159
  const durationMs = Date.now() - start;
12186
12160
  const perfPath = `${outputChunkPath}.perf.json`;
12187
12161
  const perfPayload = {
12188
- planHash: plan2.planHash,
12162
+ planHash: plan.planHash,
12189
12163
  chunkIndex,
12190
12164
  startFrame: range.startFrame,
12191
12165
  endFrame: range.endFrame,
@@ -12203,7 +12177,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
12203
12177
  videoShownBoxes: Object.fromEntries(shownBoxes ?? []),
12204
12178
  sha256,
12205
12179
  outputKind,
12206
- producerVersion: plan2.producerVersion,
12180
+ producerVersion: plan.producerVersion,
12207
12181
  ffmpegVersion
12208
12182
  };
12209
12183
  writeFileSync11(perfPath, `${JSON.stringify(perfPayload, null, 2)}
@@ -12643,12 +12617,10 @@ export {
12643
12617
  AUDIO_SIDECAR_MIN_BYTES,
12644
12618
  CHUNK_EXCEEDS_WORKER_TIMEOUT,
12645
12619
  CHUNK_FRAME_RANGE_INVALID,
12646
- CURRENT_PLAN_PROTOCOL,
12647
12620
  ChunkExceedsWorkerTimeoutError,
12648
12621
  DEFAULT_CHUNK_SIZE,
12649
12622
  DEFAULT_MAX_PARALLEL_CHUNKS,
12650
12623
  DISTRIBUTED_DURATION_OUT_OF_RANGE,
12651
- DISTRIBUTED_RENDER_CAPABILITIES,
12652
12624
  FFMPEG_VERSION_MISMATCH,
12653
12625
  FORMAT_NOT_SUPPORTED_IN_DISTRIBUTED,
12654
12626
  FormatNotSupportedInDistributedError,
@@ -12657,25 +12629,19 @@ export {
12657
12629
  LocalPlanV2ArtifactPublisher,
12658
12630
  MAX_DISTRIBUTED_DURATION_SECONDS,
12659
12631
  MIN_CHUNK_SIZE,
12660
- PLAN_ARTIFACT_LAYOUT,
12661
12632
  PLAN_AUDIO_LEGACY_RELATIVE_PATH,
12662
12633
  PLAN_AUDIO_RELATIVE_PATH,
12663
12634
  PLAN_DIR_SIZE_LIMIT_BYTES,
12664
12635
  PLAN_HASH_MISMATCH,
12665
- PLAN_HASH_SCHEMA,
12666
12636
  PLAN_PROJECT_DIR_SKIP_SEGMENTS,
12667
12637
  PLAN_PROTOCOL_UNSUPPORTED,
12668
- PLAN_PROTOCOL_V1,
12669
12638
  PLAN_PROTOCOL_V2,
12670
- PLAN_SCHEMA_VERSION,
12671
- PLAN_TOO_LARGE,
12672
12639
  PLAN_V2_ARTIFACT_LAYOUT,
12673
12640
  PLAN_V2_HASH_SCHEMA,
12674
12641
  PLAN_V2_INTEGRITY_UNRECOVERABLE,
12675
12642
  PLAN_V2_MATERIALIZATION_MARKER,
12676
12643
  PLAN_V2_SCHEMA_VERSION,
12677
12644
  PlanProtocolUnsupportedError,
12678
- PlanTooLargeError,
12679
12645
  PlanV2IntegrityError,
12680
12646
  PlanValidationError,
12681
12647
  PlanVideosMetadataError,
@@ -12690,8 +12656,6 @@ export {
12690
12656
  buildStitchedHeader,
12691
12657
  chunksAreStitchedMp4,
12692
12658
  createPlanV2FromExecutionPlan,
12693
- createPlanV2FromV1,
12694
- getDistributedRenderCapabilities,
12695
12659
  getPlanV2ExecutionPlanHash,
12696
12660
  hashProjectDir,
12697
12661
  isPlanAudioArtifactPath,
@@ -12701,15 +12665,11 @@ export {
12701
12665
  materializePlanV2Target,
12702
12666
  measurePlanDirBytes,
12703
12667
  muxChunkWithAudio,
12704
- plan,
12705
12668
  planV2,
12706
12669
  planV2WithPublisher,
12707
12670
  plansSeparateAudio,
12708
12671
  publishPlanV2FromExecutionPlan,
12709
- publishPlanV2FromV1,
12710
12672
  readMp4Layout,
12711
- readPlanProtocol,
12712
- readPlanProtocolV1,
12713
12673
  readPlanV2Manifest,
12714
12674
  readWebGlVendorInfoFromCanvas2 as readWebGlVendorInfoFromCanvas,
12715
12675
  rejectUnsupportedDistributedFormat,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "0.1.0",
3
3
  "buildId": "dev",
4
- "sha256": "26a38a1b27437168d361cad2fffff9ae50f5a86ce880bb7f3fb473b97304fec5",
4
+ "sha256": "6018b9f4174f36358ea66bf885e50e05ed18042628340e4e488bbaf5584e8a8a",
5
5
  "artifacts": {
6
6
  "iife": "hyperframe.runtime.iife.js",
7
7
  "esm": "hyperframe.runtime.mjs"