fix(sdk): attachSync re-syncs the override snapshot on iframe load#2500
Conversation
miga-heygen
left a comment
There was a problem hiding this comment.
Review — #2500 fix(sdk): attachSync re-syncs the override snapshot on iframe load
Verdict: LGTM
SSOT check
Single syncOverrides function for both initial and load-time sync. The load listener is correctly added to the iframe element (not the document) and removed on detach. The try/catch with console.warn correctly prevents a failed sync from breaking the ongoing patch subscription.
The race condition this fixes is well-documented: srcdoc assignment is async, so an attachSync call in the same tick snapshots the outgoing document. Patches committed during the load window mirror into the dying document. Re-syncing on load converges the new document.
Tests: 2 cases — override re-applied after load, no re-sync after detach. No blockers.
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Reviewed at 4682da14. Layering on Miga's LGTM.
Blockers
(none)
Concerns
(none)
Nits
(none)
Green notes
🟢 Race characterization is precise. srcdoc/src assignment fires the navigation asynchronously; an attachSync in the same tick captures the OUTGOING document. Patches committed during the load window mirror into a document that's about to be torn down. Re-syncing on load converges the new document with the composition state regardless of attach/navigation ordering — captured cleanly in the docstring comment on line 771-775.
🟢 Listener lifecycle is symmetric. addEventListener("load", syncOverrides) on attach, removeEventListener("load", syncOverrides) on detach — same closure reference so the removal actually takes. Re-attaching via attachSync in the same session first invokes this._syncDetach?.() (line 753), which removes the previous listener + patch subscription, THEN a new syncOverrides closure is created and installed — no listener leak on repeated attach.
🟢 applyOverrideSet is idempotent on repeat loads. Firing load multiple times with the same override set re-establishes the same live-DOM state each time, so the "srcdoc reset mid-edit" path (where the iframe fires load twice without navigation) doesn't accumulate stale writes.
🟢 try/catch around each syncOverrides call is scoped correctly. A bad override snapshot no longer prevents the patch subscription from attaching, and now doesn't prevent the load-driven re-sync from continuing to run either — errors are per-call, not per-attach. Warn message updated from "initial override sync failed" → "override sync failed" reflects that.
🟢 Detach test is genuine. expect(liveTitle.style.getPropertyValue("color")).toBe("#fff") — post-detach, load fires, and the composition's #f00 override is NOT re-applied. Would fail against a naive fix that forgot the removeEventListener call.
Verdict framing
Clean fix for a real navigation race. LGTM from my side.

Summary
Part 2/4 of the SDK gap-closure stack. Makes
IframePreviewAdapter.attachSyncreapply the composition override snapshot whenever the iframe firesload.Why
srcdocandsrcassignments navigate asynchronously. An attach or patch can target the outgoing document and be lost when the new document arrives.Implementation
loadevent.Validation
src/adapters/iframe.sync.test.ts: 15 tests passing, including load re-sync and detach coverage.