包详细信息

centrifuge

centrifugal412.4kMIT5.3.5

JavaScript client SDK for bidirectional communication with Centrifugo and Centrifuge-based server from browser, NodeJS and React Native

websocket, webtransport, eventsource, streaming

自述文件

This SDK provides a client to connect to Centrifugo or any Centrifuge-based server using pure WebSocket or one of the alternative transports (HTTP-streaming, SSE/EventSource, experimental WebTransport) from web browser, ReactNative, or NodeJS environments.

[!IMPORTANT]
This library behaves according to a common Centrifigo SDK spec. It's recommended to read that before starting to work with this SDK as the spec covers common SDK behavior - describes client and subscription state transitions, main options and methods. Then proceed with this readme for more specifics about centrifuge-js.

The features implemented by this SDK can be found in SDK feature matrix.

centrifuge-js v5.x is compatible with Centrifugo server v6, v5 and v4, and Centrifuge >= 0.25.0. For Centrifugo v2, Centrifugo v3 and Centrifuge < 0.25.0 you should use centrifuge-js v2.x.

Install

SDK can be installed via npm:

npm install centrifuge

And then in your project:

import { Centrifuge } from 'centrifuge';

In browser, you can import SDK from CDN (replace 5.0.0 with a concrete version number you want to use, see releases):

<script src="https://unpkg.com/centrifuge@5.0.0/dist/centrifuge.js"></script>

See also centrifuge-js on cdnjs. Note that centrifuge-js browser builds target ES6.

By default, library works with JSON only, if you want to send binary payloads go to Protobuf support section to see how to import client with Protobuf support.

Quick start

The basic usage example may look like this:

// Use WebSocket transport endpoint.
const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');

// Allocate Subscription to a channel.
const sub = centrifuge.newSubscription('news');

// React on `news` channel real-time publications.
sub.on('publication', function(ctx) {
    console.log(ctx.data);
});

// Trigger subscribe process.
sub.subscribe();

// Trigger actual connection establishement.
centrifuge.connect();

Note, that we explicitly call .connect() method to initiate connection establishement with a server and .subscribe() method to move Subscription to subsribing state (which should transform into subscribed state soon after connection with a server is established). The order of .connect() and .subscribe calls does not actually matter here.

Centrifuge object and Subscription object are both instances of EventEmitter. Below we will describe events that can be exposed in detail.

Supported real-time transports

This SDK supports several real-time transports.

Websocket transport

WebSocket is the main protocol used by centrifuge-js to communicate with a server.

In a browser environment WebSocket is available globally, but if you want to connect from NodeJS env – then you need to provide WebSocket constructor to centrifuge-js explicitly. See below more information about this.

It's the only transport for which you can just use a string endpoint as first argument of Centrifuge constructor. If you need to use other transports, or several transports – then you should use Array<TransportEndpoint>.

HTTP-based WebSocket fallbacks

In the quick start example above we used WebSocket endpoint to configure Centrifuge. WebSocket is the main transport – it's bidirectional out of the box.

In some cases though, WebSocket connection may not be established (for example, due to corporate firewalls and proxies). For such situations centrifuge-js offers several WebSocket fallback options based on HTTP:

These two transports use Centrifugo/Centrifuge own bidirectional emulation layer. See more details in introduction post. Bidirectional emulation must be first enabled on a server-side. See Centrifugo docs to find out how.

After enabling HTTP-streaming or SSE endpoints on a server side you can slightly change client initialization and point Javascript SDK to a list of endpoints and transports you want to use:

const transports = [
    {
        transport: 'websocket',
        endpoint: 'ws://example.com/connection/websocket'
    },
    {
        transport: 'http_stream',
        endpoint: 'http://example.com/connection/http_stream'
    },
    {
        transport: 'sse',
        endpoint: 'http://example.com/connection/sse'
    }
];
const centrifuge = new Centrifuge(transports);
centrifuge.connect()

In this case, client will try transports in order, one by one, during the initial handshake. Until success. Then will only use a successfully chosen transport during reconnects.

Supported transports are:

  • websocket
  • http_stream
  • sse
  • sockjs - SockJS can also be used as a fallback in Centrifugo < v6, in Centrifugo v6 SockJS was removed and will be removed in centrifuge-js v6 too. Also, sticky sessions must be used on the backend in distributed case with it. See more details below
  • webtransport - this SDK also supports WebTransport in experimental form. See details below

If you want to use sticky sessions on a load balancer level as an optimimization for Centrifugal bidirectional emulation layer keep in mind that we currently use same-origin credentials policy for emulation requests in http_stream and sse transport cases. So cookies will only be passed in same-origin case. Please open an issue in case you need to configure more relaxed credentials. Though in most cases stickyness based on client's IP may be sufficient enough.

Using SockJS

SockJS usage is DEPRECATED. Its support was removed in Centrifugo v6, and it will also be removed from this SDK in v6 release.

If you want to use SockJS you must also import SockJS client before centrifuge.js

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/centrifuge@5.0.0/dist/centrifuge.js" type="text/javascript"></script>

Or provide it explicitly as a dependency:

import { Centrifuge } from 'centrifuge'
import SockJS from 'sockjs-client'

const transports = [{
    transport: "sockjs",
    endpoint: "http://localhost:8000/connection/sockjs"
}];

const centrifuge = new Centrifuge(transports, {
  sockjs: SockJS
})

Note, that in SockJS case endpoint starts with http://, not with ws:// as we used above when connecting to a pure WebSocket endpoint.

WebTransport (experimental)

WebTransport is experimental and is only supported by Centrifugo at the moment (i.e. it's not available in Centrifuge library for Go out of the box).

Server must be additionally configured to work with WebTransport connections – see information in Centrifugo WebTransport docs.

Client API

Let's look at top-level API of Centrifuge client.

Client methods and events

connect method

As we already showed above, we must call connect() method to make an actual connection request to Centrifugo server:

const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');
centrifuge.connect();

connect() triggers an actual connection request to server.

connected event

As soon as connection is established and client successfully authenticated – connected event on Centrifuge object instance will be called.

It's possible to listen to this event by setting event listener function on connected event:

centrifuge.on('connected', function(ctx) {
    // now client connected to Centrifugo and authenticated.
});

connecting event

connecting event fired when Centrifuge object goes to connecting state. This may be called during initial connect, or after being connected due to temporary connection loss.

centrifuge.on('connecting', function(ctx) {
    // do whatever you need in case of connecting to a server
});

disconnected event

disconnected event fired on Centrifuge object every time client disconnects for some reason. This can be terminal disconnect due to advice from a server or disconnect initiated by client-side.

centrifuge.on('disconnected', function(ctx) {
    // do whatever you need in case of disconnect from server
});

disconnect method

In some cases you may need to disconnect your client from server, use .disconnect() method to do this:

centrifuge.disconnect();

After calling this client will not try to reestablish connection periodically. You must call .connect() method manually again.

publish method

Sometimes you need to publish into channel without actually being subscribed to it. In this case you can use publish method:

centrifuge.publish("channel", {"input": "hello"}).then(function(res) {
    console.log('successfully published');
}, function(err) {
    console.log('publish error', err);
});

send method

This is only valid for Centrifuge server library for Go and does not work for Centrifugo server at the moment. send method allows sending asynchronous message from a client to a server.

centrifuge.send({"input": "hello"}).then(function(res) {
    console.log('successfully sent');
}, function(err) {
    console.log('send error', err);
});

rpc method

rpc method allows to send rpc request from client to server and wait for data response.

centrifuge.rpc("my.method.name", {"input": "hello"}).then(function(res) {
    console.log('rpc result', res);
}, function(err) {
    console.log('rpc error', err);
});

history method

Allows to get history from a server. This is a top-level analogue of Subscription.history method. But accepts a channel as first argument.

centrifuge.history("channel", {since: {offset: 0, epoch: "xyz"}, limit: 10}).then(function(resp) {
    console.log(resp);
}, function(err) {
    console.log('history error', err);
});

presence method

Allows to get presence info from a server. This is a top-level analogue of Subscription.presence method. But accepts a channel as first argument.

centrifuge.presence("channel").then(function(resp) {
    console.log(resp);
}, function(err) {
    console.log('presence error', err);
});

presenceStats method

Allows to get presence stats from a server. This is a top-level analogue of Subscription.presenceStats method. But accepts a channel as first argument.

centrifuge.presenceStats("channel").then(function(resp) {
    console.log(resp);
}, function(err) {
    console.log('presence stats error', err);
});

ready method

Returns a Promise which will be resolved upon connection establishement (i.e. when Client goes to connected state).

setToken method

setToken may be useful to dynamically change the connection token. For example when you need to implement login/logout workflow. See an example in blog post.

error event

To listen asynchronous error happening internally while Centrifuge client works you can set an error handler:

const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');

centrifuge.on('error', function(ctx) {
    console.log(ctx);
});

This can help you to log failed connection attempts, or token refresh errors, etc.

Connection Token

Depending on authentication scheme used by a server you may also want to provide connection token:

const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket', {
    token: '<CONNECTION_TOKEN>'
});

In case of Centrifugo on a server side this may be a JSON Web Token - see authentication documentation for details on how to generate it on your backend side.

Connection token must come to the frontend from application backend - i.e. must be generated on the backend side. The way to deliver token to the application frontend is up to the developer. Usually you can pass it in template rendering context or issue a separate call to request a connection token from the backend.

If the token sets connection expiration then the client SDK will keep the token refreshed. It does this by calling a special callback function. This callback must return a new token. If a new token with updated connection expiration is returned from callback then it's sent to Centrifugo. In case of error returned by your callback SDK will retry the operation after some jittered time. You can throw a special error (throw new Centrifuge.UnauthorizedError();) from getToken function to move the client into disconnected state (for example, when there is no permission to connect anymore).

An example of possible getToken function implementation:

import { Centrifuge, UnauthorizedError } from 'centrifuge';

async function getToken() {
    if (!loggedIn) {
        return "";
    }
    const res = await fetch('/centrifuge/connection_token');
    if (!res.ok) {
        if (res.status === 403) {
            // Return special error to not proceed with token refreshes, client will be disconnected.
            throw new UnauthorizedError();
        }
        // Any other error thrown will result into token refresh re-attempts.
        throw new Error(`Unexpected status code ${res.status}`);
    }
    const data = await res.json();
    return data.token;
}

const client = new Centrifuge(
    'ws://localhost:8000/connection/websocket',
    {
        token: 'JWT-GENERATED-ON-BACKEND-SIDE',
        getToken: getToken
    }
);

If initial token is not provided, but getToken is specified – then SDK assumes that developer wants to use token authentication. In this case SDK attempts to get a connection token before establishing an initial connection.

Subscription API

What we usually want from Centrifugo is to receive new messages published into channels. To do this we must create Subscription object.

Subscription methods and events

Subscribe to a channel

The simplest usage that allow to subscribe on channel and listen to new messages is:

const sub = centrifuge.newSubscription('example');

sub.on('publication', function(ctx) {
    // handle new Publication data coming from channel "news".
    console.log(ctx.data);
});

sub.subscribe();

Subscription events

Some events which can be listened on Subscription object are:

  • publication – called when new publication received from a Subscription channel
  • join – called when someone joined channel
  • leave – called when someone left channel
  • subscribing - called when Subscription goes to subscribing state (initial subscribe and re-subscribes)
  • subscribed – called when Subscription goes to subscribed state
  • unsubscribed – called when Subscription goes to unsubscribed state
  • error – called when subscription on channel failed with error. It can be called several times during lifetime as browser client automatically resubscribes on channels after successful reconnect (caused by temporary network disconnect for example or Centrifugo server restart)

Don't be frightened by amount of events available. In most cases you only need some of them until you need full control to what happens with your subscriptions.

Subscription objects are instances of EventEmitter.

presence method of Subscription

presence allows to get information about clients which are subscribed on channel at this moment. Note that this information is only available if presence option enabled in Centrifugo configuration for all channels or for channel namespace.

const sub = centrifuge.newSubscription("news");
sub.subscribe()

sub.presence().then(function(ctx) {
    console.log(ctx.clients);
}, function(err) {
    // presence call failed with error
});

presence is internally a promise that will be waiting for subscription subscribe success if required.

As you can see presence data is a map where keys are client IDs and values are objects with client information.

Format of err in error callback:

{
    "code": 108,
    "message": "not available"
}
  • code - error code (number)
  • message – error description (string)

Note, that in order presence to work corresponding options must be enabled in server channel configuration (on top level or for channel namespace)

presenceStats method of subscription

presenceStats allows to get two counters from a server: number of total clients currently subscribed and number of unique users currently subscribed. Note that this information is only available if presence option enabled in server configuration for a channel.

sub.presenceStats().then(function(ctx) {
    console.log(ctx.numClients);
}, function(err) {
    // presence stats call failed with error
});

history method of subscription

history method allows to get last messages published into channel. Note that history for channel must be configured in Centrifugo to be available for history calls from client.

sub.history({limit: 100}).then(function(ctx) {
    console.log(ctx.publications);
}, function(err) {
    // history call failed with error
});

Note, that in order history to work corresponding options must be enabled in server channel configuration (on top level or for channel namespace)

Some history options available:

  • limit (number)
  • since (StreamPosition)
  • reverse (boolean)
resp = await subscription.history({'since': {'offset': 2, 'epoch': 'xcf4w'}, limit: 100});

If server can't fulfill a query for history (due to stream retention - size or expiration, or malformed offset, or stream already has another epoch) then an Unrecoverable Position Error will be returned (code 112).

To only call for current offset and epoch use:

resp = await subscription.history({limit: 0});

I.e. not providing since and using zero limit.

publish method of subscription

publish method of Subscription object allows publishing data into channel directly from a client.

Using client-side publish is not an idiomatic Centrifugo usage in many cases. Centrifugo is standalone server and when publishing from a client you won't get the message on the backend side (except using publish proxy feature of Centrifugo). In most real-life apps you need to send new data to your application backend first (using the convenient way, for example AJAX request in web app) and then publish data to Centrifugo over Centrifugo API.

Just like presence and history publish must be allowed in Centrifugo configuration for all channels or for channel namespace.

sub.publish({"input": "hello world"}).then(function() {
        // success ack from Centrifugo received
    }, function(err) {
        // publish call failed with error
    });
});

Note, that in order publish to work in Centrifugo corresponding option must be enabled in server channel configuration or client should have capability to publish.

unsubscribe method of subscription

You can call unsubscribe method to unsubscribe from a channel:

sub.unsubscribe();

Important thing to mention is that unsubscribing from subscription does not remove event handlers you already set to that Subscription object. This allows to simply subscribe to channel again later calling .subscribe() method of subscription (see below). But there are cases when your code structured in a way that you need to remove event handlers after unsubscribe to prevent them be executed twice in the future. To do this remove event listeners explicitly after calling unsubscribe():

sub.unsubscribe();
sub.removeAllListeners();

ready method of subscription

Returns a Promise which will be resolved upon subscription success (i.e. when Subscription goes to subscribed state).

Subscription token

You may want to provide subscription token:

const sub = centrifuge.newSubscription("news", {
    token: '<SUBSCRIPTION_TOKEN>'
});

In case of Centrifugo on a server side this may be a JSON Web Token - see channel token auth documentation for details on how to generate it on your backend side.

Subscription token must come to the frontend from application backend - i.e. must be generated on the backend side. The way to deliver token to the application frontend is up to the developer. Usually you can pass it in template rendering context or issue a separate call to request a connection token from the backend.

If token sets subscription expiration client SDK will keep token refreshed. It does this by calling special callback function. This callback must return a new token. If new token with updated subscription expiration returned from a calbback then it's sent to Centrifugo. If your callback returns an empty string – this means user has no permission to subscribe to a channel anymore and subscription will be unsubscribed. In case of error returned by your callback SDK will retry operation after some jittered time.

An example:

import { Centrifuge, UnauthorizedError } from 'centrifuge';

async function getToken(ctx) {
    // ctx argument has a channel.
    const res = await fetch('/centrifuge/subscription_token', {
        method: 'POST',
        headers: new Headers({ 'Content-Type': 'application/json' }),
        body: JSON.stringify(ctx)
    });
    if (!res.ok) {
        if (res.status === 403) {
            // Return special error to not proceed with token refreshes, subscription will be unsubscribed.
            throw new UnauthorizedError();
        }
        // Any other error thrown will result into token refresh re-attempts.
        throw new Error(`Unexpected status code ${res.status}`);
    }
    const data = await res.json();
    return data.token;
}

const client = new Centrifuge('ws://localhost:8000/connection/websocket', {});

const sub = centrifuge.newSubscription(channel, {
    token: 'JWT-GENERATED-ON-BACKEND-SIDE',
    getToken: getToken,
});
sub.subscribe();

If initial token is not provided, but getToken is specified – then SDK assumes that developer wants to use token authorization for a channel subscription. In this case SDK attempts to get a subscription token before initial subscribe.

Subscription management API

According to client SDK spec centrifuge-js supports several methods to manage client-side subscriptions in internal registry. The following methods are available on top level of the Centrifuge SDK client instance.

newSubscription

newSubscription(channel: string, options?: Partial<SubscriptionOptions>): Subscription

Creates new Subscription to a channel or throws an exception if the Subscription to a channel already exists in the internal registry of the client.

getSubscription

getSubscription(channel: string): Subscription | null

getSubscription returns Subscription if it's registered in the internal registry or null.

removeSubscription

removeSubscription(sub: Subscription | null)

removeSubscription allows removing Subcription from the internal registry.

subscriptions

subscriptions(): Record<string, Subscription>

Get a map with all current client-side subscriptions registered in the client.

Message batching

There is also a command batching support. It allows to send several commands to a server in one request - may be especially useful when connection established via one of HTTP-based transports.

You can start collecting commands by calling startBatching() method:

centrifuge.startBatching();

Finally if you don't want batching anymore call stopBatching() method:

centrifuge.stopBatching();

This call will flush all collected commands to a network.

Server-side subscriptions

We encourage using client-side subscriptions where possible as they provide a better control and isolation from connection. But in some cases you may want to use server-side subscriptions (i.e. subscriptions created by server upon connection establishment).

Technically, client SDK keeps server-side subscriptions in internal registry (similar to client-side subscriptions but without possibility to control them).

To listen for server-side subscription events use callbacks as shown in example below:

const client = new Centrifuge('ws://localhost:8000/connection/websocket', {});

client.on('subscribed', function(ctx) {
    // Called when subscribed to a server-side channel upon Client moving to
    // connected state or during connection lifetime if server sends Subscribe
    // push message.
    console.log('subscribed to server-side channel', ctx.channel);
});

client.on('subscribing', function(ctx) {
    // Called when existing connection lost (Client reconnects) or Client
    // explicitly disconnected. Client continue keeping server-side subscription
    // registry with stream position information where applicable.
    console.log('subscribing to server-side channel', ctx.channel);
});

client.on('unsubscribed', function(ctx) {
    // Called when server sent unsubscribe push or server-side subscription
    // previously existed in SDK registry disappeared upon Client reconnect.
    console.log('unsubscribed from server-side channel', ctx.channel);
});

client.on('publication', function(ctx) {
    // Called when server sends Publication over server-side subscription.
    console.log('publication receive from server-side channel', ctx.channel, ctx.data);
});

client.connect();

Server-side subscription events mostly mimic events of client-side subscriptions. But again – they do not provide control to the client and managed entirely by a server side.

Additionally, Client has several top-level methods to call with server-side subscription related operations:

  • publish(channel, data)
  • history(channel, options)
  • presence(channel)
  • presenceStats(channel)

Configuration options

You can check out all available options with description in source code.

Let's look at available configuration parameters when initializing Centrifuge object instance.

debug

debug is a boolean option which is false by default. When enabled lots of various debug messages will be logged into javascript console. Mostly useful for development or troubleshooting.

minReconnectDelay

When client disconnected from a server it will automatically try to reconnect using a backoff algorithm with jitter. minReconnectDelay option sets minimal interval value in milliseconds before first reconnect attempt. Default is 500 milliseconds.

maxReconnectDelay

maxReconnectDelay sets an upper reconnect delay value. Default is 20000 milliseconds - i.e. clients won't have delays between reconnect attempts which are larger than 20 seconds.

maxServerPingDelay

maxServerPingDelay sets the maximum delay of server pings after which connection is considered broken and client reconnects. In milliseconds. Default is 10000.

token

Set initial connection token.

getToken

Set function for getting connection token. This may be used for initial token loading and token refresh mechanism (when initial token is going to expire).

data

Set custom data to send to a server withing every connect command.

name

Set custom client name. By default, it's set to js. This is useful for analitycs and semantically must identify an environment from which client establishes a connection.

version

Version of your application - useful for analitycs.

timeout

Timeout for operations in milliseconds.

websocket

websocket option allows to explicitly provide custom WebSocket client to use. By default centrifuge-js will try to use global WebSocket object, so if you are in web browser – it will just use native WebSocket implementation. See notes about using centrifuge-js with NodeJS below.

sockjs

sockjs option allows to explicitly provide SockJS client object to Centrifuge client.

Protobuf support

To import client which uses Protobuf protocol under the hood:

<script src="https://unpkg.com/centrifuge@5.0.0/dist/centrifuge.protobuf.js"></script>

Or if you are developing with npm:

import { Centrifuge } from 'centrifuge/build/protobuf';

This client uses protobuf.js under the hood.

When running with Protobuf-based client, you can send and receive any binary data as Uint8Array. Make sure data is properly encoded when calling methods of Centrifuge Protobuf-based instance. For example, you can not just send JSON-like objects like in JSON protocol case, you need to encode data to Uint8Array first:

const data = new TextEncoder("utf-8").encode(JSON.stringify({"any": "data"})); 
sub.publish(data);

Using with NodeJS

NodeJS does not have native WebSocket library in std lib. To use centrifuge-js on Node you need to explicitly provide WebSocket constructor to the library.

First, install WebSocket dependency:

npm install ws

At this point you have 2 options. Explicitly pass WebSocket object to Centrifuge.

import { Centrifuge } from 'centrifuge';
import WebSocket from 'ws';

var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
    websocket: WebSocket
})

Or define it globally:

import { Centrifuge } from 'centrifuge';
import WebSocket from 'ws';

global.WebSocket = WebSocket;

const centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket');

Custom WebSocket constructor

If you are building a client for a non-browser environment and want to pass custom headers then you can use the following approach to wrap a WebSocket constructor and let custom options to be used on connection initialization:

const myWs = function (options) {
  return class wsClass extends WebSocket {
    constructor(...args) {
      if (args.length === 1) {
        super(...[...args, 'centrifuge-json', ...[options]])
      } else {
        super(...[...args, ...[options]])
      }
    }
  }
}

It should be now possible to use pass your custom WebSocket constructor to centrifuge-js and so custom headers will be used when connecting to a server (only in non-browser environment):

var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
    websocket: myWs({ headers: { Authorization: '<token or key>' } }),
});

See a basic example with React Native where this technique is used in this comment.

Using with React Native on Android

If you have issues with the connection on Android when using React Native – check out this comment – you may be using non-secure endpoint schemes and need to explicitly allow it.

Run tests locally

If you want to run centrifuge-js tests locally, start test Centrifugo server:

docker compose up

Then:

yarn test

更新日志

5.0.2 and higher

Since centrifuge-js 5.0.2 we do not maintain CHANGELOG.md file.

All changes may be found on releases page on Github.

5.0.1

  • Add missing .hasOwnProperty check when iterating over arrays

5.0.0

In v5 release we are moving to Rollup to build the library. For centrifuge-js this means both ESM and CommonJS support and thus solve some issues when users could not use SDK with their existing toolchains. The migration includes some changes in how we provide Protobuf version of Centrifuge client. That's why we are making a new major v5 release.

For users which work with JSON-based Centrifuge client (default behaviour) the migration to v5 should be smooth and require no code changes.

Users of Protobuf version of the client need to change how they import Centrifuge when using the library. Also, we removed protocol option of Centrifuge instance config object. Imported Protobuf client now automatically uses Protobuf protocol under the hood.

For example, previously, when using Protobuf version of Centrifuge client, you have to import Protobuf client and then provide an option to constructor:

import Centrifuge from 'centrifuge/build/protobuf';

const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket", {
    protocol: 'protobuf'
});

Now this simplifies to:

import { Centrifuge } from 'centrifuge/build/protobuf';

const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket", {});

Note - changed import and no need to pass protocol: 'protobuf'. See readme for more information about using Protobuf client and constructing binary payloads.

4.1.0

  • Fix types: use Record instead of Map for publication tags and clients field of PresenceResult.

4.0.1

  • Update dependencies. In particular: migrate to the latest protobufjs 7.2.4.

4.0.0

This release changes the semantics of working with connection tokens described in Centrifugo v5 release post.

Previously, returning an empty token string from getToken callback resulted in client disconnection with unauthorized reason.

Now returning an empty string from getToken is a valid scenario which won't result into disconnect on the client side. It's still possible to disconnect client by throwing a special UnauthorizedError() error from getToken function.

And we are putting back setToken method to the SDK – so it's now possible to reset the token to be empty upon user logout.

Also, centrifuge-js v4 contains the reworked reconnect code where we schedule reconnect task from the disconnect function instead of transport close event handler - see #234.

3.1.2

This release contains important connection stability improvements. If you experience disconnections due to bad request or stale reasons – this release may fix if not all but most of them.

  • Fix connection leak due to transport close race, #225.
  • Use network events in connecting state, #227. This allows immediately close transport upon offline event while SDK is in connecting state. Previously we only started handling these events after successful connect. Also fixes setting duplicate onlne/offline event handlers.

3.1.1

  • Fix missing connInfo and chanInfo in presence data, see #220

3.1.0

  • React on network online/offline events #204. In browser environment centrifuge-js will automatically listen to window online and offline events, on offline event client will immediately disconnect, on online event reconnect attempt will be forced
  • Fix non-working HTTP-streaming in browser build due to esbuild minification issue

3.0.1

3.0.0

Breaking changes

This release adopts a new iteration of Centrifugal protocol and a new iteration of API. Client now behaves according to the client SDK API specification. The work has been done according to Centrifugo v4 roadmap.

Check out Centrifugo v4 release post that covers the reasoning behind changes here.

New release only works with Centrifugo >= v4.0.0 and Centrifuge >= 0.25.0. See Centrifugo v4 migration guide for details about the changes in the ecosystem.

Note, that Centrifugo v4 supports clients working over the previous protocol iteration, so you can update Centrifugo to v4 without any changes on the client side (but you need to turn on use_client_protocol_v1_by_default option in the configuration of Centrifugo, see Centrifugo v4 migration guide for details).

Release notes:

  • new API according to the new SDK API specification
  • client migrated to Typescript, all public API is strictly typed, including EventEmitter callbacks
  • SockJS is now DEPRECATED in Centrifugal ecosystem and requires explicit configuration, see the library readme
  • introducing our own WebSocket emulation layer - based on HTTP-streaming and SSE (Eventsource) fallbacks
  • experimental WebTransport support (only works with Centrifugo v4 experimental HTTP/3 support)
  • optimistic subscriptions to reduce connect latency
  • redesigned PING-PONG (pings are only sent from server to client now)
  • resilient subscriptions which handle temporary server errors and re-subscribe (with full jitter backoff)

2.8.5

  • fix typing of subscribe error context #187
  • throw error if no transport configured #176

2.8.4

  • Support setting a custom data attached to a subscribe request. This data will be then available in OnSubscribe callback on the server side (in the case of Centrifugo subscribe proxy will be able to access this data). #171.

2.8.3

  • Fix regression of 2.8.0: handle server-side subscribe and unsubscribe pushes.

2.8.2

  • Fix TypeScript definitions for subscribe (A rest parameter must be last in a parameter list.).

2.8.1

  • Support sockjsTimeout (number) option which translates to SockJS.timeout option - i.e. a minimum timeout in milliseconds to use for the transport connections. By default SockJS uses timeout determined automatically based on calculating round trip time during info request.

2.8.0

Update to work with Centrifuge >= v0.18.0 and Centrifugo v3.

Breaking change in server behavior. Client History API behavior changed in Centrifuge >= v0.18.0 and Centrifugo >= v3.0.0. When using history call it won't return all publications in a stream by default. See Centrifuge v0.18.0 release notes or Centrifugo v3 migration guide for more information and workaround on server-side. If you are using centrifuge-js with older server versions then everything without using history options like limit and since then everything should work the same way. Since this is a change in a server behavior we don't release a new major centrifuge-js version.

Other changes:

  • Protocol definitions updated to the latest version
  • When working with Centrifugo v3 or Centrifuge >= v0.18.0 it's now possible to avoid using ?format=protobuf in connection URL when using Protobuf protocol. The intent to use binary Protobuf protocol can now be set explicitly in client options. In this case client will negotiate Protobuf protocol with a server using WebSocket subprotocol mechanism (in request headers). Pull request.
  • It's now possible to call subscribe and provide custom subscribe options. One subscribe option available now is since – which allows setting known StreamPosition and initiate automatic recovery. Pull request.

2.7.7

  • possibility to set disableWithCredentials boolean option (false by default) to control withCredentials option of XMLHttpRequest. See #155.

2.7.6

  • xmlhttprequest option to explicitly pass XMLHttpRequest (for NodeJS environment)

2.7.5

  • Fix regression of 2.7.4 - Unexpected end of JSON input

2.7.4

  • Optimize & simplify json encode/decode, see #138

2.7.3

  • SubscribeSuccessContext can contain data field if custom data returned from a server in a subscribe result.

2.7.2

  • Handle server-side SUB push in Protobuf case (previously ignored). Sub push is a message that contains information about server-side subscription made after connection already established.

2.7.1

  • Fix type definitions - see #133

2.7.0

  • add missing offset to TS definitions for PublicationContext, note that seq and gen fields considered deprecated and will go away with next major centrifuge-js release
  • add top-level methods: history, presence, presenceStats – those are useful when using sever-side subscriptions
  • fix wrong error format of top-level publish Promise reject branch – it now contains protocol error object (with code and message fields)
  • possibility to set name and version protocol fields over Centrifuge config options
  • remove unused promise option from configuration
  • add history iteration API (usage limited to Centrifuge library for Go at the moment) - see example below
  • subscribe success event context in positioned subscriptions (added in Centrifuge library v0.15.0) now contains streamPosition object (with current offset and epoch fields)
  • updated protobuf-js dependency (now ^6.10.2)
  • all dev-dependencies updated and now use the latest versions of webpack, babel, eslint, mocha etc
  • internal code refactoring of Subscrption methods - code is simplified and more reusable now

Let's look at history pagination feature in more detail. It's now possible to iterate over channel history this way:

resp = await subscription.history({'since': {'offset': 2, 'epoch': 'xcf4w'}, limit: 100});

If server can't fulfill a query for history (due to stream retention - size or expiration, or malformed offset, or stream already has another epoch) then an Unrecoverable Position Error will be returned (code 112).

To only call for current offset and epoch use:

resp = await subscription.history({limit: 0});

I.e. not providing since and using zero limit.

Due to backward compatibility history call without arguments will return full existing history in channel (though it's possible to limit max number of publications to return on server side).

For now history pagination feature only works with Centrifuge library based server and not available in Centrifugo.

2.6.4

  • fix missing info in Publication context
  • add namedRPC method to call RPC with method string

2.6.3

  • fix possible event loss in server-side subscriptions due to Promise execution order

2.6.2

  • fix TypeError in subRefresh method, #109

2.6.1

  • fix TypeError on refresh token with protobuf, #107

2.6.0

  • Support Offset protocol field which is replacing Seq and Gen, client will work with both Offset and Seq/Gen based servers until next major release. Then support for Seq/Gen will be removed.

2.5.0

  • Remove subscription from internal _subs map after .unsubscribe() called, see this discussion for more details
  • Make sure that server-side subscription exists before calling server-side subscription events

2.4.0

2.3.0

  • Fix fulfilling Promise when RPC error happens. Before this fix RPC error did not properly called Promise error handler, now it does.

2.2.3

  • Fix type declarations for onPrivateSubscribe callback. See #94 for details.

2.2.2

  • Do not reconnect after disconnect called in disconnected state, more details in #92.

2.2.1

  • Fix error on resolving EventEmitter import while building TypeScript project with definitions added in 2.2.0.

2.2.0

  • fix wrong case of fields in Publication info and in result of presence() and presenceStats() responses in Protobuf format case. Those fields were not compliant with JSON format due to the fact that Protobuf compiler does not keep original case defined in proto schema by default. If you are using Protobuf this can be a breaking change - see this commit for fix details and all fields that now use snake_case instead of camelCase in Protobuf case. If you are using JSON you are not affected with these changes
  • fix unhandled promise exceptions on NodeJS when calling subscription methods
  • add TypeScript type definitions, thanks to @jekaspekas for contribution
  • add websocket option to explicitly provide custom WebSocket implementation to use

2.1.6

  • fix subscribe after clearing connection state, see #83 for details

2.1.5

  • fix wrong error object format (on timeout, disconnect and connection closed errors) introduced in 2.1.4

2.1.4

  • fix broken iteration over several replies in one frame if one of replies had error field set

2.1.3

  • fix setting setInterval with value greater than 2,147,483,647 which resulted in immediate refresh callback firing. Thi means that maximum possible TTL for JWT is about 25 days in Javascript.

2.1.2

  • fix private subscription races after reconnect, see #76 for issue and solution details

2.1.1

  • fix websocket transport state check - see #74

2.1.0

  • new publish method of Centrifuge object to publish into channels without being subscribed
  • check connection state to prevent writing to closed connection and thus unhandled errors
  • send method now sends message to server immediately and returns Promise

2.0.1

  • Prevent unhandled errors to be raised after failed subscription (#70)

2.0.0

This is a new major release of library updated to work with Centrifugo v2 and Centrifuge library. Library is now written using more actual Javascript instruments - with Webpack and ES6 classes. See readme for more information about new API and how to use library in general.

Highlights:

  • Webpack and ES6 for code base
  • JSON and Protobuf (only Websocket) serialization formats supported
  • new presenceStats method of subscription

1.5.0

  • fix isResubscribe flag behaviour to only be true after resubscribe on reconnect. See more details in #62
  • fix resubscribe behaviour after unsubscribe sent from server - this is th remaining part of #46

1.4.9

  • support new private subscription response format. Now it's possible to return JSON of this kind:
{
  "channels": [
    {
      "channel": "$one",
      "sign": "..."
    }
  ]
}

I.e. object with channels on top level which is an array of objects with channel data. This resolves issues with API generators that do not support map on top level. This is also a bit more extendable and most probably will be default format in v2.

1.4.8

  • withCredentials support for XHR requests - #39.
  • fix resubscribe bug introduced in 1.4.7

1.4.7

  • fix undesired resubscribe after reconnect. See #45
  • add onRefresh and onPrivateChannelAuth callback functions to config to replace built-in refresh and private channel auth behaviour with you own logic. See #45 for motivation and initial pull request sent by @skyborn8
  • onTransportClose callback should be executed every time transport was closed - see #33 for motivation.
  • fix refresh workflow in case client offline for a while

1.4.6

  • export recovered flag in successful subscribe event context. It indicates that Centrifugo thinks all messages were successfully recovered (i.e. client did not miss any messages) after successful resubscribe on channel. See https://github.com/centrifugal/centrifugo/issues/165 for motivation.

So it's possible to use it like this:

function handleSubscribe(ctx) {
    console.log('Subscribed on channel ' + ctx.channel);
    if (ctx.isResubscribe && !ctx.recovered) {
        console.log("you need to restore messages from app backend");
    } else {
        console.log("no need to restore state");
    }
}

var sub = centrifuge.subscribe(channel, handleMessage).on("subscribe", handleSubscribe)

Note that asking your backend about actual state after every reconnect is still the most reliable way to recover your app state. Relying on recovered flag can be an acceptable trade off for some applications though.

1.4.5

  • update es6-promise dependency to ^4.0.5

1.4.4

  • removing ping field from connect message as it not used by Centrifugo >= 1.6.3

1.4.3

It's recommended to update SockJS library to latest version - 1.1.2

  • Use public SockJS API to get transport name. See #26

1.4.2

  • Do not send ping to server for a while after receiving SockJS heartbeat frame.

1.4.1

  • fix ReferenceError - see #25

1.4.0

This release works with Centrifugo >= 1.6.0

  • automatic client to server pings.

Ping will be sent to server only when connection was idle - i.e. if there was no wire activity for pingInterval period so it should not affect performance much.

You can disable automatic pings using "ping": false option. But before turning it off make sure you've read chapter about pings in docs.

Also there is an adjustable pongWaitTimeout option to control how long to wait for pong response before closing connection.

1.3.9

  • do not try to refresh after disconnected. See #24

1.3.8

  • properly handle disconnect API command - do not reconnect.

1.3.7

  • Adapt to use in ES6 style
  • new sockJS option to explicitly provide SockJS client object
  • npm entry point is src/centrifuge.js now to prevent webpack warning.

ES6 example:

import Centrifuge from 'centrifuge'
import SockJS from 'sockjs-client'

var c = new Centrifuge({
    "url": "...",
    "user": "...",
    "token": "...",
    "timestamp": "...",
    "sockJS": SockJS
});

c.connect();

1.3.6

  • refreshData option to send extra data in body when sending AJAX POST refresh request
  • refreshAttempts option to limit amount of refresh requests before giving up
  • refreshFailed options to set callback function called when refreshAttempts came to the end.

1.3.5

  • fix using centrifuge-js in SharedWorker - there is no window object, so using self instead of window when we in SharedWorker context.

1.3.4

  • only call subscribe for existing subscription if its in unsubscribed state.

1.3.3

  • fix centrifuge.subscribe method when calling on channel for which subscription already exists but in unsubscribe state. See this pull request for more details.

1.3.2

  • use browserify to build library
  • fix import over requirejs introduced in 1.3.0

1.3.1

  • add latency field (in milliseconds) to connect event context. This measures time passed between sending connect client protocol command and receiving connect response.

Also there was debug logging statement in 1.3.0 left in source code occasionally. 1.3.0 was rebuilt with fix, but I am not sure that it was not cached somewhere in bower. So here is 1.3.1

1.3.0

Client API completely refactored in this release. You can still use previous versions to communicate with Centrifugo server from browser environment but new implementation much more comfortable to use in our opinion and will be supported in future releases so consider upgrading!

Highlights of this release:

  • automatic resubscribe, no need to subscribe manually in connect event handler
  • more opaque error handling
  • drop support for SockJS < 1.0.0 (but if you still use SockJS 0.3.4 then feel free to open issue and we will return its support to client)

Please, read new documentation for Javascript browser client.

Also, DOM plugin was removed from repository as new client API design solves most of problems that DOM plugin existed for - i.e. abstracting subscribe on many channels and automatically resubscribe on them. With new client you can have one global connection to Centrifugo and subscribe on channels at any moment from any part of your javascript code.

Also we updated examples to fit new changes.

If you are searching for old API docs (centrifuge-js <= 1.2.0) - you can find it here

1.2.0

  • use exponential backoff when reconnecting
  • follow disconnect advice from Centrifugo

1.1.0

  • support for recover option (introduced in Centrifugo v1.2.0)
  • fix removing subscription when unsubscribing from channel

1.0.0

One backwards incompatible change here. Centrifuge-js now sends JSON (application/json) request instead of application/x-www-form-urlencoded when client wants to subscribe on private channel. See in docs how to deal with JSON in this case.

  • send JSON instead of form when subscribing on private channel.
  • simple reconnect strategy

0.9.0

The only change in 0.9.0 is changing private channel request POST parameter name channels to channels[]. If you are using private channels then you should update your backend code to fit new parameter name. This change was required because of how PHP and Ruby on Rails handle POST parameter names when POST request contains multiple values for the same parameter name.

  • channels parameter renamed to channels[] in private subscription POST request to application.

0.8.0

  • Support SockJS 1.0. Use transports instead of protocols_whitelist.
  • auto detect connection endpoint when url without endpoint path provided
  • properly handle auth request failure