Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare v5 release #252

Merged
merged 13 commits into from
Sep 12, 2023
Merged
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
=====

Expand Down
101 changes: 70 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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
<script src="https://unpkg.com/centrifuge@4.0.0/dist/centrifuge.js"></script>
<script src="https://unpkg.com/centrifuge@5.0.0/dist/centrifuge.js"></script>
```

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.

Expand Down Expand Up @@ -142,7 +143,7 @@ If you want to use SockJS you must also import SockJS client before centrifuge.j

```html
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/centrifuge@4.0.0/dist/centrifuge.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:
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 "";
Expand All @@ -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}`);
Expand Down Expand Up @@ -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', {
Expand All @@ -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}`);
Expand Down Expand Up @@ -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

Expand All @@ -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.
Expand Down Expand Up @@ -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
<script src="https://unpkg.com/centrifuge@4.0.0/dist/centrifuge.protobuf.js"></script>
<script src="https://unpkg.com/centrifuge@5.0.0/dist/centrifuge.protobuf.js"></script>
```

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"}));
Expand All @@ -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
Expand All @@ -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');
```
Expand Down
9 changes: 9 additions & 0 deletions fixup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

cat >build/protobuf/package.json <<!EOF
{
"main": "index.js",
"types": "index.d.ts",
"module": "index.mjs"
}
!EOF
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
{
"name": "centrifuge",
"version": "5.0.0-beta.1",
"version": "5.0.0-beta.3",
"description": "JavaScript client SDK for bidirectional communication with Centrifugo and Centrifuge-based server from browser, NodeJS and React Native",
"main": "build/index.js",
"types": "build/index.d.ts",
"module": "build/index.mjs",
"exports": {
".": {
"import": "./build/index.mjs",
"require": "./build/index.js",
"types": "./build/index.d.ts"
},
"./build/protobuf": {
"import": "./build/protobuf/index.mjs",
"require": "./build/protobuf/index.js",
"types": "./build/protobuf/index.d.ts"
}
},
"files": [
"dist/**",
"build/**"
Expand All @@ -13,13 +25,13 @@
"events": "events"
},
"scripts": {
"build": "rollup -c",
"build": "rollup -c && ./fixup.sh",
"prepare": "npm run build-all",
"lint": "eslint src/ --ext .js,.jsx,.ts,.tsx",
"test": "jest --detectOpenHandles --verbose",
"clean": "rm -rf dist build package",
"ts-node": "ts-node",
"docs": "typedoc --exclude '**/transport_*.ts' --exclude '**/*.test.ts' --exclude '**/*+(utils|json|codes|browser).ts' --excludePrivate --excludeInternal --entryPoints src/*.ts",
"docs": "typedoc --exclude '**/transport_*.ts' --exclude '**/*.test.ts' --exclude '**/*+(utils|json|protobuf.codec|codes|browser).ts' --excludePrivate --excludeInternal --entryPoints src/*.ts",
"build-all": "yarn clean && yarn build && yarn build-browser && yarn build-browser-protobuf",
"build-browser": "esbuild src/browser.ts --bundle --minify --sourcemap --outfile=dist/centrifuge.js",
"dev": "esbuild src/browser.ts --bundle --outfile=dist/centrifuge.js --servedir=dist/ --serve=2000",
Expand Down
19 changes: 7 additions & 12 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,22 @@ export default [
commonjs(),
del({
targets: [
'build/cjs/index.d.ts',
'build/esm/index.d.ts',
'build/cjs/transport_*.d.ts',
'build/esm/transport_*.d.ts',
'build/cjs/protobuf.codec.d.ts',
'build/esm/protobuf.codec.d.ts',
'build/cjs/json.d.ts',
'build/cjs/utils.d.ts',
'build/esm/json.d.ts',
'build/esm/utils.d.ts',
'build/protobuf/protobuf.d.ts',
'build/protobuf/transport_*.d.ts',
'build/protobuf/protobuf.codec.d.ts',
'build/protobuf/json.d.ts',
'build/protobuf/utils.d.ts',
],
hook: 'writeBundle'
}),
],
output: [
{
file: 'build/cjs/protobuf.js',
file: 'build/protobuf/index.js',
format: 'cjs',
},
{
file: 'build/esm/protobuf.js',
file: 'build/protobuf/index.mjs',
format: 'es',
}
]
Expand Down
12 changes: 1 addition & 11 deletions src/browser.protobuf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,8 @@
* This file is the entrypoint of browser builds.
* The code executes when loaded in a browser.
*/
import { Centrifuge, UnauthorizedError } from './centrifuge';
import { Centrifuge } from './centrifuge';
import { ProtobufCodec } from './protobuf.codec';
import {
State, SubscriptionState,
} from './types';

// @ts-ignore – required for browser build.
Centrifuge.SubscriptionState = SubscriptionState;
// @ts-ignore – need for browser build.
Centrifuge.State = State
// @ts-ignore – need for browser build.
Centrifuge.UnauthorizedError = UnauthorizedError;

export default class CentrifugeProtobuf extends Centrifuge {
protected _formatOverride() {
Expand Down
12 changes: 1 addition & 11 deletions src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
/**
* This file is the entrypoint of browser builds.
*/
import { Centrifuge, UnauthorizedError } from './centrifuge'
import {
State, SubscriptionState,
} from './types';

// @ts-ignore – need for browser build.
Centrifuge.SubscriptionState = SubscriptionState;
// @ts-ignore – need for browser build.
Centrifuge.State = State
// @ts-ignore – need for browser build.
Centrifuge.UnauthorizedError = UnauthorizedError;
import { Centrifuge } from './centrifuge'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).Centrifuge = Centrifuge
Loading