Skip to content

feat(truapi): export createWebSocketProvider for browser clients - #438

Merged
filvecchiato merged 5 commits into
mainfrom
feat/ws-provider-export
Aug 19, 2026
Merged

feat(truapi): export createWebSocketProvider for browser clients#438
filvecchiato merged 5 commits into
mainfrom
feat/ws-provider-export

Conversation

@peetzweg

Copy link
Copy Markdown
Member

Closes #435

What

@parity/truapi gains createWebSocketProvider(url), the WebSocket WireProvider that both native host READMEs already tell products to import, plus connectWebSocketHost(url) on the sandbox path so a plain browser tab is detected as hosted and getClientSync() returns a client.

Why

truapi-host signing-host --frame-listen is documented as the browser-facing option, but the browser had no transport that could reach it. The sandbox builds only the iframe handover and a MessagePort parked on window.__HOST_API_PORT__. Products worked around that by writing the bridge themselves, which is why the same provider now exists four times: ios/.../TrUAPIHost.swift:192 as a Swift string literal, android/.../TrUAPIHost.kt:421 again in Kotlin, rust/crates/truapi-host-cli/js/ws-provider.ts as this repo's own provider, and apps/web/src/dev/cliHost.ts in the DIM2 SPA, written only because there was nothing to import.

With this, running a real host next to a dev server needs no product-specific glue:

truapi-host signing-host --frame-listen 127.0.0.1:9955 --product-id my-product.dot
import { connectWebSocketHost } from "@parity/truapi/sandbox";

connectWebSocketHost("ws://127.0.0.1:9955");

That gives any web product a desk-local host with a real signer, real product accounts and the real statement store, and it covers two things the simulated host cannot: AutoSigning grants and authorized statement proofs. We have been developing the DIM2 SPA against signing-host this way for two weeks, so the shape is proven, just not shareable until now.

How

Mostly a move. nativeWsProvider in rust/crates/truapi-host-cli/js/ws-provider.ts was already correct and used nothing Node-specific, so the implementation moves next to createMessagePortProvider in transport.ts, reuses the shared createBaseProvider bookkeeping, and the CLI's provider delegates its TCP branch to it while keeping the Unix-socket half that only the CLI speaks. The frame protocol is one binary WebSocket message per SCALE frame, byte-identical to what the MessagePort transport carries, so the bridge is a pipe with no reframing.

connectWebSocketHost stores the endpoint, which makes isCorrectEnvironment() true and lets getClientSync() build and cache the client, so product code that already runs inside a webview or an iframe needs no changes. It throws if a client for another transport already exists, since that client is cached and cannot be redirected.

The native hosts are left alone on purpose. Collapsing their Swift and Kotlin copies onto this export is an obvious follow-up, but it touches release artifacts and is better sequenced by their owners.

Notes

  • One behaviour change for CLI scripts: postMessage after close now throws, matching every other provider in the package, where the old TCP branch returned silently.
  • Tests cover queueing before open, close propagation, a rejected connect, and the sandbox path (hosted detection, cached client, connected status, and the redirect guard).
  • The CLI README gains a "Browser products" section, including the two-host recipe for testing with two users.
  • #436 covers the other half of a one-command dev setup, a headless serve mode so the host does not need its own terminal.

Both native host READMEs tell products to pass the bridge URL to
`@parity/truapi`'s `createWebSocketProvider`, which did not exist. The same
provider was hand-written four times instead: as a Swift string literal on iOS,
again in Kotlin on Android, as the CLI's own JS provider, and once more
downstream in a product that needed to reach `signing-host --frame-listen`.

Add `createWebSocketProvider(url)` next to the MessagePort provider, and
`connectWebSocketHost(url)` on the sandbox path so a plain browser tab pointed
at such a host is detected as hosted and shares the cached client. The CLI's
provider now delegates its TCP branch and keeps only the Unix-socket half.
@filvecchiato
filvecchiato added this pull request to the merge queue Aug 19, 2026
Merged via the queue into main with commit d49f253 Aug 19, 2026
17 checks passed
@filvecchiato
filvecchiato deleted the feat/ws-provider-export branch August 19, 2026 14:59
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.

Run a real host beside a dev server: createWebSocketProvider is documented but missing

3 participants