mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(core): address staff review — diagnostics, comments, test coverage
- Add onActivation callback to MediaPreloadManager; wired to postRuntimeDiagnosticOnce in init.ts for observability - Document LAZY_THRESHOLD rationale (why 6) and MAX_PROMOTED defense-in-depth semantics - Add render-mode bypass contract test (isLazy with exactly 6 clips) - Add onActivation tests: fires once on lazy activation, skips below threshold, deduplicates across refreshes
This commit is contained in:
@@ -1224,7 +1224,11 @@ export function initSandboxRuntimeModular(): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isRenderMode = Boolean((window as Record<string, unknown>).__HF_EXPORT_RENDER_SEEK_CONFIG);
|
const isRenderMode = Boolean((window as Record<string, unknown>).__HF_EXPORT_RENDER_SEEK_CONFIG);
|
||||||
const mediaPreloader = createMediaPreloadManager();
|
const mediaPreloader = createMediaPreloadManager({
|
||||||
|
onActivation: (clipCount) => {
|
||||||
|
postRuntimeDiagnosticOnce("lazy_preload_activated", { clipCount }, "lazy_preload_activated");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const bindMediaMetadataListeners = () => {
|
const bindMediaMetadataListeners = () => {
|
||||||
if (state.tornDown) return;
|
if (state.tornDown) return;
|
||||||
|
|||||||
@@ -268,4 +268,58 @@ describe("createMediaPreloadManager", () => {
|
|||||||
const loadCallsAfter = (elements[0].load as ReturnType<typeof vi.fn>).mock.calls.length;
|
const loadCallsAfter = (elements[0].load as ReturnType<typeof vi.fn>).mock.calls.length;
|
||||||
expect(loadCallsAfter).toBeGreaterThan(loadCallsBefore);
|
expect(loadCallsAfter).toBeGreaterThan(loadCallsBefore);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("isLazy reports true with 6+ clips so caller can gate render-mode bypass", () => {
|
||||||
|
elements = Array.from({ length: 6 }, (_, i) =>
|
||||||
|
mockMediaElement({ start: String(i * 5), duration: "5" }),
|
||||||
|
);
|
||||||
|
setupDOM(elements);
|
||||||
|
|
||||||
|
const manager = createMediaPreloadManager();
|
||||||
|
manager.refresh();
|
||||||
|
expect(manager.isLazy()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls onActivation when lazy mode activates", () => {
|
||||||
|
elements = Array.from({ length: 8 }, (_, i) =>
|
||||||
|
mockMediaElement({ start: String(i * 5), duration: "5" }),
|
||||||
|
);
|
||||||
|
setupDOM(elements);
|
||||||
|
|
||||||
|
const onActivation = vi.fn();
|
||||||
|
const manager = createMediaPreloadManager({ onActivation });
|
||||||
|
manager.refresh();
|
||||||
|
|
||||||
|
expect(onActivation).toHaveBeenCalledOnce();
|
||||||
|
expect(onActivation).toHaveBeenCalledWith(8);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not call onActivation below threshold", () => {
|
||||||
|
elements = [
|
||||||
|
mockMediaElement({ start: "0", duration: "5" }),
|
||||||
|
mockMediaElement({ start: "5", duration: "5" }),
|
||||||
|
];
|
||||||
|
setupDOM(elements);
|
||||||
|
|
||||||
|
const onActivation = vi.fn();
|
||||||
|
const manager = createMediaPreloadManager({ onActivation });
|
||||||
|
manager.refresh();
|
||||||
|
|
||||||
|
expect(onActivation).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls onActivation only once across multiple refreshes", () => {
|
||||||
|
elements = Array.from({ length: 8 }, (_, i) =>
|
||||||
|
mockMediaElement({ start: String(i * 5), duration: "5" }),
|
||||||
|
);
|
||||||
|
setupDOM(elements);
|
||||||
|
|
||||||
|
const onActivation = vi.fn();
|
||||||
|
const manager = createMediaPreloadManager({ onActivation });
|
||||||
|
manager.refresh();
|
||||||
|
manager.refresh();
|
||||||
|
manager.refresh();
|
||||||
|
|
||||||
|
expect(onActivation).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
import { refreshRuntimeMediaCache, type RuntimeMediaClip } from "./media";
|
import { refreshRuntimeMediaCache, type RuntimeMediaClip } from "./media";
|
||||||
|
|
||||||
|
// Compositions with fewer than 6 timed clips rarely exceed browser memory
|
||||||
|
// limits during eager preload. The threshold avoids preload management
|
||||||
|
// overhead for typical compositions while catching the heavy-media case
|
||||||
|
// (e.g., 20 clips / 6GB reported in heygen-com/hyperframes#729).
|
||||||
const LAZY_THRESHOLD = 6;
|
const LAZY_THRESHOLD = 6;
|
||||||
const LOOKAHEAD_SECONDS = 10;
|
const LOOKAHEAD_SECONDS = 10;
|
||||||
const LOOKAHEAD_MIN_CLIPS = 2;
|
const LOOKAHEAD_MIN_CLIPS = 2;
|
||||||
|
// Cap on simultaneously promoted (buffered) clips. When the lookahead window
|
||||||
|
// contains more clips than this (e.g., many short clips), all window clips
|
||||||
|
// stay promoted — the cap is defense-in-depth, not a hard ceiling. The primary
|
||||||
|
// memory bound comes from window-based eviction in syncWindow().
|
||||||
const MAX_PROMOTED = 5;
|
const MAX_PROMOTED = 5;
|
||||||
|
|
||||||
export interface MediaPreloadManager {
|
export interface MediaPreloadManager {
|
||||||
@@ -16,6 +24,7 @@ export function createMediaPreloadManager(options?: {
|
|||||||
resolveStartSeconds?: (element: Element) => number;
|
resolveStartSeconds?: (element: Element) => number;
|
||||||
resolveDurationSeconds?: (element: HTMLVideoElement | HTMLAudioElement) => number | null;
|
resolveDurationSeconds?: (element: HTMLVideoElement | HTMLAudioElement) => number | null;
|
||||||
shouldIncludeElement?: (element: HTMLVideoElement | HTMLAudioElement) => boolean;
|
shouldIncludeElement?: (element: HTMLVideoElement | HTMLAudioElement) => boolean;
|
||||||
|
onActivation?: (clipCount: number) => void;
|
||||||
}): MediaPreloadManager {
|
}): MediaPreloadManager {
|
||||||
let clips: RuntimeMediaClip[] = [];
|
let clips: RuntimeMediaClip[] = [];
|
||||||
const promoted = new Set<HTMLMediaElement>();
|
const promoted = new Set<HTMLMediaElement>();
|
||||||
@@ -24,11 +33,16 @@ export function createMediaPreloadManager(options?: {
|
|||||||
/** Stashed original src so we can restore after eviction. */
|
/** Stashed original src so we can restore after eviction. */
|
||||||
const originalSrc = new Map<HTMLMediaElement, string>();
|
const originalSrc = new Map<HTMLMediaElement, string>();
|
||||||
let lazy = false;
|
let lazy = false;
|
||||||
|
let activationEmitted = false;
|
||||||
|
|
||||||
function refresh(): void {
|
function refresh(): void {
|
||||||
const cache = refreshRuntimeMediaCache(options);
|
const cache = refreshRuntimeMediaCache(options);
|
||||||
clips = cache.mediaClips;
|
clips = cache.mediaClips;
|
||||||
lazy = clips.length >= LAZY_THRESHOLD;
|
lazy = clips.length >= LAZY_THRESHOLD;
|
||||||
|
if (lazy && !activationEmitted) {
|
||||||
|
activationEmitted = true;
|
||||||
|
options?.onActivation?.(clips.length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function evictClip(clip: RuntimeMediaClip): void {
|
function evictClip(clip: RuntimeMediaClip): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user