@hyperframes/producer 0.8.157 → 0.8.159

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.
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/services/renderOrchestrator.ts
2
+ import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
2
3
  import {
3
4
  existsSync as existsSync16,
4
5
  mkdirSync as mkdirSync9,
@@ -1271,15 +1272,17 @@ var EncoderInterruptedError = class extends Error {
1271
1272
  retryable = true;
1272
1273
  /** Retained inside the producer for diagnostics; never copied to the wire envelope. */
1273
1274
  diagnosticMessage;
1274
- constructor(prefix, diagnosticMessage) {
1275
+ audioFailures;
1276
+ constructor(prefix, diagnosticMessage, audioFailures = []) {
1275
1277
  super(`${prefix}: encoder process was interrupted by the host lifecycle`);
1276
1278
  this.name = "EncoderInterruptedError";
1277
1279
  this.diagnosticMessage = diagnosticMessage;
1280
+ this.audioFailures = audioFailures;
1278
1281
  }
1279
1282
  };
1280
1283
  function encoderFailureError(prefix, result) {
1281
1284
  const message = `${prefix}: ${result.error ?? "unknown encoder failure"}`;
1282
- return result.failureReason === "external_interruption" ? new EncoderInterruptedError(prefix, message) : new Error(message);
1285
+ return result.failureReason === "external_interruption" ? new EncoderInterruptedError(prefix, message, result.audioFailures) : new Error(message);
1283
1286
  }
1284
1287
 
1285
1288
  // src/services/render/renderExecutionContext.ts
@@ -8647,8 +8650,12 @@ function appendAutoDetectedVideoAudio(composition, extracted) {
8647
8650
  import { join as join17 } from "node:path";
8648
8651
  import {
8649
8652
  MIXED_AUDIO_FILENAME,
8653
+ audioFailureDiagnostics,
8650
8654
  processCompositionAudio
8651
8655
  } from "@hyperframes/engine";
8656
+ function triggerFirst(failures, trigger) {
8657
+ return [trigger, ...(failures ?? []).filter((failure) => failure !== trigger)];
8658
+ }
8652
8659
  async function runAudioStage(input) {
8653
8660
  const {
8654
8661
  projectDir,
@@ -8714,7 +8721,8 @@ async function runAudioStage(input) {
8714
8721
  if (interrupted) {
8715
8722
  throw encoderFailureError("Audio processing failed", {
8716
8723
  error: interrupted.detail,
8717
- failureReason: "external_interruption"
8724
+ failureReason: "external_interruption",
8725
+ audioFailures: audioFailureDiagnostics(triggerFirst(audioResult.failures, interrupted))
8718
8726
  });
8719
8727
  }
8720
8728
  hasAudio = audioResult.success;
@@ -12170,6 +12178,7 @@ async function executeRenderPipeline(input) {
12170
12178
  message: `Audio mix failed; output would be video-only: ${audioResult.audioError}`,
12171
12179
  details: {
12172
12180
  mediaType: "audio",
12181
+ audioFailures: audioFailureDiagnostics2(audioFailures),
12173
12182
  failureReasons: [...new Set(audioFailures.map((failure) => failure.reason))],
12174
12183
  failureStages: [...new Set(audioFailures.map((failure) => failure.stage))],
12175
12184
  failureOwner,
@@ -14911,6 +14920,7 @@ import {
14911
14920
  import { quantizeTimeToFrame, MEDIA_VISUAL_STYLE_PROPERTIES } from "@hyperframes/engine";
14912
14921
 
14913
14922
  // src/services/distributed/plan.ts
14923
+ import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframes/engine";
14914
14924
  import {
14915
14925
  copyFileSync as copyFileSync5,
14916
14926
  cpSync as cpSync2,
@@ -15691,6 +15701,7 @@ function applyDistributedAudioWarningPolicy(job, audioError, audioFailures = [],
15691
15701
  message: `Audio mix failed; output would be video-only: ${audioError}`,
15692
15702
  details: {
15693
15703
  mediaType: "audio",
15704
+ audioFailures: audioFailureDiagnostics3(audioFailures),
15694
15705
  failureReasons: [...new Set(audioFailures.map((failure) => failure.reason))],
15695
15706
  failureStages: [...new Set(audioFailures.map((failure) => failure.stage))],
15696
15707
  failureOwner,
@@ -19,6 +19,7 @@ import { streamSSE } from "hono/streaming";
19
19
  import { serve as serve2 } from "@hono/node-server";
20
20
 
21
21
  // src/services/renderOrchestrator.ts
22
+ import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
22
23
  import {
23
24
  existsSync as existsSync16,
24
25
  mkdirSync as mkdirSync9,
@@ -1291,15 +1292,17 @@ var EncoderInterruptedError = class extends Error {
1291
1292
  retryable = true;
1292
1293
  /** Retained inside the producer for diagnostics; never copied to the wire envelope. */
1293
1294
  diagnosticMessage;
1294
- constructor(prefix, diagnosticMessage) {
1295
+ audioFailures;
1296
+ constructor(prefix, diagnosticMessage, audioFailures = []) {
1295
1297
  super(`${prefix}: encoder process was interrupted by the host lifecycle`);
1296
1298
  this.name = "EncoderInterruptedError";
1297
1299
  this.diagnosticMessage = diagnosticMessage;
1300
+ this.audioFailures = audioFailures;
1298
1301
  }
1299
1302
  };
1300
1303
  function encoderFailureError(prefix, result) {
1301
1304
  const message = `${prefix}: ${result.error ?? "unknown encoder failure"}`;
1302
- return result.failureReason === "external_interruption" ? new EncoderInterruptedError(prefix, message) : new Error(message);
1305
+ return result.failureReason === "external_interruption" ? new EncoderInterruptedError(prefix, message, result.audioFailures) : new Error(message);
1303
1306
  }
1304
1307
 
1305
1308
  // src/services/render/renderExecutionContext.ts
@@ -8630,8 +8633,12 @@ function appendAutoDetectedVideoAudio(composition, extracted) {
8630
8633
  import { join as join17 } from "node:path";
8631
8634
  import {
8632
8635
  MIXED_AUDIO_FILENAME,
8636
+ audioFailureDiagnostics,
8633
8637
  processCompositionAudio
8634
8638
  } from "@hyperframes/engine";
8639
+ function triggerFirst(failures, trigger) {
8640
+ return [trigger, ...(failures ?? []).filter((failure) => failure !== trigger)];
8641
+ }
8635
8642
  async function runAudioStage(input) {
8636
8643
  const {
8637
8644
  projectDir,
@@ -8697,7 +8704,8 @@ async function runAudioStage(input) {
8697
8704
  if (interrupted) {
8698
8705
  throw encoderFailureError("Audio processing failed", {
8699
8706
  error: interrupted.detail,
8700
- failureReason: "external_interruption"
8707
+ failureReason: "external_interruption",
8708
+ audioFailures: audioFailureDiagnostics(triggerFirst(audioResult.failures, interrupted))
8701
8709
  });
8702
8710
  }
8703
8711
  hasAudio = audioResult.success;
@@ -12153,6 +12161,7 @@ async function executeRenderPipeline(input) {
12153
12161
  message: `Audio mix failed; output would be video-only: ${audioResult.audioError}`,
12154
12162
  details: {
12155
12163
  mediaType: "audio",
12164
+ audioFailures: audioFailureDiagnostics2(audioFailures),
12156
12165
  failureReasons: [...new Set(audioFailures.map((failure) => failure.reason))],
12157
12166
  failureStages: [...new Set(audioFailures.map((failure) => failure.stage))],
12158
12167
  failureOwner,
@@ -1,30 +1,3 @@
1
- /**
2
- * Activity A of the distributed render pipeline.
3
- *
4
- * `buildLocalExecutionPlan(projectDir, config, executionPlanDir)` composes the
5
- * existing render stages (compile → probe → extract videos → audio → freeze)
6
- * into a self-contained local execution directory that downstream chunk
7
- * workers consume:
8
- *
9
- * <planDir>/
10
- * ├── plan.json
11
- * ├── compiled/ # compileForRender output (self-contained)
12
- * ├── video-frames/ # per-video JPEG sequences (dereferenced)
13
- * ├── audio.m4a # only when composition has audio
14
- * └── meta/
15
- * ├── composition.json
16
- * ├── encoder.json # LockedRenderConfig
17
- * └── chunks.json
18
- *
19
- * Pure function over local paths. No networking. Two invocations with the
20
- * same inputs produce the same execution-plan hash. Transport adapters use
21
- * that representation either through the legacy v1 `plan()` wrapper or the
22
- * v2 manifest/CAS publisher.
23
- *
24
- * Banned configurations (GPU encode, hardware browser GL, system primary
25
- * fonts) are rejected at plan time via `planValidation.ts` so chunk workers
26
- * never have to handle them.
27
- */
28
1
  import { type CanvasResolution } from "@hyperframes/core";
29
2
  import { type EngineConfig, type VideoFrameFormat, type AudioProcessingFailure } from "@hyperframes/engine";
30
3
  import { type ProducerLogger } from "../../logger.js";
@@ -1,6 +1,8 @@
1
+ import type { AudioFailureDiagnostic } from "@hyperframes/engine";
1
2
  interface EncoderFailureResult {
2
3
  error?: string;
3
4
  failureReason?: "external_interruption";
5
+ audioFailures?: AudioFailureDiagnostic[];
4
6
  }
5
7
  /** A host/process lifecycle interruption that is safe to retry on a fresh producer. */
6
8
  export declare class EncoderInterruptedError extends Error {
@@ -9,7 +11,8 @@ export declare class EncoderInterruptedError extends Error {
9
11
  readonly retryable: true;
10
12
  /** Retained inside the producer for diagnostics; never copied to the wire envelope. */
11
13
  readonly diagnosticMessage: string;
12
- constructor(prefix: string, diagnosticMessage: string);
14
+ readonly audioFailures: AudioFailureDiagnostic[];
15
+ constructor(prefix: string, diagnosticMessage: string, audioFailures?: AudioFailureDiagnostic[]);
13
16
  }
14
17
  export declare function encoderFailureError(prefix: string, result: EncoderFailureResult): Error;
15
18
  export {};
@@ -0,0 +1,4 @@
1
+ export declare const FFMPEG: string;
2
+ export declare const HAS_FFMPEG: boolean;
3
+ /** Mean grey level of every frame of an encoded video, 0-255. */
4
+ export declare function frameLevels(videoPath: string, width: number, height: number): number[];
@@ -1,34 +1,3 @@
1
- /**
2
- * Render Orchestrator Service
3
- *
4
- * `executeRenderJob` is the in-process entry point that composes the
5
- * pipeline's six stages. Each stage lives in its own module under
6
- * `./render/stages/` so the pure-function primitives can be reused by
7
- * the distributed render path without dragging the orchestrator's
8
- * cleanup and observability scaffolding with them.
9
- *
10
- * Stage 1 compile → services/render/stages/compileStage.ts
11
- * Stage 1b probe → services/render/stages/probeStage.ts
12
- * (browser-driven duration discovery + media reconciliation;
13
- * grouped with Stage 1 in the perf summary)
14
- * Stage 2 extract videos → services/render/stages/extractVideosStage.ts
15
- * Stage 3 audio → services/render/stages/audioStage.ts
16
- * Stage 4 capture → services/render/stages/captureStage.ts
17
- * services/render/stages/captureStreamingStage.ts
18
- * services/render/stages/captureHdrStage.ts
19
- * Stage 5 encode → services/render/stages/encodeStage.ts
20
- * Stage 6 assemble → services/render/stages/assembleStage.ts
21
- *
22
- * Resources spawned by stages (file server, capture sessions, streaming
23
- * encoders, raw HDR frame files) are tracked in the orchestrator's
24
- * `try/finally` so a stage throwing mid-pipeline doesn't leak Chrome
25
- * processes or ffmpeg subprocesses.
26
- *
27
- * Heavy observability: every stage records timing into `perfStages`,
28
- * errors carry full context, and failures produce a diagnostic summary
29
- * (browser console tail, memory peaks, capture attempts, HDR
30
- * diagnostics).
31
- */
32
1
  import { type CanvasResolution, type Fps, type FpsInput, type HfVfxCapture } from "@hyperframes/core";
33
2
  import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, type CaptureFailureKind, type MotionBlurOptions } from "@hyperframes/engine";
34
3
  import { type ProducerLogger } from "../logger.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.157",
3
+ "version": "0.8.159",
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.2.1",
37
37
  "puppeteer-core": "^25.2.1",
38
- "@hyperframes/core": "0.8.157",
39
- "@hyperframes/engine": "0.8.157",
40
- "@hyperframes/lint": "0.8.157",
41
- "@hyperframes/parsers": "0.8.157",
42
- "@hyperframes/studio-server": "0.8.157"
38
+ "@hyperframes/parsers": "0.8.159",
39
+ "@hyperframes/core": "0.8.159",
40
+ "@hyperframes/studio-server": "0.8.159",
41
+ "@hyperframes/engine": "0.8.159",
42
+ "@hyperframes/lint": "0.8.159"
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.8.157"
51
+ "@hyperframes/aws-lambda": "0.8.159"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"