fix(core): enforce strict runtime safety

This commit is contained in:
James
2026-07-11 21:31:30 -07:00
parent ebbd1eb2c2
commit 0af07a07c5
24 changed files with 348 additions and 116 deletions
+31 -26
View File
@@ -44,6 +44,7 @@ import type {
} from "./types";
import type { PlayerAPI } from "../core.types";
import { swallow } from "./diagnostics";
import { shouldAttemptPeriodicTimelineBind } from "./timelineRebindPolicy";
const AUTHORED_DURATION_ATTR = "data-hf-authored-duration";
const AUTHORED_END_ATTR = "data-hf-authored-end";
@@ -186,7 +187,7 @@ export function initSandboxRuntimeModular(): void {
} else {
for (let i = 0; i < arr.length; i++) normalized[`tl-${i}`] = arr[i];
}
(window as Record<string, unknown>).__timelines = normalized;
(window as unknown as Record<string, unknown>).__timelines = normalized;
}
// Agents sometimes omit data-start on the root composition element. The
@@ -295,7 +296,6 @@ export function initSandboxRuntimeModular(): void {
const MIN_VALID_TIMELINE_DURATION_SECONDS = 1 / 60;
const TIMELINE_FLOOR_COVERAGE_RATIO = 0.75;
const PLAY_REBIND_HOLD_SECONDS = 2;
const METADATA_REBIND_MIN_DURATION_GAIN_SECONDS = 0.05;
const METADATA_REBIND_DEBOUNCE_MS = 100;
const MAX_DIAGNOSTIC_MESSAGE_LENGTH = 240;
@@ -776,7 +776,9 @@ export function initSandboxRuntimeModular(): void {
!!entry[1] && typeof entry[1].play === "function" && typeof entry[1].pause === "function",
);
if (usable.length !== 1) return { timeline: null };
const [soleId, soleTimeline] = usable[0];
const sole = usable[0];
if (!sole) return { timeline: null };
const [soleId, soleTimeline] = sole;
return {
timeline: soleTimeline,
selectedTimelineIds: [soleId],
@@ -1223,7 +1225,7 @@ export function initSandboxRuntimeModular(): void {
// reapplyPositionEditsAfterSeek to un-bake it. Call the apply hook
// directly here as well, since the wrapper may not be installed yet
// during initial rebind (timing race on first load / soft reload).
const applyFn = (window as Record<string, unknown>).__hfStudioManualEditsApply;
const applyFn = (window as unknown as Record<string, unknown>).__hfStudioManualEditsApply;
if (typeof applyFn === "function") applyFn();
// SDK moveElement edits (data-hf-edit-base-x/y markers) render as a
@@ -1996,8 +1998,10 @@ export function initSandboxRuntimeModular(): void {
// handler. Identity is stable as long as the inputs are stable (each
// adapter is expected to return the same promise on repeat calls while
// its work is in flight).
const firstPromise = promises[0];
if (!firstPromise) return true;
const combined: PromiseLike<unknown> =
promises.length === 1 ? promises[0] : Promise.all(promises);
promises.length === 1 ? firstPromise : Promise.all(promises);
if (combined !== trackedAdapterReadyPromise) {
trackedAdapterReadyPromise = combined;
trackedAdapterReadySettled = false;
@@ -2512,10 +2516,10 @@ export function initSandboxRuntimeModular(): void {
}
for (const child of children) {
if (!isObjectRecord(child) || !isObjectRecord(child.vars)) continue;
const hasCallback = GSAP_CALLBACK_NAMES.some(
(name) => typeof child.vars[name] === "function",
);
if (!isObjectRecord(child)) continue;
const vars = child.vars;
if (!isObjectRecord(vars)) continue;
const hasCallback = GSAP_CALLBACK_NAMES.some((name) => typeof vars[name] === "function");
if (!hasCallback) continue;
const totalDuration = readGsapDuration(child, "totalDuration");
@@ -2629,24 +2633,25 @@ export function initSandboxRuntimeModular(): void {
transportTickCount += 1;
// Slower operations: timeline binding (~every 60 frames / ~1s at 60fps)
if (transportTickCount % 60 === 0) {
const shouldHoldRebind =
clock.isPlaying() &&
state.capturedTimeline != null &&
clock.now() < PLAY_REBIND_HOLD_SECONDS;
if (!shouldHoldRebind) {
const prevTimeline = state.capturedTimeline;
if (bindRootTimelineIfAvailable()) {
if (state.capturedTimeline && !player._timeline) {
player._timeline = state.capturedTimeline;
}
if (state.capturedTimeline && state.capturedTimeline !== prevTimeline) {
state.capturedTimeline.pause();
}
const dur = getSafeTimelineDurationSeconds(state.capturedTimeline, 0);
if (dur > 0) clock.setDuration(dur);
postTimeline();
if (
shouldAttemptPeriodicTimelineBind({
tick: transportTickCount,
isPlaying: clock.isPlaying(),
hasCapturedTimeline: state.capturedTimeline != null,
currentTimeSeconds: clock.now(),
})
) {
const prevTimeline = state.capturedTimeline;
if (bindRootTimelineIfAvailable()) {
if (state.capturedTimeline && !player._timeline) {
player._timeline = state.capturedTimeline;
}
if (state.capturedTimeline && state.capturedTimeline !== prevTimeline) {
state.capturedTimeline.pause();
}
const dur = getSafeTimelineDurationSeconds(state.capturedTimeline, 0);
if (dur > 0) clock.setDuration(dur);
postTimeline();
}
}
if (transportTickCount % 20 === 0) {