Skip to content

fix(client): don't close a connected embed bridge on a late iframe load - #11

Open
fishOfOUC wants to merge 1 commit into
imsai-sh:mainfrom
fishOfOUC:fix/embed-bridge-late-load
Open

fix(client): don't close a connected embed bridge on a late iframe load#11
fishOfOUC wants to merge 1 commit into
imsai-sh:mainfrom
fishOfOUC:fix/embed-bridge-late-load

Conversation

@fishOfOUC

Copy link
Copy Markdown

What breaks

With dsh1024 0.5.0 in a web profile, opening the store (sidebar entry, or 设置 → 1024 Store) shows the embedded store for a moment and then replaces it with 「商店页面未能加载 / 可以重试、在系统浏览器打开主站,或检查本地壳更新。」 (or the English equivalent).

The bridge is actually fine: it connects, and then gets torn down by a later event.

Root cause

plugin/client/client.js:

const frameLoaded = useCallback(() => {
  closeBridge()
  setConnection('connecting')
  readyTimerRef.current = window.setTimeout(() => setConnection('failed'), READY_TIMEOUT_MS)
}, [closeBridge])

The embedded page posts { type: 'init' } exactly once per document (from a useEffect on mount), and the parent only calls connectFrame() from that message. frameLoaded runs on the iframe's load event and unconditionally closes the live MessagePort and starts the 5s readiness timer.

load waits for every subresource, while the SPA mounts before that finishes. So whenever a subresource is slow or blocked — a browser extension blocking or delaying a third-party request is enough — load lands after the handshake. The port is then closed, no second init ever arrives, and connection flips to 'failed' 5s later. The store was working the whole time; only the panel state is wrong.

Evidence

CDP instrumentation of both the GUI page and the embed document (it runs as an out-of-process iframe, so both were attached), same machine, dsh1024 0.5.0, dsh web on http://127.0.0.1:3081, Chrome 148 with AdGuard AdBlocker loaded (which delays some embed subresources):

frame-created   810706
init   (in)     811225   <- embed posted init
connect(in)     811991   <- child received the port
ready  (out)    811991   <- bridge established
frame-load      812298   <- 307 ms AFTER ready -> closeBridge() + 5 s timer
~817300                  <- connection = 'failed', error face replaces the store

Without extensions the race usually goes the other way (load first), which is why this is environment-dependent and not reported more widely.

Fix

Ignore load while a bridge port is already live. The port is still closed on an explicit reload (reloadFrame), on unmount (useEffect(() => closeBridge, ...)), and by connectFrame() itself before it opens a new one, so every other path keeps its current behavior.

Verified end-to-end against a dsh web server serving this patched bundle, in the same extension-loaded browser that reproduces the bug: frame-load still lands ~200 ms after ready, and the panel stays on the store for the whole observation window with no fallback.

Checks run in this branch:

  • npm test --workspace dsh1024 → 41/41 pass (includes scripts/preflight.mjspreflight ok: dsh1024@0.5.0)

Notes

  • plugin/client/client.js is the committed artifact for the client half; nothing in this repository generates it, so the change is made there directly. If it is built from a source outside the repository, happy to move the change upstream of the build instead.
  • No unit harness covers the client bundle, so the verification is the end-to-end one above. Glad to add whatever check you would prefer.

中文摘要:嵌入页每个文档只发一次 init,父页只在收到 initconnectFrame();而 frameLoaded() 在 iframe 的 load 事件里无条件 closeBridge() 并重启 5 秒计时器。当 load 晚于握手完成(子资源被扩展拦截或加载慢时就会如此),桥接被拆掉且无法重建,5 秒后就用「商店页面未能加载」盖住一个本来正常的商店。修复:已有活端口时忽略 load

The embed page posts `init` once per document and the parent only calls
connectFrame() from that message, but frameLoaded() unconditionally closed
the live port and restarted the readiness timer on every iframe `load`
event. When `load` lands after the handshake — any slow or blocked
subresource delays it past the SPA mount — the bridge is closed with no way
to re-establish it, and the panel replaces a working store with its error
face 5s later.

Ignore `load` while a bridge port is live. Explicit reload, unmount, and
connectFrame() itself still close the port.
@fishOfOUC
fishOfOUC requested a review from imsai-sh as a code owner September 8, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant