@hyperframes/producer 0.8.181 → 0.8.183

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.
@@ -22,6 +22,8 @@ export interface ArtifactTransactionFileSystem {
22
22
  export interface ArtifactDurationProbeResult {
23
23
  durationSeconds: number;
24
24
  frames?: number;
25
+ width?: number;
26
+ height?: number;
25
27
  }
26
28
  /**
27
29
  * Pluggable probe used by `ArtifactTransaction.validate()` when the caller
@@ -60,6 +62,9 @@ export interface ArtifactValidationExpectation {
60
62
  expectedDurationSeconds: number;
61
63
  fps?: number;
62
64
  expectedFrames?: number;
65
+ /** The output size the render was asked for; a route that ignores it must not publish. */
66
+ expectedWidth?: number;
67
+ expectedHeight?: number;
63
68
  toleranceSeconds?: number;
64
69
  /** Path relative to the staging directory to run the duration probe against. */
65
70
  probeTarget?: string;
@@ -84,6 +89,8 @@ export declare function buildArtifactExpectation(input: {
84
89
  durationSeconds: number;
85
90
  fps: number;
86
91
  expectedFrames: number | undefined;
92
+ width?: number;
93
+ height?: number;
87
94
  }): ArtifactValidationExpectation | undefined;
88
95
  /**
89
96
  * Stages a render beside its final destination and promotes only a validated
@@ -54,12 +54,16 @@ export interface PadTrimAudioInput {
54
54
  probeVideoFrameInfo?: (videoPath: string) => Promise<ProbeVideoFrameInfo>;
55
55
  probeAudioInfo?: (audioPath: string, signal?: AbortSignal) => Promise<AudioProbeInfo>;
56
56
  probeAudioTruePeakDbfs?: (audioPath: string, signal?: AbortSignal) => Promise<number>;
57
- runFfmpeg?: (args: string[]) => Promise<{
58
- success: boolean;
59
- error?: string;
60
- failureReason?: "external_interruption";
61
- }>;
57
+ runFfmpeg?: (args: string[]) => Promise<StepResult>;
58
+ encodeAac?: AacEncoder;
62
59
  }
60
+ interface StepResult {
61
+ success: boolean;
62
+ error?: string;
63
+ failureReason?: "external_interruption";
64
+ }
65
+ /** Encodes `filter` applied to `inputPath` as AAC of exactly `durationSeconds`. */
66
+ type AacEncoder = (inputPath: string, outputPath: string, durationSeconds: number, filter: string) => Promise<StepResult>;
63
67
  export type PadTrimOperation = "pad" | "trim" | "copy";
64
68
  export interface PadTrimAudioResult {
65
69
  success: boolean;
@@ -77,19 +81,21 @@ export interface PadTrimAudioResult {
77
81
  /** dB the true-peak limiter lowered the whole mix by; absent when it did not engage. */
78
82
  audioLoweredDb?: number;
79
83
  }
80
- export type PadTrimAudioStepKind = "copy" | "trim" | "normalize";
81
- export interface PadTrimAudioStep {
82
- kind: PadTrimAudioStepKind;
84
+ export type PadTrimAudioStep = {
85
+ kind: "copy";
83
86
  args: string[];
84
- }
87
+ } | {
88
+ kind: "trim" | "normalize";
89
+ filter: string;
90
+ };
85
91
  export interface PadTrimAudioPlan {
86
92
  operation: PadTrimOperation;
87
93
  steps: PadTrimAudioStep[];
88
94
  cleanupPaths: string[];
89
95
  }
90
96
  /**
91
- * Pure helper: decide the pad/trim operation and build the ffmpeg argv
92
- * sequence that materializes it. Exported separately so unit tests can pin
97
+ * Pure helper: decide the pad/trim operation and the steps that
98
+ * materialize it. Exported separately so unit tests can pin
93
99
  * every branch without spawning ffmpeg.
94
100
  *
95
101
  * - `sourceDuration < targetDuration` → pad with `apad` to the exact target
@@ -102,10 +108,6 @@ export interface PadTrimAudioPlan {
102
108
  * run ffmpeg with `-c:a copy` to materialize the output path.
103
109
  */
104
110
  export declare function buildPadTrimAudioPlan(audioPath: string, outputPath: string, sourceDurationSeconds: number, targetDurationSeconds: number): PadTrimAudioPlan;
105
- export declare function buildPadTrimAudioArgs(audioPath: string, outputPath: string, sourceDurationSeconds: number, targetDurationSeconds: number): {
106
- args: string[];
107
- operation: PadTrimOperation;
108
- };
109
111
  /**
110
112
  * Pad or trim the mixed audio so its exact duration matches `frameCount / fps`
111
113
  * for the assembled video.
@@ -117,6 +119,8 @@ export declare function padOrTrimAudioToVideoFrameCount(input: PadTrimAudioInput
117
119
  */
118
120
  export declare function constrainAacTruePeak(input: {
119
121
  audioPath: string;
122
+ /** The PCM `audioPath` was encoded from: a correction re-encodes it instead of decoding the AAC. */
123
+ sourcePath?: string;
120
124
  targetDurationSeconds: number;
121
125
  signal?: AbortSignal;
122
126
  timeoutMs?: number;
@@ -128,3 +132,4 @@ export declare function constrainAacTruePeak(input: {
128
132
  }>;
129
133
  export declare function defaultProbeVideoFrameInfo(videoPath: string, signal?: AbortSignal): Promise<ProbeVideoFrameInfo>;
130
134
  export declare function runFfprobeJson<T>(args: string[], signal?: AbortSignal): Promise<T>;
135
+ export {};
@@ -1,12 +1,8 @@
1
1
  /**
2
2
  * The true peak one `ebur128=peak=true` pass over the whole file reports, measured in parallel
3
- * segments when the length is known and the rate is 48 kHz: the same digit, not an estimate.
3
+ * segments when the file is 48 kHz with a known length: the same digit, not an estimate.
4
4
  */
5
5
  export declare function measureTruePeakDbfs(audioPath: string, options: {
6
6
  timeoutMs: number;
7
7
  signal?: AbortSignal;
8
- segments?: {
9
- durationSeconds: number;
10
- sampleRate: number;
11
- };
12
8
  }): Promise<number>;
@@ -50,6 +50,8 @@ export declare function roundDb(value: number | undefined): number | undefined;
50
50
  export interface DrawElementPerfInput {
51
51
  compileGate?: string;
52
52
  clampReason?: string;
53
+ /** Engine init-time gate the pre-capture probe hit; its session may be closed before capture. */
54
+ probeGateReason?: string;
53
55
  workerInversion?: "inverted" | "reverted";
54
56
  /** Auto-resolved worker count before the inversion pinned it to 1 (set only when the inversion fired). */
55
57
  preInversionWorkers?: number;
@@ -34,6 +34,8 @@ export interface AudioStageInput {
34
34
  audios: CompositionMetadata["audios"];
35
35
  masterFxChain?: string;
36
36
  urlByAbsentLocalPath?: ReadonlyMap<string, string>;
37
+ /** Keep the float mix the AAC was encoded from here, for a later re-encode from it. */
38
+ keepEncoderInputAt?: string;
37
39
  abortSignal: AbortSignal | undefined;
38
40
  assertNotAborted: () => void;
39
41
  /** Where a per-track failure's detail goes. Optional so tests need not pass one. */
@@ -37,7 +37,7 @@
37
37
  import { type BeforeCaptureHook, type CaptureOptions, type CapturePerfSummary, type CaptureSession, type EngineConfig } from "@hyperframes/engine";
38
38
  import type { FileServerHandle } from "../../fileServer.js";
39
39
  import type { ProducerLogger } from "../../../logger.js";
40
- import { type CaptureAttemptSummary, type ProgressCallback, type RenderJob } from "../../renderOrchestrator.js";
40
+ import { type CaptureAttemptSummary, type ProgressCallback, type RenderConfig, type RenderJob } from "../../renderOrchestrator.js";
41
41
  import type { SdrDiskCapturePlan } from "../capturePlan.js";
42
42
  export interface CaptureStageInput {
43
43
  fileServer: FileServerHandle;
@@ -121,8 +121,13 @@ export type DiskCaptureHeadroom = {
121
121
  };
122
122
  /** Shared 90% disk gate used by both fallback planning and disk execution. */
123
123
  export declare function inspectDiskCaptureHeadroom(framesDir: string, totalFrames: number, captureOptions: CaptureOptions, freeDiskBytes?: (path: string) => number | null): DiskCaptureHeadroom;
124
- export declare function diskCaptureShortfallError(needBytes: number, freeBytes: number, framesDir: string, basis: "estimate" | "measured"): Error;
125
- export declare function assertDiskCaptureHeadroom(framesDir: string, totalFrames: number, captureOptions: CaptureOptions, freeDiskBytes?: (path: string) => number | null): void;
124
+ /**
125
+ * Why this render stores frames and what would take it off disk. `--workers 1`
126
+ * is offered only when a one-worker run of the same render would stream.
127
+ */
128
+ export declare function diskCaptureRemedy(cfg: EngineConfig, outputFormat: NonNullable<RenderConfig["format"]>, durationSeconds: number, workerCount: number): string;
129
+ export declare function diskCaptureShortfallError(needBytes: number, freeBytes: number, framesDir: string, basis: "estimate" | "measured", remedy: string): Error;
130
+ export declare function assertDiskCaptureHeadroom(framesDir: string, totalFrames: number, captureOptions: CaptureOptions, remedy: string, freeDiskBytes?: (path: string) => number | null): void;
126
131
  /** Frame bytes written so far: the merged frames dir plus every capture attempt's worker dirs. */
127
132
  export declare function measureCaptureFrameBytes(workDir: string, framesDir: string): number;
128
133
  /** Per-frame callback: after the sample frames, throws if the projected remainder exceeds 90% of free space. */
@@ -130,6 +135,7 @@ export declare function createDiskCaptureProjection(input: {
130
135
  framesDir: string;
131
136
  totalFrames: number;
132
137
  measureBytes: () => number;
138
+ remedy: string;
133
139
  freeDiskBytes?: (path: string) => number | null;
134
140
  }): (capturedFrames: number) => void;
135
141
  export declare function runCaptureStage(input: CaptureStageInput): Promise<CaptureStageResult>;
@@ -70,6 +70,7 @@ export interface LockedRenderConfig {
70
70
  */
71
71
  variables?: Record<string, unknown>;
72
72
  chunksCarryAudio?: true;
73
+ separateAudio?: true;
73
74
  }
74
75
  export interface CompositionMetadataJson {
75
76
  durationSeconds: number;
@@ -1152,8 +1152,8 @@ export declare function closeOrphanedProbeForRetry(probe: CaptureSession, closer
1152
1152
  */
1153
1153
  export declare function resolveParallelCaptureMode(args: {
1154
1154
  platform: NodeJS.Platform;
1155
- /** A chrome-headless-shell binary was resolved for this render. */
1156
- headlessShell: boolean;
1155
+ /** The chrome-headless-shell binary resolved for this render, if any. */
1156
+ headlessShellPath: string | undefined;
1157
1157
  forceScreenshot: boolean;
1158
1158
  deviceScaleFactor?: number;
1159
1159
  }): "screenshot" | "beginframe";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/producer",
3
- "version": "0.8.181",
3
+ "version": "0.8.183",
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.181",
39
- "@hyperframes/lint": "0.8.181",
40
- "@hyperframes/engine": "0.8.181",
41
- "@hyperframes/parsers": "0.8.181",
42
- "@hyperframes/studio-server": "0.8.181"
38
+ "@hyperframes/core": "0.8.183",
39
+ "@hyperframes/engine": "0.8.183",
40
+ "@hyperframes/parsers": "0.8.183",
41
+ "@hyperframes/studio-server": "0.8.183",
42
+ "@hyperframes/lint": "0.8.183"
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.181"
51
+ "@hyperframes/aws-lambda": "0.8.183"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"