centrifuge-js

Real-time JavaScript SDK for connecting browser, Node.js, and React Native apps to Centrifugo and Centrifuge servers.

SDK
npm
v5.7.3
504stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
79/100Good
Development Activity84
Maintenance72
Community80
Maturity60
Momentum20

Technical Analysis

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

Centrifuge is the official JavaScript client SDK for Centrifugo and Centrifuge-based servers, giving browser, Node.js, and React Native applications a single API for real-time bidirectional communication. It targets WebSocket as its primary transport but falls back to HTTP-streaming, SSE, and (experimentally) WebTransport when WebSocket connections are blocked by proxies or firewalls, using Centrifugo’s own bidirectional emulation layer to keep the same client API across transports.

Both the top-level Centrifuge client and its Subscription objects are EventEmitters, so applications react to connection and channel state transitions (connecting, connected, disconnected, subscribing, subscribed, unsubscribed) rather than polling for status. Beyond plain channel publications, the SDK layers three subscription styles on top of the same transport — base pub/sub, map subscriptions for synchronized key-value state, and shared-poll subscriptions for tracking a set of keys — plus offset/epoch-based recovery so a reconnecting client can be brought back in sync with messages it missed.

What You Get

  • A typed Centrifuge client and Subscription/BaseSubscription classes that expose connection and channel state as EventEmitter events instead of raw socket callbacks.
  • Built-in WebSocket-first transport selection with automatic fallback to HTTP-streaming, SSE, SockJS, or experimental WebTransport when a direct WebSocket connection is blocked.
  • Token-based authentication with a getToken callback for on-demand refresh, plus per-connection and per-subscription data/getData payloads.
  • Presence, presence-stats, history, and publish methods scoped to a channel subscription, alongside server-announced (server-side) subscriptions.
  • Experimental map and shared-poll subscription types for synchronized key-value state and lightweight key tracking, built on the same reconnect/recovery machinery as regular channels.

Common Use Cases

  • Live chat and notification feeds - subscribing to a channel and rendering publication events as they arrive, with join/leave events for presence-aware UIs.
  • Collaborative and shared state UIs - using map subscriptions to keep a synchronized key-value snapshot (e.g. a shared board or leaderboard) in sync across clients without re-fetching.
  • Resilient mobile and browser clients - relying on automatic reconnect with exponential backoff and stream recovery (offset/epoch) so a flaky connection doesn’t lose missed messages.
  • Multi-environment real-time apps - sharing one client API across browser, Node.js, and React Native by supplying an environment-specific WebSocket/EventSource/fetch implementation.

Under The Hood

Architecture The library is organized around two core classes — Centrifuge (src/centrifuge.ts, ~2150 lines) and Subscription/BaseSubscription (src/subscription.ts, ~2400 lines) — both extending Node’s EventEmitter cast to a typed interface (TypedEventEmitter) defined in src/types.ts. Centrifuge owns a transport abstraction layer (transport_websocket.ts, transport_http_stream.ts, transport_sse.ts, transport_sockjs.ts, transport_webtransport.ts) that it iterates through in configured order until one connects, then delegates command/reply framing to a pluggable codec (json.ts default, protobuf.codec.ts plus protobuf.ts for the binary variant), so transport and encoding are both swappable without touching client logic. Explicit state machines for the client (disconnected/connecting/connected) and each subscription (unsubscribed/subscribing/subscribed) drive the reconnect loop, backoff, and recovery bookkeeping (per-subscription offset/epoch tracked internally in centrifuge.ts). Three subscription “kinds” (base, Map, SharedPoll) share the same underlying implementation and are distinguished only by which events and methods are exposed on the returned surface via typed intersections, keeping reconnect and recovery logic in one place rather than duplicated across three classes.

Tech Stack Pure TypeScript in strict mode, targeting ES6, built with Rollup for the npm package (index.js/.mjs/.d.ts) and esbuild for standalone browser bundles. Runtime dependencies are minimal — the events polyfill and protobufjs for the binary codec — while WebSocket, EventSource, fetch, and SockJS implementations are all supplied by the consumer through options, keeping the SDK itself environment-agnostic. Tests run under Jest with ts-jest, and CI spins up a real Centrifugo server via docker-compose before running lint and the full test suite across multiple Node versions.

Code Quality Seventeen test files under src/ cover both codec-level behavior and higher-level reconnect, recovery, debounce, delta-compression, and map/shared-poll logic, with a global setup step that boots a real server so some tests exercise real network behavior rather than pure mocks. TypeScript strict mode and ESLint both run in CI. Error handling is explicit and typed — a dedicated error class plus enumerated error, disconnect, and subscribe codes rather than ad hoc string errors — and naming is consistent throughout, with public types documented via inline comments.

API Design The public surface stays intentionally small and consistent: one constructor accepting either a single WebSocket URL or an array of transport endpoints, one call to allocate a subscription per channel, and the same handful of methods (subscribe, unsubscribe, presence, history, publish) regardless of whether the underlying subscription is a plain channel, a map subscription, or a shared-poll subscription — the type system narrows what’s available per kind instead of exposing unrelated APIs. Getting started requires little beyond constructing the client, allocating a subscription, and calling connect/subscribe, and the README explicitly defers to a shared cross-language SDK spec for consistent state semantics before documenting every option and event in detail locally.

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