@hyperframes/producer 0.9.12 → 0.9.13

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.
@@ -1124,27 +1124,25 @@ var materializeFileSystem = {
1124
1124
  rmSync
1125
1125
  };
1126
1126
  var warnedSymlinkFallback = false;
1127
+ var copyCannotFix = (error) => ["ENOSPC", "EDQUOT", "EEXIST", "ENOENT"].includes(
1128
+ error?.code ?? ""
1129
+ );
1127
1130
  function tryWindowsFrameJunction(fileSystem, src, dest) {
1128
1131
  if (process.platform !== "win32") return false;
1129
1132
  try {
1130
1133
  fileSystem.symlinkSync(src, dest, "junction");
1131
1134
  return true;
1132
1135
  } catch (error) {
1133
- const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
1134
- if (["EPERM", "EACCES", "UNKNOWN", "EINVAL", "ENOSYS", "EOPNOTSUPP", "ENOTSUP"].includes(
1135
- code ?? ""
1136
- )) {
1137
- return false;
1138
- }
1139
- throw error;
1136
+ if (copyCannotFix(error)) throw error;
1137
+ return false;
1140
1138
  }
1141
1139
  }
1142
1140
  function linkOrCopyFrameDir(fileSystem, src, dest) {
1143
1141
  try {
1144
1142
  fileSystem.symlinkSync(src, dest, "dir");
1145
1143
  } catch (err) {
1144
+ if (copyCannotFix(err)) throw err;
1146
1145
  const code = err?.code;
1147
- if (code !== "EPERM" && code !== "EACCES" && code !== "UNKNOWN") throw err;
1148
1146
  if (tryWindowsFrameJunction(fileSystem, src, dest)) return;
1149
1147
  if (!warnedSymlinkFallback) {
1150
1148
  warnedSymlinkFallback = true;
@@ -5585,17 +5583,24 @@ var VideoExtractionStageError = class extends Error {
5585
5583
  publicMetadata;
5586
5584
  };
5587
5585
  function assertVideoExtractionSucceeded(result) {
5588
- throwIfEncoderInterrupted(result);
5586
+ throwIfHostFailure(result);
5589
5587
  const error = buildVideoExtractionStageError(result);
5590
5588
  if (error) throw error;
5591
5589
  }
5592
- function throwIfEncoderInterrupted(result) {
5590
+ function throwIfHostFailure(result) {
5593
5591
  const interrupted = result.errors.find((failure) => failure.kind === "external_interruption");
5594
- if (!interrupted) return;
5595
- throw encoderFailureError("Video frame extraction failed", {
5596
- error: String(interrupted.error),
5597
- failureReason: "external_interruption"
5598
- });
5592
+ if (interrupted) {
5593
+ throw encoderFailureError("Video frame extraction failed", {
5594
+ error: String(interrupted.error),
5595
+ failureReason: "external_interruption"
5596
+ });
5597
+ }
5598
+ const full = result.errors.filter((failure) => failure.kind === "disk_full").length;
5599
+ if (full === 0) return;
5600
+ throw Object.assign(
5601
+ new Error(`ENOSPC: no space left on device, extracting the frames of ${full} video source(s)`),
5602
+ { code: "ENOSPC" }
5603
+ );
5599
5604
  }
5600
5605
  function buildVideoExtractionStageError(result) {
5601
5606
  if (result.success && result.errors.length === 0) return null;
@@ -5810,7 +5815,7 @@ async function runExtractVideosStage(input) {
5810
5815
  );
5811
5816
  extractionResult.phaseBreakdown.transientRetries = (extractionResult.phaseBreakdown.transientRetries ?? 0) + hdrProbeTransientRetries;
5812
5817
  assertNotAborted();
5813
- throwIfEncoderInterrupted(extractionResult);
5818
+ throwIfHostFailure(extractionResult);
5814
5819
  failureToEnforce = applyVideoExtractionFailurePolicy(extractionResult, extractionPolicy, log);
5815
5820
  materializeExtractedFramesForCompiledDir(extractionResult.extracted, compiledDir, {
5816
5821
  materializeSymlinks
@@ -7651,6 +7656,22 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
7651
7656
  }
7652
7657
  const remainingCount = countFrameRanges(remaining);
7653
7658
  const madeProgress = captureAttemptMadeProgress(frameCount, remainingCount);
7659
+ if (options.allowRetry && !madeProgress && (currentWorkers > 1 || initializationRetriesUsed === 0 && failure.kind === "protocol_timeout") && /\bNetwork\.enable timed out|Navigation timeout of \d+ ms exceeded/i.test(failure.message)) {
7660
+ initializationRetriesUsed++;
7661
+ const nextWorkers2 = getNextRetryWorkerCount(currentWorkers);
7662
+ options.log.warn(
7663
+ "[Render] Browser initialization timed out; retrying with fewer workers.",
7664
+ {
7665
+ fromWorkers: currentWorkers,
7666
+ toWorkers: nextWorkers2,
7667
+ error: failure.message
7668
+ }
7669
+ );
7670
+ currentWorkers = nextWorkers2;
7671
+ missingRanges = remaining;
7672
+ attempt++;
7673
+ continue;
7674
+ }
7654
7675
  if (options.allowRetry && isTransientCaptureRetryEligible(failure.kind, remaining, transientRetriesUsed)) {
7655
7676
  transientRetriesUsed++;
7656
7677
  options.log.warn(
@@ -7668,22 +7689,6 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
7668
7689
  pendingTransientRetry = true;
7669
7690
  continue;
7670
7691
  }
7671
- if (options.allowRetry && !madeProgress && initializationRetriesUsed === 0 && failure.kind === "protocol_timeout" && /\bNetwork\.enable timed out/i.test(failure.message)) {
7672
- initializationRetriesUsed++;
7673
- const nextWorkers2 = getNextRetryWorkerCount(currentWorkers);
7674
- options.log.warn(
7675
- "[Render] Browser initialization timed out; retrying once with fresh sessions.",
7676
- {
7677
- fromWorkers: currentWorkers,
7678
- toWorkers: nextWorkers2,
7679
- error: failure.message
7680
- }
7681
- );
7682
- currentWorkers = nextWorkers2;
7683
- missingRanges = remaining;
7684
- attempt++;
7685
- continue;
7686
- }
7687
7692
  if (!madeProgress) {
7688
7693
  options.log.warn(
7689
7694
  "[Render] Capture attempt made no forward progress; composition is likely structurally broken, not retrying.",
package/dist/index.js CHANGED
@@ -1223,27 +1223,25 @@ function createMemorySampler(intervalMs = 250) {
1223
1223
  };
1224
1224
  }
1225
1225
  var warnedSymlinkFallback = false;
1226
+ var copyCannotFix = (error) => ["ENOSPC", "EDQUOT", "EEXIST", "ENOENT"].includes(
1227
+ error?.code ?? ""
1228
+ );
1226
1229
  function tryWindowsFrameJunction(fileSystem, src, dest) {
1227
1230
  if (process.platform !== "win32") return false;
1228
1231
  try {
1229
1232
  fileSystem.symlinkSync(src, dest, "junction");
1230
1233
  return true;
1231
1234
  } catch (error) {
1232
- const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
1233
- if (["EPERM", "EACCES", "UNKNOWN", "EINVAL", "ENOSYS", "EOPNOTSUPP", "ENOTSUP"].includes(
1234
- code ?? ""
1235
- )) {
1236
- return false;
1237
- }
1238
- throw error;
1235
+ if (copyCannotFix(error)) throw error;
1236
+ return false;
1239
1237
  }
1240
1238
  }
1241
1239
  function linkOrCopyFrameDir(fileSystem, src, dest) {
1242
1240
  try {
1243
1241
  fileSystem.symlinkSync(src, dest, "dir");
1244
1242
  } catch (err) {
1243
+ if (copyCannotFix(err)) throw err;
1245
1244
  const code = err?.code;
1246
- if (code !== "EPERM" && code !== "EACCES" && code !== "UNKNOWN") throw err;
1247
1245
  if (tryWindowsFrameJunction(fileSystem, src, dest)) return;
1248
1246
  if (!warnedSymlinkFallback) {
1249
1247
  warnedSymlinkFallback = true;
@@ -9528,17 +9526,24 @@ var VideoExtractionStageError = class extends Error {
9528
9526
  publicMetadata;
9529
9527
  };
9530
9528
  function assertVideoExtractionSucceeded(result) {
9531
- throwIfEncoderInterrupted(result);
9529
+ throwIfHostFailure(result);
9532
9530
  const error = buildVideoExtractionStageError(result);
9533
9531
  if (error) throw error;
9534
9532
  }
9535
- function throwIfEncoderInterrupted(result) {
9533
+ function throwIfHostFailure(result) {
9536
9534
  const interrupted = result.errors.find((failure) => failure.kind === "external_interruption");
9537
- if (!interrupted) return;
9538
- throw encoderFailureError("Video frame extraction failed", {
9539
- error: String(interrupted.error),
9540
- failureReason: "external_interruption"
9541
- });
9535
+ if (interrupted) {
9536
+ throw encoderFailureError("Video frame extraction failed", {
9537
+ error: String(interrupted.error),
9538
+ failureReason: "external_interruption"
9539
+ });
9540
+ }
9541
+ const full = result.errors.filter((failure) => failure.kind === "disk_full").length;
9542
+ if (full === 0) return;
9543
+ throw Object.assign(
9544
+ new Error(`ENOSPC: no space left on device, extracting the frames of ${full} video source(s)`),
9545
+ { code: "ENOSPC" }
9546
+ );
9542
9547
  }
9543
9548
  function buildVideoExtractionStageError(result) {
9544
9549
  if (result.success && result.errors.length === 0) return null;
@@ -9753,7 +9758,7 @@ async function runExtractVideosStage(input) {
9753
9758
  );
9754
9759
  extractionResult.phaseBreakdown.transientRetries = (extractionResult.phaseBreakdown.transientRetries ?? 0) + hdrProbeTransientRetries;
9755
9760
  assertNotAborted();
9756
- throwIfEncoderInterrupted(extractionResult);
9761
+ throwIfHostFailure(extractionResult);
9757
9762
  failureToEnforce = applyVideoExtractionFailurePolicy(extractionResult, extractionPolicy, log);
9758
9763
  materializeExtractedFramesForCompiledDir(extractionResult.extracted, compiledDir, {
9759
9764
  materializeSymlinks
@@ -12891,6 +12896,22 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
12891
12896
  }
12892
12897
  const remainingCount = countFrameRanges(remaining);
12893
12898
  const madeProgress = captureAttemptMadeProgress(frameCount, remainingCount);
12899
+ if (options.allowRetry && !madeProgress && (currentWorkers > 1 || initializationRetriesUsed === 0 && failure.kind === "protocol_timeout") && /\bNetwork\.enable timed out|Navigation timeout of \d+ ms exceeded/i.test(failure.message)) {
12900
+ initializationRetriesUsed++;
12901
+ const nextWorkers2 = getNextRetryWorkerCount(currentWorkers);
12902
+ options.log.warn(
12903
+ "[Render] Browser initialization timed out; retrying with fewer workers.",
12904
+ {
12905
+ fromWorkers: currentWorkers,
12906
+ toWorkers: nextWorkers2,
12907
+ error: failure.message
12908
+ }
12909
+ );
12910
+ currentWorkers = nextWorkers2;
12911
+ missingRanges = remaining;
12912
+ attempt++;
12913
+ continue;
12914
+ }
12894
12915
  if (options.allowRetry && isTransientCaptureRetryEligible(failure.kind, remaining, transientRetriesUsed)) {
12895
12916
  transientRetriesUsed++;
12896
12917
  options.log.warn(
@@ -12908,22 +12929,6 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
12908
12929
  pendingTransientRetry = true;
12909
12930
  continue;
12910
12931
  }
12911
- if (options.allowRetry && !madeProgress && initializationRetriesUsed === 0 && failure.kind === "protocol_timeout" && /\bNetwork\.enable timed out/i.test(failure.message)) {
12912
- initializationRetriesUsed++;
12913
- const nextWorkers2 = getNextRetryWorkerCount(currentWorkers);
12914
- options.log.warn(
12915
- "[Render] Browser initialization timed out; retrying once with fresh sessions.",
12916
- {
12917
- fromWorkers: currentWorkers,
12918
- toWorkers: nextWorkers2,
12919
- error: failure.message
12920
- }
12921
- );
12922
- currentWorkers = nextWorkers2;
12923
- missingRanges = remaining;
12924
- attempt++;
12925
- continue;
12926
- }
12927
12932
  if (!madeProgress) {
12928
12933
  options.log.warn(
12929
12934
  "[Render] Capture attempt made no forward progress; composition is likely structurally broken, not retrying.",
@@ -1237,27 +1237,25 @@ function createMemorySampler(intervalMs = 250) {
1237
1237
  };
1238
1238
  }
1239
1239
  var warnedSymlinkFallback = false;
1240
+ var copyCannotFix = (error) => ["ENOSPC", "EDQUOT", "EEXIST", "ENOENT"].includes(
1241
+ error?.code ?? ""
1242
+ );
1240
1243
  function tryWindowsFrameJunction(fileSystem, src, dest) {
1241
1244
  if (process.platform !== "win32") return false;
1242
1245
  try {
1243
1246
  fileSystem.symlinkSync(src, dest, "junction");
1244
1247
  return true;
1245
1248
  } catch (error) {
1246
- const code = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
1247
- if (["EPERM", "EACCES", "UNKNOWN", "EINVAL", "ENOSYS", "EOPNOTSUPP", "ENOTSUP"].includes(
1248
- code ?? ""
1249
- )) {
1250
- return false;
1251
- }
1252
- throw error;
1249
+ if (copyCannotFix(error)) throw error;
1250
+ return false;
1253
1251
  }
1254
1252
  }
1255
1253
  function linkOrCopyFrameDir(fileSystem, src, dest) {
1256
1254
  try {
1257
1255
  fileSystem.symlinkSync(src, dest, "dir");
1258
1256
  } catch (err) {
1257
+ if (copyCannotFix(err)) throw err;
1259
1258
  const code = err?.code;
1260
- if (code !== "EPERM" && code !== "EACCES" && code !== "UNKNOWN") throw err;
1261
1259
  if (tryWindowsFrameJunction(fileSystem, src, dest)) return;
1262
1260
  if (!warnedSymlinkFallback) {
1263
1261
  warnedSymlinkFallback = true;
@@ -9508,13 +9506,20 @@ var VideoExtractionStageError = class extends Error {
9508
9506
  */
9509
9507
  publicMetadata;
9510
9508
  };
9511
- function throwIfEncoderInterrupted(result) {
9509
+ function throwIfHostFailure(result) {
9512
9510
  const interrupted = result.errors.find((failure) => failure.kind === "external_interruption");
9513
- if (!interrupted) return;
9514
- throw encoderFailureError("Video frame extraction failed", {
9515
- error: String(interrupted.error),
9516
- failureReason: "external_interruption"
9517
- });
9511
+ if (interrupted) {
9512
+ throw encoderFailureError("Video frame extraction failed", {
9513
+ error: String(interrupted.error),
9514
+ failureReason: "external_interruption"
9515
+ });
9516
+ }
9517
+ const full = result.errors.filter((failure) => failure.kind === "disk_full").length;
9518
+ if (full === 0) return;
9519
+ throw Object.assign(
9520
+ new Error(`ENOSPC: no space left on device, extracting the frames of ${full} video source(s)`),
9521
+ { code: "ENOSPC" }
9522
+ );
9518
9523
  }
9519
9524
  function buildVideoExtractionStageError(result) {
9520
9525
  if (result.success && result.errors.length === 0) return null;
@@ -9729,7 +9734,7 @@ async function runExtractVideosStage(input) {
9729
9734
  );
9730
9735
  extractionResult.phaseBreakdown.transientRetries = (extractionResult.phaseBreakdown.transientRetries ?? 0) + hdrProbeTransientRetries;
9731
9736
  assertNotAborted();
9732
- throwIfEncoderInterrupted(extractionResult);
9737
+ throwIfHostFailure(extractionResult);
9733
9738
  failureToEnforce = applyVideoExtractionFailurePolicy(extractionResult, extractionPolicy, log);
9734
9739
  materializeExtractedFramesForCompiledDir(extractionResult.extracted, compiledDir, {
9735
9740
  materializeSymlinks
@@ -12867,6 +12872,22 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
12867
12872
  }
12868
12873
  const remainingCount = countFrameRanges(remaining);
12869
12874
  const madeProgress = captureAttemptMadeProgress(frameCount, remainingCount);
12875
+ if (options.allowRetry && !madeProgress && (currentWorkers > 1 || initializationRetriesUsed === 0 && failure.kind === "protocol_timeout") && /\bNetwork\.enable timed out|Navigation timeout of \d+ ms exceeded/i.test(failure.message)) {
12876
+ initializationRetriesUsed++;
12877
+ const nextWorkers2 = getNextRetryWorkerCount(currentWorkers);
12878
+ options.log.warn(
12879
+ "[Render] Browser initialization timed out; retrying with fewer workers.",
12880
+ {
12881
+ fromWorkers: currentWorkers,
12882
+ toWorkers: nextWorkers2,
12883
+ error: failure.message
12884
+ }
12885
+ );
12886
+ currentWorkers = nextWorkers2;
12887
+ missingRanges = remaining;
12888
+ attempt++;
12889
+ continue;
12890
+ }
12870
12891
  if (options.allowRetry && isTransientCaptureRetryEligible(failure.kind, remaining, transientRetriesUsed)) {
12871
12892
  transientRetriesUsed++;
12872
12893
  options.log.warn(
@@ -12884,22 +12905,6 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
12884
12905
  pendingTransientRetry = true;
12885
12906
  continue;
12886
12907
  }
12887
- if (options.allowRetry && !madeProgress && initializationRetriesUsed === 0 && failure.kind === "protocol_timeout" && /\bNetwork\.enable timed out/i.test(failure.message)) {
12888
- initializationRetriesUsed++;
12889
- const nextWorkers2 = getNextRetryWorkerCount(currentWorkers);
12890
- options.log.warn(
12891
- "[Render] Browser initialization timed out; retrying once with fresh sessions.",
12892
- {
12893
- fromWorkers: currentWorkers,
12894
- toWorkers: nextWorkers2,
12895
- error: failure.message
12896
- }
12897
- );
12898
- currentWorkers = nextWorkers2;
12899
- missingRanges = remaining;
12900
- attempt++;
12901
- continue;
12902
- }
12903
12908
  if (!madeProgress) {
12904
12909
  options.log.warn(
12905
12910
  "[Render] Capture attempt made no forward progress; composition is likely structurally broken, not retrying.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.9.12",
3
+ "version": "0.9.13",
4
4
  "description": "HTML-to-video rendering engine using Chrome's BeginFrame API",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,11 +35,11 @@
35
35
  "postcss": "^8.4.0",
36
36
  "puppeteer": "~25.11.0",
37
37
  "puppeteer-core": "^25.11.0",
38
- "@hyperframes/core": "0.9.12",
39
- "@hyperframes/engine": "0.9.12",
40
- "@hyperframes/lint": "0.9.12",
41
- "@hyperframes/parsers": "0.9.12",
42
- "@hyperframes/studio-server": "0.9.12"
38
+ "@hyperframes/lint": "0.9.13",
39
+ "@hyperframes/core": "0.9.13",
40
+ "@hyperframes/engine": "0.9.13",
41
+ "@hyperframes/parsers": "0.9.13",
42
+ "@hyperframes/studio-server": "0.9.13"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^25.0.10",
@@ -48,7 +48,7 @@
48
48
  "tsx": "^4.21.0",
49
49
  "typescript": "^5.7.2",
50
50
  "vitest": "^4.1.11",
51
- "@hyperframes/aws-lambda": "0.9.12"
51
+ "@hyperframes/aws-lambda": "0.9.13"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"