@hyperframes/engine 0.7.59 → 0.7.61

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.
Files changed (76) hide show
  1. package/README.md +3 -4
  2. package/dist/config.d.ts +95 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +131 -16
  5. package/dist/config.js.map +1 -1
  6. package/dist/index.d.ts +7 -3
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +7 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/services/audioMixer.d.ts.map +1 -1
  11. package/dist/services/audioMixer.js +38 -3
  12. package/dist/services/audioMixer.js.map +1 -1
  13. package/dist/services/browserLeasePool.d.ts +48 -0
  14. package/dist/services/browserLeasePool.d.ts.map +1 -0
  15. package/dist/services/browserLeasePool.js +210 -0
  16. package/dist/services/browserLeasePool.js.map +1 -0
  17. package/dist/services/browserManager.d.ts +6 -7
  18. package/dist/services/browserManager.d.ts.map +1 -1
  19. package/dist/services/browserManager.js +134 -177
  20. package/dist/services/browserManager.js.map +1 -1
  21. package/dist/services/chunkEncoder.d.ts.map +1 -1
  22. package/dist/services/chunkEncoder.js +45 -134
  23. package/dist/services/chunkEncoder.js.map +1 -1
  24. package/dist/services/frameCapture.d.ts +38 -1
  25. package/dist/services/frameCapture.d.ts.map +1 -1
  26. package/dist/services/frameCapture.js +119 -8
  27. package/dist/services/frameCapture.js.map +1 -1
  28. package/dist/services/pageNavigationTimeoutErrorHint.d.ts +79 -0
  29. package/dist/services/pageNavigationTimeoutErrorHint.d.ts.map +1 -0
  30. package/dist/services/pageNavigationTimeoutErrorHint.js +112 -0
  31. package/dist/services/pageNavigationTimeoutErrorHint.js.map +1 -0
  32. package/dist/services/parallelCoordinator.d.ts +21 -0
  33. package/dist/services/parallelCoordinator.d.ts.map +1 -1
  34. package/dist/services/parallelCoordinator.js +40 -1
  35. package/dist/services/parallelCoordinator.js.map +1 -1
  36. package/dist/services/protocolTimeoutErrorHint.d.ts +28 -0
  37. package/dist/services/protocolTimeoutErrorHint.d.ts.map +1 -0
  38. package/dist/services/protocolTimeoutErrorHint.js +45 -0
  39. package/dist/services/protocolTimeoutErrorHint.js.map +1 -0
  40. package/dist/services/streamingEncoder.d.ts.map +1 -1
  41. package/dist/services/streamingEncoder.js +23 -58
  42. package/dist/services/streamingEncoder.js.map +1 -1
  43. package/dist/services/systemMemory.d.ts.map +1 -1
  44. package/dist/services/systemMemory.js +4 -1
  45. package/dist/services/systemMemory.js.map +1 -1
  46. package/dist/services/videoFrameExtractor.d.ts +4 -5
  47. package/dist/services/videoFrameExtractor.d.ts.map +1 -1
  48. package/dist/services/videoFrameExtractor.js +57 -112
  49. package/dist/services/videoFrameExtractor.js.map +1 -1
  50. package/dist/types.d.ts +28 -0
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/utils/ffmpegBinaries.d.ts +2 -2
  53. package/dist/utils/ffmpegBinaries.d.ts.map +1 -1
  54. package/dist/utils/ffmpegBinaries.js +8 -82
  55. package/dist/utils/ffmpegBinaries.js.map +1 -1
  56. package/dist/utils/ffprobe.d.ts +3 -1
  57. package/dist/utils/ffprobe.d.ts.map +1 -1
  58. package/dist/utils/ffprobe.js +35 -42
  59. package/dist/utils/ffprobe.js.map +1 -1
  60. package/dist/utils/gpuEncoder.d.ts.map +1 -1
  61. package/dist/utils/gpuEncoder.js +32 -52
  62. package/dist/utils/gpuEncoder.js.map +1 -1
  63. package/dist/utils/gpuParityDiff.d.ts +142 -0
  64. package/dist/utils/gpuParityDiff.d.ts.map +1 -0
  65. package/dist/utils/gpuParityDiff.js +205 -0
  66. package/dist/utils/gpuParityDiff.js.map +1 -0
  67. package/dist/utils/managedChildProcess.d.ts +50 -0
  68. package/dist/utils/managedChildProcess.d.ts.map +1 -0
  69. package/dist/utils/managedChildProcess.js +148 -0
  70. package/dist/utils/managedChildProcess.js.map +1 -0
  71. package/dist/utils/processTracker.js +1 -1
  72. package/dist/utils/runFfmpeg.d.ts +3 -0
  73. package/dist/utils/runFfmpeg.d.ts.map +1 -1
  74. package/dist/utils/runFfmpeg.js +16 -50
  75. package/dist/utils/runFfmpeg.js.map +1 -1
  76. package/package.json +3 -2
@@ -0,0 +1,205 @@
1
+ /**
2
+ * GPU Parity Diff — diagnostic helpers for detecting shape-dependent
3
+ * hardware-GPU capture bugs by comparing frames captured via the two
4
+ * capture paths (hardware-GPU vs software-GPU / screenshot bypass).
5
+ *
6
+ * Field pattern this exists to catch:
7
+ *
8
+ * • ts=1784049136 · hardware-GPU capture emitted intermittent black
9
+ * rectangles in one scene; `--no-browser-gpu --low-memory-mode
10
+ * --workers 1` (software-GPU screenshot mode) resolved it.
11
+ * • ts=1784032286 · animated `clip-path` on a large image → intermittent
12
+ * black rectangles from Chrome capture; deterministic precomposited
13
+ * swipe states removed the artifact.
14
+ * • Baseline · JetBrains Mono glyph-drop on parallel/BeginFrame text
15
+ * capture.
16
+ *
17
+ * Common shape: hardware-GPU writes solid-black regions where content
18
+ * should exist; software-GPU / screenshot fallback renders the same
19
+ * region correctly. A raw per-pixel diff is a coarse signal for this —
20
+ * on its own it fires on every animation frame's compositor jitter, so
21
+ * this module also isolates the *asymmetric* black-in-A-only pattern
22
+ * that is the diagnostic fingerprint of the bug.
23
+ *
24
+ * This module is the reduced-scope first pass: a pure helper + unit
25
+ * tests. Wiring a `hyperframes verify-gpu-parity` CLI surface, capture
26
+ * orchestration, and integration coverage is intentionally deferred to
27
+ * a follow-up so the diagnostic primitive can land and be exercised
28
+ * against real captured frames in isolation.
29
+ */
30
+ import { decodePng } from "./alphaBlit.js";
31
+ // ── Defaults ────────────────────────────────────────────────────────────────
32
+ const DEFAULT_PIXEL_CHANNEL_TOLERANCE = 8;
33
+ const DEFAULT_BLACK_SUM_THRESHOLD = 12;
34
+ const DEFAULT_CONTENT_SUM_THRESHOLD = 32;
35
+ const DEFAULT_BLACK_ONLY_FRACTION_THRESHOLD = 0.001;
36
+ // ── Core diff ───────────────────────────────────────────────────────────────
37
+ /**
38
+ * Compare two RGBA frames captured via different GPU paths.
39
+ *
40
+ * The two inputs must have identical dimensions; on mismatch this throws
41
+ * (with the mismatched sizes surfaced in the message) so callers cannot
42
+ * silently compare misaligned frames.
43
+ *
44
+ * Alpha channel is *not* considered for the black-only detection — Chrome's
45
+ * capture output is opaque along the code paths this diagnostic targets,
46
+ * and considering alpha would false-positive on legitimately transparent
47
+ * pixels. `pixelChannelTolerance` also compares only R/G/B for the same
48
+ * reason.
49
+ */
50
+ export function diffGpuParityFrames(a, b, options = {}) {
51
+ if (a.width !== b.width || a.height !== b.height) {
52
+ throw new Error(`diffGpuParityFrames: frame size mismatch — A is ${a.width}x${a.height}, ` +
53
+ `B is ${b.width}x${b.height}`);
54
+ }
55
+ const expectedLen = a.width * a.height * 4;
56
+ if (a.data.length !== expectedLen) {
57
+ throw new Error(`diffGpuParityFrames: frame A data length ${a.data.length} does not match ` +
58
+ `expected ${expectedLen} (${a.width}x${a.height} * 4)`);
59
+ }
60
+ if (b.data.length !== expectedLen) {
61
+ throw new Error(`diffGpuParityFrames: frame B data length ${b.data.length} does not match ` +
62
+ `expected ${expectedLen} (${b.width}x${b.height} * 4)`);
63
+ }
64
+ const tol = options.pixelChannelTolerance ?? DEFAULT_PIXEL_CHANNEL_TOLERANCE;
65
+ const blackSum = options.blackSumThreshold ?? DEFAULT_BLACK_SUM_THRESHOLD;
66
+ const contentSum = options.contentSumThreshold ?? DEFAULT_CONTENT_SUM_THRESHOLD;
67
+ if (contentSum <= blackSum) {
68
+ throw new Error(`diffGpuParityFrames: contentSumThreshold (${contentSum}) must be strictly greater ` +
69
+ `than blackSumThreshold (${blackSum}) — overlapping thresholds would double-classify ` +
70
+ `borderline pixels`);
71
+ }
72
+ const total = a.width * a.height;
73
+ const aData = a.data;
74
+ const bData = b.data;
75
+ let diffPixels = 0;
76
+ let blackOnlyAPixels = 0;
77
+ let blackOnlyBPixels = 0;
78
+ let aMinX = a.width;
79
+ let aMinY = a.height;
80
+ let aMaxX = -1;
81
+ let aMaxY = -1;
82
+ let bMinX = a.width;
83
+ let bMinY = a.height;
84
+ let bMaxX = -1;
85
+ let bMaxY = -1;
86
+ for (let y = 0; y < a.height; y++) {
87
+ for (let x = 0; x < a.width; x++) {
88
+ const i = (y * a.width + x) * 4;
89
+ const ar = aData[i] ?? 0;
90
+ const ag = aData[i + 1] ?? 0;
91
+ const ab = aData[i + 2] ?? 0;
92
+ const br = bData[i] ?? 0;
93
+ const bg = bData[i + 1] ?? 0;
94
+ const bb = bData[i + 2] ?? 0;
95
+ if (Math.abs(ar - br) > tol || Math.abs(ag - bg) > tol || Math.abs(ab - bb) > tol) {
96
+ diffPixels++;
97
+ }
98
+ const aSum = ar + ag + ab;
99
+ const bSum = br + bg + bb;
100
+ if (aSum <= blackSum && bSum >= contentSum) {
101
+ blackOnlyAPixels++;
102
+ if (x < aMinX)
103
+ aMinX = x;
104
+ if (y < aMinY)
105
+ aMinY = y;
106
+ if (x > aMaxX)
107
+ aMaxX = x;
108
+ if (y > aMaxY)
109
+ aMaxY = y;
110
+ }
111
+ else if (bSum <= blackSum && aSum >= contentSum) {
112
+ blackOnlyBPixels++;
113
+ if (x < bMinX)
114
+ bMinX = x;
115
+ if (y < bMinY)
116
+ bMinY = y;
117
+ if (x > bMaxX)
118
+ bMaxX = x;
119
+ if (y > bMaxY)
120
+ bMaxY = y;
121
+ }
122
+ }
123
+ }
124
+ return {
125
+ width: a.width,
126
+ height: a.height,
127
+ totalPixels: total,
128
+ diffPixels,
129
+ diffFraction: diffPixels / total,
130
+ blackOnlyInA: {
131
+ pixels: blackOnlyAPixels,
132
+ fraction: blackOnlyAPixels / total,
133
+ boundingBox: blackOnlyAPixels === 0
134
+ ? null
135
+ : { x: aMinX, y: aMinY, width: aMaxX - aMinX + 1, height: aMaxY - aMinY + 1 },
136
+ },
137
+ blackOnlyInB: {
138
+ pixels: blackOnlyBPixels,
139
+ fraction: blackOnlyBPixels / total,
140
+ boundingBox: blackOnlyBPixels === 0
141
+ ? null
142
+ : { x: bMinX, y: bMinY, width: bMaxX - bMinX + 1, height: bMaxY - bMinY + 1 },
143
+ },
144
+ };
145
+ }
146
+ /**
147
+ * PNG-buffer convenience wrapper around `diffGpuParityFrames`. Decodes
148
+ * both inputs via `decodePng` and delegates. Errors from the decoder are
149
+ * re-thrown with `cause` preserved so the failing side (A or B) is
150
+ * obvious in the stack.
151
+ */
152
+ export function diffGpuParityPngs(pngA, pngB, options = {}) {
153
+ let a;
154
+ let b;
155
+ try {
156
+ a = decodePng(pngA);
157
+ }
158
+ catch (err) {
159
+ throw new Error(`diffGpuParityPngs: failed to decode frame A`, { cause: err });
160
+ }
161
+ try {
162
+ b = decodePng(pngB);
163
+ }
164
+ catch (err) {
165
+ throw new Error(`diffGpuParityPngs: failed to decode frame B`, { cause: err });
166
+ }
167
+ return diffGpuParityFrames(a, b, options);
168
+ }
169
+ /**
170
+ * Verdict wrapper — returns `{ ok, reason }` suitable for a follow-up
171
+ * CLI or gate to emit. `ok === false` when either black-only fraction
172
+ * exceeds `blackOnlyFractionThreshold`. Raw diff numbers are always
173
+ * included on both branches so callers can log or gate on their own
174
+ * metrics without a second pass.
175
+ */
176
+ export function verifyGpuParity(a, b, options = {}) {
177
+ const diff = diffGpuParityFrames(a, b, options);
178
+ const threshold = options.blackOnlyFractionThreshold ?? DEFAULT_BLACK_ONLY_FRACTION_THRESHOLD;
179
+ if (diff.blackOnlyInA.fraction > threshold) {
180
+ const bb = diff.blackOnlyInA.boundingBox;
181
+ const region = bb ? ` (bbox ${bb.x},${bb.y} ${bb.width}x${bb.height})` : "";
182
+ return {
183
+ ok: false,
184
+ reason: `hardware-GPU frame has ${diff.blackOnlyInA.pixels} pixel(s) ` +
185
+ `(${(diff.blackOnlyInA.fraction * 100).toFixed(3)}%) that are solid-black ` +
186
+ `while software-GPU frame has content there${region} — likely shape-dependent ` +
187
+ `hardware-GPU capture bug`,
188
+ diff,
189
+ };
190
+ }
191
+ if (diff.blackOnlyInB.fraction > threshold) {
192
+ const bb = diff.blackOnlyInB.boundingBox;
193
+ const region = bb ? ` (bbox ${bb.x},${bb.y} ${bb.width}x${bb.height})` : "";
194
+ return {
195
+ ok: false,
196
+ reason: `software-GPU frame has ${diff.blackOnlyInB.pixels} pixel(s) ` +
197
+ `(${(diff.blackOnlyInB.fraction * 100).toFixed(3)}%) that are solid-black ` +
198
+ `while hardware-GPU frame has content there${region} — unexpected inverse ` +
199
+ `pattern, worth investigating`,
200
+ diff,
201
+ };
202
+ }
203
+ return { ok: true, reason: "", diff };
204
+ }
205
+ //# sourceMappingURL=gpuParityDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpuParityDiff.js","sourceRoot":"","sources":["../../src/utils/gpuParityDiff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { ChildProcess } from "node:child_process";
2
+ export type ManagedProcessTerminationReason = "exit" | "abort" | "deadline" | "inactivity" | "spawn_error";
3
+ export interface ManagedChildProcessOutcome {
4
+ reason: ManagedProcessTerminationReason;
5
+ exitCode: number | null;
6
+ signal: NodeJS.Signals | null;
7
+ stderr: string;
8
+ durationMs: number;
9
+ error?: Error;
10
+ }
11
+ export interface ManagedChildProcessOptions {
12
+ signal?: AbortSignal;
13
+ deadlineAtMs?: number;
14
+ inactivityTimeoutMs?: number;
15
+ terminationGraceMs?: number;
16
+ stderrMaxBytes?: number;
17
+ onStderr?: (chunk: string) => void;
18
+ now?: () => number;
19
+ }
20
+ /** Owns cancellation, escalation, stderr and reaping for one child process. */
21
+ export declare class ManagedChildProcess {
22
+ readonly child: ChildProcess;
23
+ private readonly options;
24
+ private readonly startedAtMs;
25
+ private readonly now;
26
+ private readonly outcomePromise;
27
+ private resolveOutcome;
28
+ private requestedReason;
29
+ private stderrTail;
30
+ private spawned;
31
+ private settled;
32
+ private deadlineTimer;
33
+ private inactivityTimer;
34
+ private escalationTimer;
35
+ constructor(child: ChildProcess, options?: ManagedChildProcessOptions);
36
+ wait(): Promise<ManagedChildProcessOutcome>;
37
+ get isSettled(): boolean;
38
+ markActivity(): void;
39
+ private readonly onStderr;
40
+ private readonly onSpawn;
41
+ private readonly onClose;
42
+ private readonly onError;
43
+ private installAbort;
44
+ private readonly onAbort;
45
+ private installDeadline;
46
+ private requestTermination;
47
+ private settle;
48
+ private clearTimers;
49
+ }
50
+ //# sourceMappingURL=managedChildProcess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managedChildProcess.d.ts","sourceRoot":"","sources":["../../src/utils/managedChildProcess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,+BAA+B,GACvC,MAAM,GACN,OAAO,GACP,UAAU,GACV,YAAY,GACZ,aAAa,CAAC;AAElB,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,+BAA+B,CAAC;IACxC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAKD,+EAA+E;AAC/E,qBAAa,mBAAmB;IAe5B,QAAQ,CAAC,KAAK,EAAE,YAAY;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAf1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsC;IACrE,OAAO,CAAC,cAAc,CAAiD;IACvE,OAAO,CAAC,eAAe,CAChB;IACP,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,eAAe,CAA+B;gBAG3C,KAAK,EAAE,YAAY,EACX,OAAO,GAAE,0BAA+B;IAiB3D,IAAI,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAI3C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,YAAY,IAAI,IAAI;IAUpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAQvB;IAEF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEtB;IAEF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAQtB;IAEF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAUtB;IAEF,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAEtB;IAEF,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,WAAW;CAQpB"}
@@ -0,0 +1,148 @@
1
+ const DEFAULT_TERMINATION_GRACE_MS = 2_000;
2
+ const DEFAULT_STDERR_MAX_BYTES = 64 * 1024;
3
+ /** Owns cancellation, escalation, stderr and reaping for one child process. */
4
+ export class ManagedChildProcess {
5
+ child;
6
+ options;
7
+ startedAtMs;
8
+ now;
9
+ outcomePromise;
10
+ resolveOutcome;
11
+ requestedReason = null;
12
+ stderrTail = Buffer.alloc(0);
13
+ spawned = false;
14
+ settled = false;
15
+ deadlineTimer = null;
16
+ inactivityTimer = null;
17
+ escalationTimer = null;
18
+ constructor(child, options = {}) {
19
+ this.child = child;
20
+ this.options = options;
21
+ this.now = options.now ?? Date.now;
22
+ this.startedAtMs = this.now();
23
+ this.outcomePromise = new Promise((resolve) => {
24
+ this.resolveOutcome = resolve;
25
+ });
26
+ child.stderr?.on("data", this.onStderr);
27
+ child.once("spawn", this.onSpawn);
28
+ child.once("close", this.onClose);
29
+ child.on("error", this.onError);
30
+ this.installAbort();
31
+ this.installDeadline();
32
+ this.markActivity();
33
+ }
34
+ wait() {
35
+ return this.outcomePromise;
36
+ }
37
+ get isSettled() {
38
+ return this.settled;
39
+ }
40
+ markActivity() {
41
+ if (this.settled || this.options.inactivityTimeoutMs === undefined)
42
+ return;
43
+ if (this.inactivityTimer)
44
+ clearTimeout(this.inactivityTimer);
45
+ this.inactivityTimer = setTimeout(() => this.requestTermination("inactivity"), Math.max(0, this.options.inactivityTimeoutMs));
46
+ this.inactivityTimer.unref?.();
47
+ }
48
+ onStderr = (data) => {
49
+ const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
50
+ const maxBytes = this.options.stderrMaxBytes ?? DEFAULT_STDERR_MAX_BYTES;
51
+ this.stderrTail = Buffer.concat([this.stderrTail, chunk]);
52
+ if (this.stderrTail.byteLength > maxBytes) {
53
+ this.stderrTail = this.stderrTail.subarray(this.stderrTail.byteLength - maxBytes);
54
+ }
55
+ this.options.onStderr?.(chunk.toString());
56
+ };
57
+ onSpawn = () => {
58
+ this.spawned = true;
59
+ };
60
+ onClose = (exitCode, signal) => {
61
+ this.settle({
62
+ reason: this.requestedReason ?? "exit",
63
+ exitCode,
64
+ signal,
65
+ stderr: this.stderrTail.toString(),
66
+ durationMs: this.now() - this.startedAtMs,
67
+ });
68
+ };
69
+ onError = (error) => {
70
+ if (this.spawned)
71
+ return;
72
+ this.settle({
73
+ reason: "spawn_error",
74
+ exitCode: null,
75
+ signal: null,
76
+ stderr: this.stderrTail.length > 0 ? this.stderrTail.toString() : error.message,
77
+ durationMs: this.now() - this.startedAtMs,
78
+ error,
79
+ });
80
+ };
81
+ installAbort() {
82
+ const signal = this.options.signal;
83
+ if (!signal)
84
+ return;
85
+ if (signal.aborted) {
86
+ this.requestTermination("abort");
87
+ return;
88
+ }
89
+ signal.addEventListener("abort", this.onAbort, { once: true });
90
+ }
91
+ onAbort = () => {
92
+ this.requestTermination("abort");
93
+ };
94
+ installDeadline() {
95
+ if (this.options.deadlineAtMs === undefined)
96
+ return;
97
+ const remainingMs = Math.max(0, this.options.deadlineAtMs - this.now());
98
+ this.deadlineTimer = setTimeout(() => this.requestTermination("deadline"), remainingMs);
99
+ this.deadlineTimer.unref?.();
100
+ }
101
+ requestTermination(reason) {
102
+ if (this.settled || this.requestedReason)
103
+ return;
104
+ this.requestedReason = reason;
105
+ try {
106
+ this.child.kill("SIGTERM");
107
+ }
108
+ catch {
109
+ // A close/error event owns settlement; escalation remains the backstop.
110
+ }
111
+ const graceMs = this.options.terminationGraceMs ?? DEFAULT_TERMINATION_GRACE_MS;
112
+ this.escalationTimer = setTimeout(() => {
113
+ if (this.settled)
114
+ return;
115
+ try {
116
+ this.child.kill("SIGKILL");
117
+ }
118
+ catch {
119
+ // The child may have exited between the settled check and kill.
120
+ }
121
+ }, Math.max(0, graceMs));
122
+ this.escalationTimer.unref?.();
123
+ }
124
+ settle(outcome) {
125
+ if (this.settled)
126
+ return;
127
+ this.settled = true;
128
+ this.clearTimers();
129
+ this.options.signal?.removeEventListener("abort", this.onAbort);
130
+ this.child.stderr?.off("data", this.onStderr);
131
+ this.child.off("spawn", this.onSpawn);
132
+ this.child.off("close", this.onClose);
133
+ this.child.off("error", this.onError);
134
+ this.resolveOutcome(outcome);
135
+ }
136
+ clearTimers() {
137
+ if (this.deadlineTimer)
138
+ clearTimeout(this.deadlineTimer);
139
+ if (this.inactivityTimer)
140
+ clearTimeout(this.inactivityTimer);
141
+ if (this.escalationTimer)
142
+ clearTimeout(this.escalationTimer);
143
+ this.deadlineTimer = null;
144
+ this.inactivityTimer = null;
145
+ this.escalationTimer = null;
146
+ }
147
+ }
148
+ //# sourceMappingURL=managedChildProcess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managedChildProcess.js","sourceRoot":"","sources":["../../src/utils/managedChildProcess.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ export function trackChildProcess(proc) {
3
3
  tracked.add(proc);
4
4
  const remove = () => tracked.delete(proc);
5
5
  proc.once("exit", remove);
6
- proc.once("error", remove);
6
+ proc.once("close", remove);
7
7
  }
8
8
  /**
9
9
  * SIGTERM all tracked child processes, then SIGKILL any that survive
@@ -4,6 +4,7 @@
4
4
  * Extracts the repeated spawn-stderr-timeout-abort-close-error pattern
5
5
  * that appears across audioMixer and chunkEncoder into a single helper.
6
6
  */
7
+ import { type ManagedProcessTerminationReason } from "./managedChildProcess.js";
7
8
  export interface RunFfmpegOptions {
8
9
  signal?: AbortSignal;
9
10
  timeout?: number;
@@ -14,6 +15,8 @@ export interface RunFfmpegResult {
14
15
  exitCode: number | null;
15
16
  stderr: string;
16
17
  durationMs: number;
18
+ terminationReason: ManagedProcessTerminationReason;
19
+ error?: Error;
17
20
  }
18
21
  /**
19
22
  * Build a user-facing error message for a failed ffmpeg invocation.
@@ -1 +1 @@
1
- {"version":3,"file":"runFfmpeg.d.ts","sourceRoot":"","sources":["../../src/utils/runFfmpeg.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAkC,GAC5C,MAAM,CAgBR;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAyDjG"}
1
+ {"version":3,"file":"runFfmpeg.d.ts","sourceRoot":"","sources":["../../src/utils/runFfmpeg.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAKH,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,+BAA+B,CAAC;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AA+BD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAkC,GAC5C,MAAM,CAgBR;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBjG"}
@@ -8,6 +8,7 @@
8
8
  import { spawn } from "child_process";
9
9
  import { getFfmpegBinary } from "./ffmpegBinaries.js";
10
10
  import { trackChildProcess } from "./processTracker.js";
11
+ import { ManagedChildProcess, } from "./managedChildProcess.js";
11
12
  const DEFAULT_TIMEOUT = 300_000;
12
13
  const DEFAULT_STDERR_TAIL_LINES = 15;
13
14
  function formatWindowsFfmpegExit(exitCode) {
@@ -57,57 +58,22 @@ export function formatFfmpegError(exitCode, stderr, tailLines = DEFAULT_STDERR_T
57
58
  : `FFmpeg exited with code ${exitCode}`;
58
59
  }
59
60
  export async function runFfmpeg(args, opts) {
60
- const startMs = Date.now();
61
- const signal = opts?.signal;
62
61
  const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
63
- const onStderr = opts?.onStderr;
64
- return new Promise((resolve) => {
65
- const ffmpeg = spawn(getFfmpegBinary(), args);
66
- trackChildProcess(ffmpeg);
67
- let stderr = "";
68
- const onAbort = () => {
69
- ffmpeg.kill("SIGTERM");
70
- };
71
- if (signal) {
72
- if (signal.aborted) {
73
- ffmpeg.kill("SIGTERM");
74
- }
75
- else {
76
- signal.addEventListener("abort", onAbort, { once: true });
77
- }
78
- }
79
- const timer = setTimeout(() => {
80
- ffmpeg.kill("SIGTERM");
81
- }, timeout);
82
- ffmpeg.stderr.on("data", (data) => {
83
- const chunk = data.toString();
84
- stderr += chunk;
85
- if (onStderr) {
86
- onStderr(chunk);
87
- }
88
- });
89
- ffmpeg.on("close", (code) => {
90
- clearTimeout(timer);
91
- if (signal)
92
- signal.removeEventListener("abort", onAbort);
93
- resolve({
94
- success: !signal?.aborted && code === 0,
95
- exitCode: code,
96
- stderr,
97
- durationMs: Date.now() - startMs,
98
- });
99
- });
100
- ffmpeg.on("error", (err) => {
101
- clearTimeout(timer);
102
- if (signal)
103
- signal.removeEventListener("abort", onAbort);
104
- resolve({
105
- success: false,
106
- exitCode: null,
107
- stderr: err.message,
108
- durationMs: Date.now() - startMs,
109
- });
110
- });
62
+ const ffmpeg = spawn(getFfmpegBinary(), args);
63
+ trackChildProcess(ffmpeg);
64
+ const managed = new ManagedChildProcess(ffmpeg, {
65
+ signal: opts?.signal,
66
+ deadlineAtMs: Date.now() + timeout,
67
+ onStderr: opts?.onStderr,
111
68
  });
69
+ const outcome = await managed.wait();
70
+ return {
71
+ success: outcome.reason === "exit" && outcome.exitCode === 0,
72
+ exitCode: outcome.exitCode,
73
+ stderr: outcome.stderr,
74
+ durationMs: outcome.durationMs,
75
+ terminationReason: outcome.reason,
76
+ error: outcome.error,
77
+ };
112
78
  }
113
79
  //# sourceMappingURL=runFfmpeg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runFfmpeg.js","sourceRoot":"","sources":["../../src/utils/runFfmpeg.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runFfmpeg.js","sourceRoot":"","sources":["../../src/utils/runFfmpeg.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/engine",
3
- "version": "0.7.59",
3
+ "version": "0.7.61",
4
4
  "description": "Seekable web page to video rendering engine (Puppeteer + FFmpeg)",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,7 +38,8 @@
38
38
  "linkedom": "^0.18.12",
39
39
  "puppeteer": "^25.2.1",
40
40
  "puppeteer-core": "^25.2.1",
41
- "@hyperframes/core": "^0.7.59"
41
+ "@hyperframes/core": "^0.7.61",
42
+ "@hyperframes/parsers": "^0.7.61"
42
43
  },
43
44
  "devDependencies": {
44
45
  "@types/node": "^25.0.10",