fix(scenes): hold host commands until the ready handshake - #40
Conversation
A freshly created iframe holds an about:blank document that inherits the
embedding page's origin until the host document loads. Posting a command
at the host origin before then is refused by the browser ("The target
origin provided does not match the recipient window's origin") and lands
as a console error on every cross-origin embed: ScenesPlayer's mount-time
setSceneTheme fires microseconds after the Player mounts the iframe.
Gate send() on the kino:ready handshake, which is the earliest point the
host is both on its own origin and listening. Nothing is lost, since the
pre-ready rate, volume, muted and theme all ride the kino:init reply. The
picture-in-picture mirror is about:blank on the pip window's origin under
the same rule, so sendMirror() gates on the mirror's own handshake.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
kino | 6206cc1 | Commit Preview URL Branch Preview URL |
Jul 24 2026, 09:53 PM |
📝 WalkthroughWalkthroughScenes messaging now waits for ChangesScenes readiness gating
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ScenesProvider
participant HostIframe
participant PipMirror
HostIframe->>ScenesProvider: kino:ready
ScenesProvider->>HostIframe: kino:init with current settings
PipMirror->>ScenesProvider: kino:ready
ScenesProvider->>PipMirror: kino:init with current mirror state
ScenesProvider->>HostIframe: Send transport or scene command
ScenesProvider->>PipMirror: Send mirrored command
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/scenes/provider.ts (1)
173-183: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winSend
kino:initbefore notifying subscribers.Line 175 synchronously emits to subscribers while
readyis already true. A subscriber that invokes an action can post a control command beforekino:init; the later init may then override that command (for example,autoPlay). Send the init reply beforepatch({ duration }).Proposed fix
case "kino:ready": ready = true - patch({ duration: msg.duration }) send({ type: "kino:init", rate: desiredRate, volume: state.volume, muted: state.muted, autoPlay: opts.autoPlay ?? false, theme, }) + patch({ duration: msg.duration }) break🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/scenes/provider.ts` around lines 173 - 183, In the initialization flow, move the kino:init send() call before patch({ duration }) so subscribers are notified only after the initialization reply has been emitted. Preserve ready = true before send(), and keep the existing init payload unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/scenes/provider.ts`:
- Around line 173-183: In the initialization flow, move the kino:init send()
call before patch({ duration }) so subscribers are notified only after the
initialization reply has been emitted. Preserve ready = true before send(), and
keep the existing init payload unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1a346907-630b-4407-b712-924d114f97e0
📒 Files selected for processing (3)
.changeset/scenes-post-before-host-ready.mdsrc/scenes/provider.test.tssrc/scenes/provider.ts
Fixes the console error reported in karnstack/karnstack#153:
Root cause
The failing direction is parent to host, not host to parent as the issue guessed (the scene host posts with
parentOrigin: "*", which never mismatches).A freshly created iframe holds an about:blank document that inherits the embedding page's origin until the real host document loads.
send()targets the host origin resolved fromsrc, so any command posted in that window is refused by the browser and surfaces as a console error.ScenesPlayerhits this on every cross-origin embed: React runs child effects first, soPlayermounts the iframe and thenScenesPlayerInner'ssceneThemeeffect immediately posts akino:setThemeinto a frame that is still about:blank.Fix
Gate
send()on thekino:readyhandshake, the earliest point at which the host is both on its own origin and listening (before then a delivered message would be dropped anyway, since the host has not attached its listener). Nothing is lost: the pre-ready rate, volume, muted and theme all ride thekino:initreply.The picture-in-picture mirror is about:blank on the pip window's origin under the same rule, so
sendMirror()gates on the mirror's own handshake, reset when a mirror is created and when pip closes.Tests
Two new cases pin the invariant for the master and the mirror, including that pre-ready settings still arrive via
kino:init. Three existing tests posted commands without the handshake (encoding the buggy behavior) and now perform it first. Full suite: 212 passing, typecheck and lint clean.Summary by CodeRabbit