fix: revert flattenInnerRoot, use host-level authored-id + count-based rebind

Three changes to fix regression failures without breaking baselines:

1. Revert flattenInnerRoot in producer — use the original innerHTML
   inlining that preserves the existing DOM structure. Instead, set
   data-hf-authored-id on the HOST element so the scoped proxy can
   still rewrite #id selectors for sub-composition scripts.

2. Revert compiled.html baselines to main (no DOM structure changes).

3. Use timeline-count comparison instead of poll duration to decide
   whether to call __hfForceTimelineRebind. Compare timeline count
   before vs after the poll — rebind only when new timelines appeared
   during polling. This correctly identifies async compositions
   regardless of fetch speed, while leaving sync compositions
   untouched.
This commit is contained in:
Miguel Ángel
2026-05-18 10:20:17 -04:00
parent 0ff6296d64
commit 4bf2fa5cd1
4 changed files with 119 additions and 1806 deletions
+7 -3
View File
@@ -365,10 +365,14 @@ async function pollSubCompositionTimelines(
} }
return true; return true;
})()`; })()`;
const beforePoll = Date.now(); const timelinesBeforePoll = Number(
await page.evaluate(`Object.keys(window.__timelines || {}).length`),
);
const ready = await pollPageExpression(page, expression, timeoutMs, intervalMs); const ready = await pollPageExpression(page, expression, timeoutMs, intervalMs);
const pollDurationMs = Date.now() - beforePoll; const timelinesAfterPoll = Number(
if (ready && pollDurationMs > intervalMs * 2) { await page.evaluate(`Object.keys(window.__timelines || {}).length`),
);
if (ready && timelinesAfterPoll > timelinesBeforePoll) {
await page.evaluate(`(function() { await page.evaluate(`(function() {
if (typeof window.__hfForceTimelineRebind === "function") { if (typeof window.__hfForceTimelineRebind === "function") {
window.__hfForceTimelineRebind(); window.__hfForceTimelineRebind();
+13 -5
View File
@@ -21,10 +21,7 @@ import {
type ResolvedDuration, type ResolvedDuration,
type UnresolvedElement, type UnresolvedElement,
} from "@hyperframes/core"; } from "@hyperframes/core";
import { import { inlineSubCompositions as inlineSubCompositionsShared } from "@hyperframes/core/compiler";
inlineSubCompositions as inlineSubCompositionsShared,
prepareFlattenedInnerRoot,
} from "@hyperframes/core/compiler";
import { extractMediaMetadata, extractAudioMetadata } from "../utils/ffprobe.js"; import { extractMediaMetadata, extractAudioMetadata } from "../utils/ffprobe.js";
import { isPathInside, toExternalAssetKey } from "../utils/paths.js"; import { isPathInside, toExternalAssetKey } from "../utils/paths.js";
import { import {
@@ -577,11 +574,22 @@ function inlineSubCompositions(
return compHtml; return compHtml;
}, },
parseHtml: (htmlStr: string) => parseHTML(htmlStr).document as unknown as Document, parseHtml: (htmlStr: string) => parseHTML(htmlStr).document as unknown as Document,
flattenInnerRoot: prepareFlattenedInnerRoot as (innerRoot: Element) => Element,
scriptErrorLabel: "[Compiler] Composition script failed", scriptErrorLabel: "[Compiler] Composition script failed",
}, },
); );
// Set data-hf-authored-id on host elements so the scoped script proxy
// can rewrite #id selectors (e.g. #us-map → [data-hf-authored-id="us-map"]).
// Unlike flattenInnerRoot (which changes DOM structure and breaks baselines),
// this preserves the existing innerHTML-based inlining while enabling the
// authored-id selector contract.
for (const hostEl of hosts) {
const compId = hostEl.getAttribute("data-composition-id");
if (compId && !hostEl.getAttribute("data-hf-authored-id")) {
hostEl.setAttribute("data-hf-authored-id", compId);
}
}
// Producer-specific: set explicit pixel dimensions on host elements so // Producer-specific: set explicit pixel dimensions on host elements so
// children using width/height: 100% resolve correctly. The runtime does // children using width/height: 100% resolve correctly. The runtime does
// this automatically but compiled HTML needs it inline. // this automatically but compiled HTML needs it inline.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long