@sanity/bifur-client

A TypeScript WebSocket client for Sanity's Bifur real-time service, communicating over JSON-RPC 2.0 and exposing connections as RxJS Observables.

SDK
npm
v2.0.2
0stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
52/100Fair
Development Activity80
Maintenance56
Community12
Maturity60
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture85
Code Quality90
Innovation82
Learning Curve45

@sanity/bifur-client is the low-level WebSocket client that powers real-time features in Sanity Studio, such as live presence indicators and collaborative document editing. It wraps a raw WebSocket connection in an RxJS-based JSON-RPC 2.0 layer, giving consumers request() for one-shot calls and listen() for long-lived subscriptions, both returned as Observables rather than callbacks or promises.

Rather than opening a new socket per subscriber, the library multicasts a single shared connection and holds it open for a short grace period after the last unsubscribe, absorbing the rapid mount/unmount churn typical of React-driven UIs without reconnecting on every render. It also handles token-based re-authentication, safe teardown that never closes a socket mid-handshake, and a fromSanityClient helper that derives the connection URL and auth token directly from an existing @sanity/client instance.

What You Get

  • Two entry points — fromUrl() for a raw WebSocket URL and fromSanityClient() that derives the URL and token from an existing @sanity/client instance
  • A BifurClient interface exposing request(), listen(), and a heartbeats Observable for connection liveness
  • Automatic single-connection sharing across subscribers, with a wall-clock grace period before tearing down an idle socket
  • Built-in support for Sanity’s presence protocol (presence_rollcall, presence_announce, presence_disconnect, presence subscription)
  • Typed ERROR_CODES covering both WebSocket close codes and JSON-RPC error codes, plus a WebSocketError class distinguishing connection errors from unexpected closes

Common Use Cases

  • Powering Sanity Studio’s real-time presence indicators and live document collaboration under the hood
  • Building custom tooling on top of Sanity that needs an authenticated, deduplicated real-time connection without hand-rolling WebSocket lifecycle management
  • Implementing presence-aware collaborative editors that need to broadcast and query ‘who is viewing what’
  • Any client-side integration that needs a resilient WebSocket connection in a UI environment with frequent component mount/unmount cycles

Under The Hood

Architecture The package is organized into small, single-responsibility modules: createConnect.ts turns a raw WebSocket factory into an Observable of an open connection with safe, never-mid-handshake teardown; createClient.ts layers JSON-RPC request/response and subscribe/unsubscribe semantics on top of that connection, including token-based re-authentication via combineLatest over a token$ Observable; operators.ts holds one small reusable RxJS operator (timeoutFirstWith); and index.ts composes these into the public fromUrl/fromSanityClient API, adding connection sharing with a wall-clock grace period and page-unload handling. The layering is clean and the dependency direction is one-way (public API depends on the connection and client layers, never the reverse), so the core abstraction that would ripple outward if changed is the BifurClient interface itself in types.ts.

Tech Stack Written in TypeScript targeting Node >=22.12 and modern browsers, built and published via Sanity’s own @sanity/pkg-utils tooling with strict dual build/type checks (pkg build --strict, pkg check --strict). RxJS 7 is the sole functional dependency plus nanoid for collision-resistant request IDs. Linting and formatting run through oxlint/oxfmt in type-aware, warnings-as-errors mode, with knip catching unused exports. Tests run on Vitest. Releases are automated through Changesets with npm provenance/OIDC publishing, and CI runs the full build/test/type-check/lint/knip pipeline across two Node versions.

Code Quality The test suite is thorough for the surface area involved: it uses a hand-rolled MockWebSocket harness plus fake timers to exercise connection sharing across multiple subscribers, the disconnect grace period, mid-handshake teardown avoidance (a regression test explicitly tied to a documented production issue), error propagation for both socket errors and unexpected closes, and page-unload handling. Types are strict throughout with @public/@internal TSDoc annotations marking the intended API surface, and the oxlint config runs in typeAware/denyWarnings mode so type errors fail CI. No gaps or untested code paths were apparent in the reviewed modules.

API Design The public API is intentionally minimal — fromUrl, fromSanityClient, createClient, plus the ERROR_CODES map and WebSocketError type — which keeps the surface easy to reason about for a library with a narrow, specific purpose. Naming is consistent (request/listen mirror JSON-RPC call/subscribe semantics), and comments go beyond ordinary documentation to record the operational rationale behind non-obvious choices, such as why the disconnect grace period is measured in wall-clock time rather than task-queue ticks, citing a linked upstream PR with real measurements. The README’s usage examples cover both entry points and the presence protocol directly.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search