@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/distributed.js +13 -3
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +55 -55
- package/dist/index.js +14 -3
- package/dist/public-server.js +12 -3
- package/dist/services/distributed/plan.d.ts +0 -27
- package/dist/services/render/encoderInterruption.d.ts +4 -1
- package/dist/services/render/frameLevelsTestFixtures.d.ts +4 -0
- package/dist/services/renderOrchestrator.d.ts +0 -31
- package/package.json +7 -7
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
|
-
|
|
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,
|
package/dist/public-server.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 {};
|
|
@@ -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.
|
|
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/
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/
|
|
41
|
-
"@hyperframes/
|
|
42
|
-
"@hyperframes/
|
|
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.
|
|
51
|
+
"@hyperframes/aws-lambda": "0.8.159"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|