@hyperframes/producer 0.8.214 → 0.8.216

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.
@@ -1770,6 +1770,7 @@ function watchStall(phase, rule) {
1770
1770
  let lastChangeAt = Date.now();
1771
1771
  let attempt;
1772
1772
  let timer;
1773
+ let inTail = false;
1773
1774
  const restartWindow = (ms) => {
1774
1775
  last = rule.progress();
1775
1776
  budgetMs = ms;
@@ -1779,6 +1780,10 @@ function watchStall(phase, rule) {
1779
1780
  timer = setInterval(
1780
1781
  () => {
1781
1782
  const current = rule.progress();
1783
+ if (rule.complete?.() && !inTail) {
1784
+ inTail = true;
1785
+ return restartWindow(rule.tailMs ?? rule.noProgressMs);
1786
+ }
1782
1787
  if (current !== last) return restartWindow(rule.noProgressMs);
1783
1788
  if (Date.now() - lastChangeAt < budgetMs) return;
1784
1789
  const error = new RenderStageStalledError(phase, budgetMs, current);
@@ -1794,6 +1799,7 @@ function watchStall(phase, rule) {
1794
1799
  });
1795
1800
  const openAttempt = (parent) => {
1796
1801
  attempt = new AbortController();
1802
+ inTail = false;
1797
1803
  restartWindow(rule.firstProgressMs);
1798
1804
  return parent ? AbortSignal.any([parent, attempt.signal]) : attempt.signal;
1799
1805
  };
@@ -4668,7 +4674,8 @@ async function runCompileStage(input) {
4668
4674
  }
4669
4675
 
4670
4676
  // src/services/render/stages/probeStage.ts
4671
- import { join as join8 } from "node:path";
4677
+ import { createHash as createHash5 } from "node:crypto";
4678
+ import { basename as basename4, join as join8 } from "node:path";
4672
4679
  import { parseHTML as parseHTML6 } from "linkedom";
4673
4680
  import {
4674
4681
  closeCaptureSession as closeCaptureSession4,
@@ -4676,6 +4683,7 @@ import {
4676
4683
  createCaptureSession as createCaptureSession4,
4677
4684
  deriveBeginFrameProbeTimeTicks,
4678
4685
  getCompositionDuration,
4686
+ getCompositionLengthSource,
4679
4687
  initializeSession as initializeSession4,
4680
4688
  isTransientBrowserError,
4681
4689
  probeBeginFrameLiveness,
@@ -4814,6 +4822,13 @@ function hasRuntimeMediaChanges(html) {
4814
4822
  function probeRequiresBrowser(args) {
4815
4823
  return args.durationSeconds <= 0 || args.unresolvedCompositionCount > 0 || args.hasAutoStart || args.hasScriptedAudio || args.hasVariableMedia || args.hasInsertedMedia;
4816
4824
  }
4825
+ function reportedLengthSource(source) {
4826
+ if (!source) return null;
4827
+ if (source.from !== "media") return { from: source.from };
4828
+ const name = basename4(source.src.split(/[?#]/, 1)[0] ?? "");
4829
+ const srcHash = createHash5("sha256").update(name).digest("hex").slice(0, 12);
4830
+ return { from: "media", tag: source.tag, trimmed: source.trimmed, srcHash };
4831
+ }
4817
4832
  async function runProbeStage(input) {
4818
4833
  const {
4819
4834
  projectDir,
@@ -4835,6 +4850,7 @@ async function runProbeStage(input) {
4835
4850
  const probeCfg = cfg.forceScreenshot === forceScreenshot ? cfg : { ...cfg, forceScreenshot };
4836
4851
  let fileServer = null;
4837
4852
  let probeSession = null;
4853
+ let lengthSource = input.composition.duration > 0 ? { from: "declared" } : null;
4838
4854
  let beginFrameStalled = false;
4839
4855
  let lastBrowserConsole = [];
4840
4856
  const probeStart = Date.now();
@@ -4996,10 +5012,12 @@ async function runProbeStage(input) {
4996
5012
  if (composition.duration <= 0) {
4997
5013
  log.info("Discovering composition duration...");
4998
5014
  const discoveredDuration = await getCompositionDuration(session);
5015
+ lengthSource = reportedLengthSource(await getCompositionLengthSource(session));
4999
5016
  assertNotAborted();
5000
5017
  log.info("Probed composition duration from browser", {
5001
5018
  discoveredDuration,
5002
- staticDuration: compiled.staticDuration
5019
+ staticDuration: compiled.staticDuration,
5020
+ lengthSource
5003
5021
  });
5004
5022
  composition.duration = discoveredDuration;
5005
5023
  } else {
@@ -5288,6 +5306,7 @@ async function runProbeStage(input) {
5288
5306
  probeSession,
5289
5307
  lastBrowserConsole,
5290
5308
  duration,
5309
+ lengthSource,
5291
5310
  totalFrames,
5292
5311
  browserProbeMs,
5293
5312
  beginFrameStalled
@@ -5839,7 +5858,7 @@ function checkedDbfs(value) {
5839
5858
  }
5840
5859
  return value;
5841
5860
  }
5842
- async function scanTruePeak(audioPath, trim, timeoutMs, signal) {
5861
+ async function scanTruePeak(audioPath, trim, timeoutMs, signal, seekSeconds = 0) {
5843
5862
  let firstBlock;
5844
5863
  let laterBlocks = Number.NEGATIVE_INFINITY;
5845
5864
  let partialLine = "";
@@ -5855,7 +5874,21 @@ async function scanTruePeak(audioPath, trim, timeoutMs, signal) {
5855
5874
  }
5856
5875
  };
5857
5876
  const result = await runFfmpeg4(
5858
- ["-i", audioPath, "-map", "0:a:0", "-vn", "-af", `${trim}ebur128=peak=true`, "-f", "null", "-"],
5877
+ [
5878
+ ...seekSeconds > 0 ? ["-ss", String(seekSeconds)] : [],
5879
+ ...[
5880
+ "-i",
5881
+ audioPath,
5882
+ "-map",
5883
+ "0:a:0",
5884
+ "-vn",
5885
+ "-af",
5886
+ `${trim}ebur128=peak=true`,
5887
+ "-f",
5888
+ "null",
5889
+ "-"
5890
+ ]
5891
+ ],
5859
5892
  { signal, timeout: timeoutMs, onStderr: readLines }
5860
5893
  );
5861
5894
  if (!result.success) {
@@ -5881,12 +5914,15 @@ async function measureTruePeakDbfs(audioPath, options) {
5881
5914
  const scans = await Promise.all(
5882
5915
  Array.from({ length: count }, (_, k) => {
5883
5916
  const start = k === 0 ? 0 : cut(k) - block;
5884
- const end = k === count - 1 ? "" : `:end_sample=${cut(k + 1)}`;
5917
+ const seekSeconds = Math.max(0, Math.floor(start / sampleRate) - 1);
5918
+ const skipped = seekSeconds * sampleRate;
5919
+ const end = k === count - 1 ? "" : `:end_sample=${cut(k + 1) - skipped}`;
5885
5920
  return scanTruePeak(
5886
5921
  audioPath,
5887
- `atrim=start_sample=${start}${end},`,
5922
+ `atrim=start_sample=${start - skipped}${end},`,
5888
5923
  timeoutMs,
5889
- segmentSignal
5924
+ segmentSignal,
5925
+ seekSeconds
5890
5926
  );
5891
5927
  })
5892
5928
  ).catch((error) => {
@@ -7318,12 +7354,15 @@ function captureAttemptMadeProgress(attemptTargetFrameCount, remainingFrameCount
7318
7354
  return remainingFrameCount < attemptTargetFrameCount;
7319
7355
  }
7320
7356
  var FIRST_FRAME_STALL_MS = 3e5;
7321
- function frameStallRule(job) {
7357
+ var TAIL_STALL_MS = FIRST_FRAME_STALL_MS;
7358
+ function frameStallRule(job, totalFrames) {
7322
7359
  const noProgressMs = resolveCaptureStallTimeoutMs();
7323
7360
  return {
7324
7361
  progress: () => job.framesRendered ?? 0,
7325
7362
  noProgressMs,
7326
- firstProgressMs: Math.max(FIRST_FRAME_STALL_MS, noProgressMs)
7363
+ firstProgressMs: Math.max(FIRST_FRAME_STALL_MS, noProgressMs),
7364
+ complete: () => (job.framesRendered ?? 0) >= totalFrames,
7365
+ tailMs: Math.max(TAIL_STALL_MS, noProgressMs)
7327
7366
  };
7328
7367
  }
7329
7368
  function isRecoverableParallelCaptureError(error) {
@@ -8283,12 +8322,12 @@ function readPlanProtocolV1(planJson, capabilities = DISTRIBUTED_RENDER_CAPABILI
8283
8322
  }
8284
8323
 
8285
8324
  // src/services/render/stages/planHash.ts
8286
- import { createHash as createHash5 } from "node:crypto";
8325
+ import { createHash as createHash6 } from "node:crypto";
8287
8326
  import { closeSync as closeSync3, createReadStream as createReadStream3, openSync as openSync3, readSync as readSync2 } from "node:fs";
8288
8327
  var PLAN_HASH_SCHEMA_PREFIX = "hyperframes-plan-hash-v1\0";
8289
8328
  var FIELD_DELIMITER = Buffer.from([0]);
8290
8329
  function computePlanHash(input) {
8291
- const hash = createHash5("sha256");
8330
+ const hash = createHash6("sha256");
8292
8331
  hash.update(PLAN_HASH_SCHEMA_PREFIX, "utf8");
8293
8332
  hash.update(input.compositionHtml);
8294
8333
  hash.update(FIELD_DELIMITER);
@@ -8335,12 +8374,12 @@ function canonicalJsonStringify(value) {
8335
8374
  throw new TypeError(`canonicalJsonStringify: unsupported value type ${typeof value}`);
8336
8375
  }
8337
8376
  function sha256Hex(bytes) {
8338
- const h = createHash5("sha256");
8377
+ const h = createHash6("sha256");
8339
8378
  h.update(bytes);
8340
8379
  return h.digest("hex");
8341
8380
  }
8342
8381
  function sha256File(path) {
8343
- const hash = createHash5("sha256");
8382
+ const hash = createHash6("sha256");
8344
8383
  const buffer = Buffer.allocUnsafe(1024 * 1024);
8345
8384
  const fd = openSync3(path, "r");
8346
8385
  try {
@@ -8355,7 +8394,7 @@ function sha256File(path) {
8355
8394
  return hash.digest("hex");
8356
8395
  }
8357
8396
  async function sha256FileAsync(path) {
8358
- const hash = createHash5("sha256");
8397
+ const hash = createHash6("sha256");
8359
8398
  for await (const chunk of createReadStream3(path, { highWaterMark: 1024 * 1024 })) {
8360
8399
  hash.update(chunk);
8361
8400
  }
@@ -9126,7 +9165,7 @@ async function muxChunkWithAudio(input) {
9126
9165
  }
9127
9166
 
9128
9167
  // src/services/distributed/planSize.ts
9129
- import { createHash as createHash6 } from "node:crypto";
9168
+ import { createHash as createHash7 } from "node:crypto";
9130
9169
  import { lstatSync, readdirSync as readdirSync6 } from "node:fs";
9131
9170
  import { extname as extname3, join as join21, relative as relative4 } from "node:path";
9132
9171
  var MAX_TOP_COMPONENTS = 10;
@@ -9156,7 +9195,7 @@ var PLAN_ROOT_CATEGORY = {
9156
9195
  "plan.json": "metadata"
9157
9196
  };
9158
9197
  function hashComponent(value) {
9159
- return createHash6("sha256").update(value).digest("hex").slice(0, 12);
9198
+ return createHash7("sha256").update(value).digest("hex").slice(0, 12);
9160
9199
  }
9161
9200
  function classifyFile(segments, rootKind) {
9162
9201
  const rootName = segments[0] ?? "";
@@ -11945,7 +11984,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
11945
11984
  openAttempt,
11946
11985
  verifyFirstSession: forceScreenshot || !verifyInWorker ? void 0 : verifyFirstWorker
11947
11986
  }),
11948
- { stall: frameStallRule(job) }
11987
+ { stall: frameStallRule(job, framesInChunk) }
11949
11988
  ).catch(async (captureError) => {
11950
11989
  await overlap.current?.abort();
11951
11990
  overlap.current = null;
@@ -12383,7 +12422,7 @@ function validateIntDimension(field, value) {
12383
12422
 
12384
12423
  // src/services/distributed/projectHash.ts
12385
12424
  import { closeSync as closeSync5, openSync as openSync5, readdirSync as readdirSync10, readSync as readSync4, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
12386
- import { createHash as createHash7 } from "node:crypto";
12425
+ import { createHash as createHash8 } from "node:crypto";
12387
12426
  import { join as join29 } from "node:path";
12388
12427
  var SITE_ID_SCHEME = "site-v2\0";
12389
12428
  var READ_CHUNK_BYTES = 256 * 1024;
@@ -12418,7 +12457,7 @@ function listSiteFiles(projectDir) {
12418
12457
  return files;
12419
12458
  }
12420
12459
  function hashProjectDir(projectDir, files = listSiteFiles(projectDir)) {
12421
- const hash = createHash7("sha256").update(SITE_ID_SCHEME);
12460
+ const hash = createHash8("sha256").update(SITE_ID_SCHEME);
12422
12461
  const chunk = Buffer.allocUnsafe(READ_CHUNK_BYTES);
12423
12462
  for (const rel of files) {
12424
12463
  hash.update(rel);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "0.1.0",
3
3
  "buildId": "dev",
4
- "sha256": "518a7f62e938590e96b95612bdc0f5319513bbbf718e76d306d6cde820000983",
4
+ "sha256": "4a2b50826f0f465a4cc6a53e8aff1cd1a58eb9890e83f29d7e02deafd4b9eaf0",
5
5
  "artifacts": {
6
6
  "iife": "hyperframe.runtime.iife.js",
7
7
  "esm": "hyperframe.runtime.mjs"