fix(frontend): prefer WebSocket for flow round-trip when wmill dev is connected

updateFlow used isInIframe priority, which routed Claude Code's iframe
preview through postMessage (no listener) and silently dropped flow
edits. Flip the priority: when the wmill dev WebSocket is open, use it
(covers standalone tabs and Claude Code's preview); fall back to
postMessage only when no WS is connected (the VS Code extension's iframe
URL has no `local=true`, so it never opens one). Also stop assigning
lastSent before a channel actually accepted the message, so a CONNECTING
WS doesn't silently swallow the first change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Guilhem Lemouel
2026-04-23 12:59:49 +02:00
co-authored by Claude Opus 4.7
parent 3c2d5155e1
commit 7afd8846ca
+16 -9
View File
@@ -596,16 +596,23 @@
if (lockChanges) {
return
}
if (!deepEqual(flow, lastSent)) {
lastSent = $state.snapshot(flow)
if (isInIframe) {
// VS Code extension: round-trip via postMessage
window?.parent.postMessage({ type: 'flow', flow: lastSent, uriPath: lastUriPath }, '*')
} else if (socket && socket.readyState === WebSocket.OPEN) {
// CLI dev mode: round-trip via WebSocket
socket.send(JSON.stringify({ type: 'flow', flow: lastSent, uriPath: lastUriPath }))
}
if (deepEqual(flow, lastSent)) {
return
}
const snapshot = $state.snapshot(flow)
// Prefer the WebSocket whenever a `wmill dev` session is connected — this covers
// both standalone browser tabs and Claude Code's iframe preview. The VS Code
// extension never opens this socket (its iframe URL omits `local=true`), so it
// falls through to the postMessage path it has always used.
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'flow', flow: snapshot, uriPath: lastUriPath }))
lastSent = snapshot
} else if (isInIframe) {
window?.parent.postMessage({ type: 'flow', flow: snapshot, uriPath: lastUriPath }, '*')
lastSent = snapshot
}
// Else: no channel available yet (WS still connecting, not in an iframe).
// Don't mark `lastSent` so the next change will retry instead of being silently swallowed.
}
let reload = $state(0)