@hyperframes/producer 0.8.207 → 0.8.208

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.
@@ -5446,10 +5446,11 @@ var VideoExtractionStageError = class extends Error {
5446
5446
  kind: failure.kind,
5447
5447
  affectedElementCount: failure.count
5448
5448
  }))
5449
- )) {
5449
+ ), ffmpegReason) {
5450
5450
  const total = failures.reduce((sum2, failure) => sum2 + failure.count, 0);
5451
5451
  const breakdown = failures.map((failure) => `${failure.kind}=${failure.count}`).join(",");
5452
- super(`Video extraction failed for ${total} source(s) [${code}; ${breakdown}]`);
5452
+ const reason = ffmpegReason ? `: ffmpeg said: ${ffmpegReason}` : "";
5453
+ super(`Video extraction failed for ${total} source(s) [${code}; ${breakdown}]${reason}`);
5453
5454
  this.code = code;
5454
5455
  this.retryable = retryable;
5455
5456
  this.failures = failures;
@@ -5496,7 +5497,8 @@ function buildVideoExtractionStageError(result) {
5496
5497
  retryable ? "VIDEO_EXTRACTION_FAILED" : "VIDEO_SOURCE_UNRENDERABLE",
5497
5498
  retryable,
5498
5499
  failures,
5499
- extractionFailureMetadataFromResult(result)
5500
+ extractionFailureMetadataFromResult(result),
5501
+ result.errors.find((failure) => failure.ffmpegReason)?.ffmpegReason
5500
5502
  );
5501
5503
  }
5502
5504
  function buildHdrProbeStageError(failures) {
@@ -6501,6 +6503,7 @@ async function runCaptureStage(input) {
6501
6503
  dedupPerfs,
6502
6504
  pageErrorLines: workerPageErrors,
6503
6505
  openAttempt: input.openAttempt,
6506
+ verifyFirstSession: input.verifyFirstSession,
6504
6507
  onProgress: (progress) => {
6505
6508
  if (progress.latestWorkerPhase) {
6506
6509
  if (progress.capturedFrames === 0) reportWorkerStartup(job, progress, onProgress);
@@ -7371,7 +7374,8 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
7371
7374
  });
7372
7375
  } : void 0,
7373
7376
  void 0,
7374
- options.cfg
7377
+ options.cfg,
7378
+ { verifyFirstSession: options.verifyFirstSession }
7375
7379
  );
7376
7380
  pushWorkerDedupPerfs(workerResults, options.dedupPerfs);
7377
7381
  if (options.pageErrorLines) pushWorkerPageErrors(workerResults, options.pageErrorLines);
@@ -11432,16 +11436,18 @@ function observedChunkCaptureMode(perfs) {
11432
11436
  }
11433
11437
  return mode;
11434
11438
  }
11439
+ var PROBE_SELECTED_SCREENSHOT = "[renderChunk] probe selected screenshot capture";
11435
11440
  function shouldRetryChunkCaptureWithScreenshot(error) {
11436
11441
  const failure = classifyCaptureFailure4(error);
11437
11442
  if (failure.kind === "cancelled" || failure.kind === "memory_exhaustion") return false;
11438
- return /HeadlessExperimental\.beginFrame/i.test(failure.message) || /beginFrame probe timeout/i.test(failure.message) || /Another frame is pending|Frame still pending/i.test(failure.message);
11443
+ return /HeadlessExperimental\.beginFrame/i.test(failure.message) || /beginFrame probe timeout/i.test(failure.message) || failure.message.includes(PROBE_SELECTED_SCREENSHOT) || /Another frame is pending|Frame still pending/i.test(failure.message);
11439
11444
  }
11440
11445
  async function runCaptureWithScreenshotFallback(input) {
11441
11446
  try {
11442
11447
  return await input.run(input.forceScreenshot);
11443
11448
  } catch (error) {
11444
- if (input.forceScreenshot || !shouldRetryChunkCaptureWithScreenshot(error)) throw error;
11449
+ if (input.forceScreenshot || await input.canRetry?.() === false) throw error;
11450
+ if (!shouldRetryChunkCaptureWithScreenshot(error)) throw error;
11445
11451
  input.onFallback?.(error);
11446
11452
  await input.resetForScreenshotRetry();
11447
11453
  return await input.run(true);
@@ -11650,7 +11656,24 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11650
11656
  let extraction;
11651
11657
  const overlap = { current: null };
11652
11658
  try {
11653
- if (chunkWorkerCount === 1 || !forceScreenshotForChunk) {
11659
+ const verifyInWorker = chunkWorkerCount > 1 && !forceScreenshotForChunk;
11660
+ let boxesMeasured;
11661
+ let boxesFailed;
11662
+ const boxesReady = new Promise((resolve10, reject) => {
11663
+ boxesMeasured = resolve10;
11664
+ boxesFailed = reject;
11665
+ });
11666
+ boxesReady.catch(() => {
11667
+ });
11668
+ const measureBoxes = async (page) => {
11669
+ shownBoxes = await measureVideoShownBoxes(
11670
+ page,
11671
+ [...shownFrames.keys()],
11672
+ chunkFrameNumbers.map((frame) => frame * chunkFps.den / chunkFps.num)
11673
+ );
11674
+ boxesMeasured();
11675
+ };
11676
+ if (chunkWorkerCount === 1) {
11654
11677
  const bootStarted = Date.now();
11655
11678
  session = await createVerifiedDistributedCaptureSession(
11656
11679
  fileServer.url,
@@ -11659,11 +11682,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11659
11682
  cfg
11660
11683
  );
11661
11684
  sessionBootMs = Date.now() - bootStarted;
11662
- shownBoxes = await measureVideoShownBoxes(
11663
- session.page,
11664
- [...shownFrames.keys()],
11665
- chunkFrameNumbers.map((frame) => frame * chunkFps.den / chunkFps.num)
11666
- );
11685
+ await measureBoxes(session.page);
11667
11686
  const browserSelectedScreenshot = session.launchCaptureMode === "screenshot";
11668
11687
  const beginFrameStalled = !browserSelectedScreenshot && await beginFrameSessionNeedsScreenshotFallback(session);
11669
11688
  if (browserSelectedScreenshot) {
@@ -11672,10 +11691,6 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11672
11691
  "[renderChunk] Browser capability probe selected screenshot capture for the entire chunk",
11673
11692
  { chunkIndex }
11674
11693
  );
11675
- if (chunkWorkerCount > 1) {
11676
- await closeCaptureSession10(session);
11677
- session = null;
11678
- }
11679
11694
  } else if (beginFrameStalled) {
11680
11695
  forceScreenshotForChunk = true;
11681
11696
  log.warn(
@@ -11685,41 +11700,66 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11685
11700
  await closeCaptureSession10(session).catch(() => {
11686
11701
  });
11687
11702
  session = null;
11688
- if (chunkWorkerCount === 1) {
11689
- const screenshotBootStarted = Date.now();
11690
- const screenshotCfg = {
11691
- ...cfg,
11692
- forceScreenshot: true,
11693
- forceScreenshotExplicitlyOptedOut: false
11694
- };
11695
- session = await createVerifiedDistributedCaptureSession(
11696
- fileServer.url,
11697
- framesDir,
11698
- captureOptions,
11699
- screenshotCfg
11703
+ const screenshotBootStarted = Date.now();
11704
+ const screenshotCfg = {
11705
+ ...cfg,
11706
+ forceScreenshot: true,
11707
+ forceScreenshotExplicitlyOptedOut: false
11708
+ };
11709
+ session = await createVerifiedDistributedCaptureSession(
11710
+ fileServer.url,
11711
+ framesDir,
11712
+ captureOptions,
11713
+ screenshotCfg
11714
+ );
11715
+ sessionBootMs += Date.now() - screenshotBootStarted;
11716
+ }
11717
+ } else if (!verifyInWorker) {
11718
+ boxesMeasured();
11719
+ }
11720
+ let verification;
11721
+ const verifyFirstWorker = (first) => verification ??= (async () => {
11722
+ sessionBootMs = Date.now() - verifyStarted;
11723
+ try {
11724
+ await measureBoxes(first.page);
11725
+ const selectedScreenshot = first.launchCaptureMode === "screenshot";
11726
+ if (selectedScreenshot || await beginFrameSessionNeedsScreenshotFallback(first)) {
11727
+ forceScreenshotForChunk = true;
11728
+ log.warn(
11729
+ selectedScreenshot ? "[renderChunk] Browser capability probe selected screenshot capture for the entire chunk" : "[renderChunk] BeginFrame liveness probe failed; using screenshot capture for the entire chunk",
11730
+ { chunkIndex }
11700
11731
  );
11701
- sessionBootMs += Date.now() - screenshotBootStarted;
11732
+ throw new Error(PROBE_SELECTED_SCREENSHOT);
11702
11733
  }
11703
- } else if (chunkWorkerCount > 1) {
11704
- await closeCaptureSession10(session);
11705
- session = null;
11734
+ } catch (error) {
11735
+ if (!forceScreenshotForChunk) {
11736
+ verifyFailure = error;
11737
+ boxesFailed(error);
11738
+ }
11739
+ throw error;
11706
11740
  }
11707
- }
11708
- const extractStarted = Date.now();
11709
- const deferredVideoFrames = planVideos ? extractDeferredVideoFramesForChunk({
11710
- planDir,
11711
- planVideos,
11712
- frames: chunkFrameNumbers,
11713
- fps: chunkFps,
11714
- outputRoot: videoFramesDir,
11715
- cfg,
11716
- remoteSources,
11717
- shownBoxes
11718
- }).then((frames) => {
11719
- videoExtractMs = Date.now() - extractStarted;
11720
- return frames;
11721
- }) : Promise.resolve([]);
11741
+ })();
11742
+ let verifyStarted = 0;
11743
+ let verifyFailure;
11744
+ const deferredVideoFrames = planVideos ? boxesReady.then(() => {
11745
+ const extractStarted = Date.now();
11746
+ return extractDeferredVideoFramesForChunk({
11747
+ planDir,
11748
+ planVideos,
11749
+ frames: chunkFrameNumbers,
11750
+ fps: chunkFps,
11751
+ outputRoot: videoFramesDir,
11752
+ cfg,
11753
+ remoteSources,
11754
+ shownBoxes
11755
+ }).then((frames) => {
11756
+ videoExtractMs = Date.now() - extractStarted;
11757
+ return frames;
11758
+ });
11759
+ }) : boxesReady.then(() => []);
11722
11760
  extraction = deferredVideoFrames;
11761
+ deferredVideoFrames.catch(() => {
11762
+ });
11723
11763
  const videoFrameLookup = planVideos && planVideos.extracted.length > 0 ? deferredVideoFrames.then(
11724
11764
  (deferred) => createFrameLookupTable5(
11725
11765
  planVideos.videos,
@@ -11798,6 +11838,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11798
11838
  const captureStarted = Date.now();
11799
11839
  captureMode = await runCaptureWithScreenshotFallback({
11800
11840
  forceScreenshot: forceScreenshotForChunk,
11841
+ canRetry: () => verifyFailure === void 0,
11801
11842
  // fallow-ignore-next-line complexity
11802
11843
  run: async (forceScreenshot) => {
11803
11844
  const captureCfg = cfg.forceScreenshot === forceScreenshot ? cfg : {
@@ -11827,6 +11868,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11827
11868
  }
11828
11869
  const captureSession = session;
11829
11870
  session = null;
11871
+ verifyStarted = Date.now();
11830
11872
  overlap.current = canEncodeWhileCapturing(encodeInput, chunkWorkerCount, cpus().length) ? encodeWhileCapturing(encodeInput, framesInChunk) : null;
11831
11873
  await observeRenderStage(
11832
11874
  new RenderObservabilityRecorder({ pipelineStartMs: start, log }),
@@ -11854,7 +11896,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11854
11896
  frameRange: range,
11855
11897
  onFrameLanded: (frame) => overlap.current?.onFrameLanded(frame),
11856
11898
  interleaveFrames: interleavesCapture(overlap.current !== null, options),
11857
- openAttempt
11899
+ openAttempt,
11900
+ verifyFirstSession: forceScreenshot || !verifyInWorker ? void 0 : verifyFirstWorker
11858
11901
  }),
11859
11902
  { stall: frameStallRule(job) }
11860
11903
  ).catch(async (captureError) => {
@@ -11866,6 +11909,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11866
11909
  },
11867
11910
  resetForScreenshotRetry: () => {
11868
11911
  rmSync11(workDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
11912
+ boxesMeasured();
11869
11913
  mkdirSync14(framesDir, { recursive: true });
11870
11914
  capturePerfs.length = 0;
11871
11915
  captureAttempts.length = 0;
@@ -11881,6 +11925,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11881
11925
  );
11882
11926
  }
11883
11927
  }).catch(async (captureError) => {
11928
+ if (verifyFailure !== void 0) throw verifyFailure;
11929
+ boxesFailed(captureError);
11884
11930
  await deferredVideoFrames;
11885
11931
  throw captureError;
11886
11932
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "0.1.0",
3
3
  "buildId": "dev",
4
- "sha256": "98ef5d9ded07a8647d7220aa648089eaf8ad2c3ddee0e2e6d563f80ba60a7a58",
4
+ "sha256": "e7380e2810c1db76b94231462d6756bbd8fd7047ab2014b7428a26dc7105b099",
5
5
  "artifacts": {
6
6
  "iife": "hyperframe.runtime.iife.js",
7
7
  "esm": "hyperframe.runtime.mjs"