diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7e6a06d..0f8a08a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,32 @@
+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. 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:
+
+```javascript
+import Centrifuge from 'centrifuge/build/protobuf';
+
+const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket", {
+ protocol: 'protobuf'
+});
+```
+
+Now this simplifies to:
+
+```javascript
+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](https://github.com/centrifugal/centrifuge-js#protobuf-support) for more information about using Protobuf client and constructing binary payloads.
+
4.1.0
=====
diff --git a/README.md b/README.md
index 962d06b2..4d7d4ae0 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
-This SDK provides a client to connect to [Centrifugo](https://github.com/centrifugal/centrifugo) or any [Centrifuge-based](https://github.com/centrifugal/centrifuge) server using pure WebSocket or one of the fallback transports from web browser, ReactNative, or NodeJS environments.
+This SDK provides a client to connect to [Centrifugo](https://github.com/centrifugal/centrifugo) or any [Centrifuge-based](https://github.com/centrifugal/centrifuge) server using pure WebSocket or one of the alternative transports (HTTP-streaming, SSE/EventSource, experimental WebTransport) from web browser, ReactNative, or NodeJS environments.
-The client behaves according to a common [Centrifigo SDK spec](https://centrifugal.dev/docs/transports/client_api). 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`.
+> [!IMPORTANT]
+> This library behaves according to a common [Centrifigo SDK spec](https://centrifugal.dev/docs/transports/client_api). 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](https://centrifugal.dev/docs/transports/client_sdk#sdk-feature-matrix).
-> **`centrifuge-js` v4.x is compatible with [Centrifugo](https://github.com/centrifugal/centrifugo) server v4 and v5 and [Centrifuge](https://github.com/centrifugal/centrifuge) >= 0.25.0. For Centrifugo v2, Centrifugo v3 and Centrifuge < 0.25.0 you should use `centrifuge-js` v2.x.**
+> `centrifuge-js` v5.x is compatible with [Centrifugo](https://github.com/centrifugal/centrifugo) server v4 and v5 and [Centrifuge](https://github.com/centrifugal/centrifuge) >= 0.25.0. For Centrifugo v2, Centrifugo v3 and Centrifuge < 0.25.0 you should use `centrifuge-js` v2.x.
* [Install](#install)
* [Quick start](#quick-start)
@@ -41,13 +42,13 @@ And then in your project:
import { Centrifuge } from 'centrifuge';
```
-In browser, you can import SDK from CDN (replace `4.0.0` with a concrete version number you want to use, see [releases](https://github.com/centrifugal/centrifuge-js/releases)):
+In browser, you can import SDK from CDN (replace `5.0.0` with a concrete version number you want to use, see [releases](https://github.com/centrifugal/centrifuge-js/releases)):
```html
-
+
```
-See also [centrifuge-js on cdnjs](https://cdnjs.com/libraries/centrifuge). Note that `centrifuge-js` browser builds target [ES6](https://caniuse.com/es6) at this point.
+See also [centrifuge-js on cdnjs](https://cdnjs.com/libraries/centrifuge). Note that `centrifuge-js` browser builds target [ES6](https://caniuse.com/es6).
**By default, library works with JSON only**, if you want to send binary payloads go to [Protobuf support](#protobuf-support) section to see how to import client with Protobuf support.
@@ -142,7 +143,7 @@ If you want to use SockJS you must also import SockJS client before centrifuge.j
```html
-
+
```
Or provide it explicitly as a dependency:
@@ -243,7 +244,7 @@ centrifuge.publish("channel", {"input": "hello"}).then(function(res) {
#### send method
-This is only valid for Centrifuge library and does not work for Centrifugo server at the moment. `send` method allows sending asynchronous message from a client to a server.
+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.
```javascript
centrifuge.send({"input": "hello"}).then(function(res) {
@@ -342,6 +343,8 @@ If the token sets connection expiration then the client SDK will keep the token
An example of possible `getToken` function implementation:
```javascript
+import { Centrifuge, UnauthorizedError } from 'centrifuge';
+
async function getToken() {
if (!loggedIn) {
return "";
@@ -350,7 +353,7 @@ async function getToken() {
if (!res.ok) {
if (res.status === 403) {
// Return special error to not proceed with token refreshes, client will be disconnected.
- throw new Centrifuge.UnauthorizedError();
+ throw new UnauthorizedError();
}
// Any other error thrown will result into token refresh re-attempts.
throw new Error(`Unexpected status code ${res.status}`);
@@ -548,6 +551,8 @@ If token sets subscription expiration client SDK will keep token refreshed. It d
An example:
```javascript
+import { Centrifuge, UnauthorizedError } from 'centrifuge';
+
async function getToken(ctx) {
// ctx argument has a channel.
const res = await fetch('/centrifuge/subscription_token', {
@@ -558,7 +563,7 @@ async function getToken(ctx) {
if (!res.ok) {
if (res.status === 403) {
// Return special error to not proceed with token refreshes, subscription will be unsubscribed.
- throw new Centrifuge.UnauthorizedError();
+ throw new UnauthorizedError();
}
// Any other error thrown will result into token refresh re-attempts.
throw new Error(`Unexpected status code ${res.status}`);
@@ -626,7 +631,51 @@ This call will flush all collected commands to a network.
## Server-side subscriptions
-TODO.
+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](https://centrifugal.dev/docs/server/server_subs) (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:
+
+```javascript
+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
@@ -652,10 +701,6 @@ When client disconnected from a server it will automatically try to reconnect us
`maxServerPingDelay` sets the maximum delay of server pings after which connection is considered broken and client reconnects. In milliseconds. Default is `10000`.
-### protocol
-
-By default, client works using `json` protocol. If you want to use binary transfer with Protobuf-based protocol this option must be set to `protobuf`. See more details about Protobuf communication in a special chapter.
-
### token
Set initial connection token.
@@ -690,29 +735,21 @@ Timeout for operations in milliseconds.
## Protobuf support
-To import client with Protobuf protocol support:
+To import client which uses Protobuf protocol under the hood:
```html
-
+
```
Or if you are developing with npm:
```javascript
-import Centrifuge from 'centrifuge/build/protobuf';
+import { Centrifuge } from 'centrifuge/build/protobuf';
```
This client uses [protobuf.js](https://github.com/dcodeIO/ProtoBuf.js/) under the hood.
-To enable binary websocket add `protocol: 'protobuf'` option to Centrifuge configuration options:
-
-```javascript
-const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket", {
- protocol: 'protobuf'
-});
-```
-
-When running with Protobuf protocol, 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:
+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:
```javascript
const data = new TextEncoder("utf-8").encode(JSON.stringify({"any": "data"}));
@@ -732,8 +769,8 @@ npm install ws
At this point you have 2 options. Explicitly pass WebSocket object to Centrifuge.
```javascript
-const { Centrifuge } = require('centrifuge');
-const WebSocket = require('ws');
+import { Centrifuge } from 'centrifuge';
+import WebSocket from 'ws';
var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
websocket: WebSocket
@@ -743,8 +780,10 @@ var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
Or define it globally:
```javascript
-const { Centrifuge } = require('centrifuge');
-global.WebSocket = require('ws');
+import { Centrifuge } from 'centrifuge';
+import WebSocket from 'ws';
+
+global.WebSocket = WebSocket;
const centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket');
```
diff --git a/fixup.sh b/fixup.sh
new file mode 100755
index 00000000..89b16d24
--- /dev/null
+++ b/fixup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+cat >build/protobuf/package.json < TypedEventEmitter, options?: Partial) {
super();
@@ -1833,3 +1837,7 @@ export class Centrifuge extends (EventEmitter as new () => TypedEventEmitter {
/** Client events which can be emitted. */
export type ClientEvents = {
+ /** called when client state changes */
state: (ctx: StateContext) => void;
+ /** called when client goes to connecting state */
connecting: (ctx: ConnectingContext) => void;
+ /** called when client goes to connected state */
connected: (ctx: ConnectedContext) => void;
+ /** called when client goes to disconnected state */
disconnected: (ctx: DisconnectedContext) => void;
// Async message coming from a server.
@@ -48,16 +52,23 @@ export enum State {
/** Events of Subscription. */
export type SubscriptionEvents = {
+ /** called when subscription state changes */
state: (ctx: SubscriptionStateContext) => void;
+ /** called when subscription state goes to subscribing */
subscribing: (ctx: SubscribingContext) => void;
+ /** called when subscription state goes to subscribed */
subscribed: (ctx: SubscribedContext) => void;
+ /** called when subscription state goes to unsubscribed */
unsubscribed: (ctx: UnsubscribedContext) => void;
+ /** called when publication from channel received */
publication: (ctx: PublicationContext) => void;
+ /** called when join event from channel received */
join: (ctx: JoinContext) => void;
+ /** called when leave event from channel received */
leave: (ctx: LeaveContext) => void;
- // listen to errors happening internally.
+ /** listen to subscription errors happening internally */
error: (ctx: SubscriptionErrorContext) => void;
}