Skip to content

fix: pass the connection's owner Peer to every Host stream and RPC (dsh 0.2.1) - #128

Draft
yao-lin-lain wants to merge 1 commit into
omdsh-dev:mainfrom
yao-lin-lain:fix/dsh-0.2.1-owner-peer
Draft

yao-lin-lain wants to merge 1 commit into
omdsh-dev:mainfrom
yao-lin-lain:fix/dsh-0.2.1-owner-peer

Conversation

@yao-lin-lain

@yao-lin-lain yao-lin-lain commented Oct 20, 2026 •

Copy link
Copy Markdown

Summary

Fixes bridge-browser on dsh 0.2.1 by passing the peer the Gateway expects to every Host call: the event stream, the /api fetch handler, and the four gateway.invoke call sites. Net change is 17 added lines in one file; nothing on the wire or in the extension changes.

Motivation

Since 0.2.1 the Gateway expects a peer scope on every Remote call and reads signal, interactions and principal.kind off it. The bridge still calls the 0.2.0 way, so the handshake succeeds and then immediately dies:

TypeError: Cannot read properties of undefined (reading 'signal')
{"t":"error","code":"stream-failed",…}  →  WS 1011

It isn't a single spot either. $events, the /api fetch and the extension→host unary calls (session.create, session.history, session.models) each fail on their own path, so fixing one doesn't reveal the others.

Changes

The peer is connection.browserPeer — the owner Peer the Connection service already publishes for authenticated browser connections (principal owner, interactions answer). So there's no new Peer to create, and its lifetime stays with the connection service:

  • openWireStream() takes an optional peer and passes it instead of undefined; the three-argument 0.2.0 shape still takes the old path
  • RemoteHostApi and EventGeneration hold that same instance — $events is opened by the latter and answered by the former, and a mismatched peer is what produces Remote event result belongs to another Peer
  • createSharedFetchHandler('/api').fetch(request, peer) gets its second argument
  • the four gateway.invoke({…}) call sites pass peer
  • the structural types (HostConnectionLike, wireStream.open, invoke) accept it; all of them take unknown, so no new interface is introduced

Testing

Linux (WSL2), dsh 0.2.1-rc.2, Edge, extension loaded unpacked. I drove the bridge with a script rather than the side panel, so the panel's connection state couldn't mislead me:

# before
rpc session.models → {"ok":false,"error":{"code":"gateway/internal","message":"…reading 'signal'"}}

# after
rpc session.models → {"ok":true,"value":{"current":{…},"groups":[…]}}
rpc workspace.list → {"ok":true,"value":{"items":[…]}}

The other direction (host → extension) still works: browser_list_tabs, browser_open_tab, browser_get_text, browser_close_tab. Worth saying for whoever tests next: exercising the tools alone is not enough — that direction never goes through invoke.

Impact

Only the bridge plugin. The extension, its tools and the message shapes are untouched. Requires dsh ≥ 0.2.1; 0.2.0 keeps the old call path. Platform independent.

Checklist

  • Tested on the relevant platforms
  • Passed basic checks (pnpm run build / bash -n scripts/install.sh) — not run. The repo's install script re-pins my local dsh dependency versions, so I verified against a locally patched build instead of running pnpm install / build
  • Docs updated if needed — no docs touched here
  • No unrelated changes included

One thing up front: this duplicates fb4d873e from #121. Mine is one file and one commit, so it can land whenever; if #121 gets there first, just close this one.

@graydovee

Copy link
Copy Markdown

感谢这个修复 —— 这个 bug 确实存在:握手成功后立刻收到 stream-failed,日志里是 TypeError: Cannot read properties of undefined (reading 'signal'),随后 WS 以 1011 关闭。这与我们在 0.2.1-rc.2 上观察到的现象一致。

不过同一处修复在 #121 里已有等价改动(fb4d873e)。

这个分支还差一处:gateway.invoke(...) 的四处调用仍然没有 peer(call()、sessionHistory、sessionModels 等)。dsh-api-gateway@0.2.1-rc.2 的 prepareInvocation 第一句就是 assertPeerLive(request.peer)(读 peer.signal),因此 unary 调用(browser_list_tabs / browser_get_text 等)在这份补丁之后仍会抛同一个 TypeError。这一处 fork 版本里已经补上了。

如果急需这个能力,可以先使用 fork 版本:https://github.com/graydovee/dsh-browser(v0.1.7 已发布,scripts/install.sh / scripts/install.ps1 会一并装好桥插件与扩展)。

@yao-lin-lain

Copy link
Copy Markdown
Author

Thanks for reviewing — you were right, the unary path was missing.

I've reworked the branch into a single commit (1 file, +17/−6). It now reuses connection.browserPeer — the owner Peer the Connection service already publishes for authenticated browser connections (principal owner, interactions answer) — instead of creating its own, and threads that one instance through openWireStream, the /api fetch and the four gateway.invoke call sites.

Verified with a script driving the bridge directly, since the side panel's connection state can be misleading:

# before
rpc session.models → {"ok":false,"error":{"code":"gateway/internal","message":"…reading 'signal'"}}

# after
rpc session.models → {"ok":true,…}    rpc workspace.list → {"ok":true,…}

Host→extension still works (browser_list_tabs / browser_open_tab / browser_get_text / browser_close_tab). That direction was the only one I had tested, which is exactly why I missed this — my mistake, and thanks for pointing it out.

Re #121: fb4d873e is the same change. Mine is a single file, so if you'd rather land #121 as a whole, I'm happy to close this one.

@yao-lin-lain
yao-lin-lain force-pushed the fix/dsh-0.2.1-owner-peer branch from 525060f to 8363102 Compare October 20, 2026 14:15
@yao-lin-lain yao-lin-lain changed the title fix: share one owner Peer across Host streams (dsh 0.2.1) fix: pass the connection's owner Peer to every Host stream and RPC (dsh 0.2.1) Oct 20, 2026
…sh 0.2.1)

dsh 0.2.1 requires a peer scope on every Remote call and reads `signal`,
`interactions` and `principal.kind` off it. The bridge still called the 0.2.0
way, so `hello.ok` was immediately followed by `stream-failed` / WS 1011 — and
even once the event stream connected, the extension→host unary calls
(session.create / session.history / session.models) kept failing with the same
"Cannot read properties of undefined (reading 'signal')".

Use the Peer the Connection service already publishes for authenticated browser
connections (`connection.browserPeer`: principal owner, interactions answer)
instead of creating another one, and thread it through:

- openWireStream(): peer instead of `undefined` (the 3-argument 0.2.0 shape
  still takes the old path)
- createSharedFetchHandler('/api').fetch(request, peer)
- the four gateway.invoke({…}) call sites

Verified over the bridge: session.models and workspace.list now return ok:true,
and the host→extension tools keep working.
@yao-lin-lain
yao-lin-lain force-pushed the fix/dsh-0.2.1-owner-peer branch from 8363102 to 8d64283 Compare October 26, 2026 03:28
@yao-lin-lain
yao-lin-lain marked this pull request as draft October 26, 2026 03:28
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.

2 participants