centrifuge 5.5.2 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  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.
2
2
 
3
3
  > [!IMPORTANT]
4
- > 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`.
4
+ > This library behaves according to a common [Centrifugo 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`.
5
5
 
6
6
  The features implemented by this SDK can be found in [SDK feature matrix](https://centrifugal.dev/docs/transports/client_sdk#sdk-feature-matrix).
7
7
 
@@ -23,6 +23,9 @@ The features implemented by this SDK can be found in [SDK feature matrix](https:
23
23
  * [Subscription token](#subscription-token)
24
24
  * [Subscription options](#subscription-options)
25
25
  * [Subscription management API](#subscription-management-api)
26
+ * [Stream subscriptions with `getState`](#stream-subscriptions-with-getstate)
27
+ * [Map subscriptions (experimental)](#map-subscriptions-experimental)
28
+ * [Shared poll subscriptions (experimental)](#shared-poll-subscriptions-experimental)
26
29
  * [Message batching](#message-batching)
27
30
  * [Server-side subscriptions](#server-side-subscriptions)
28
31
  * [Protobuf support](#protobuf-support)
@@ -46,13 +49,13 @@ And then in your project:
46
49
  import { Centrifuge } from 'centrifuge';
47
50
  ```
48
51
 
49
- 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)):
52
+ In browser, you can import SDK from [unpkg](https://app.unpkg.com/centrifuge@latest) CDN (replace `5.0.0` with a concrete version number you want to use, see [releases](https://github.com/centrifugal/centrifuge-js/releases)):
50
53
 
51
54
  ```html
52
55
  <script src="https://unpkg.com/centrifuge@5.0.0/dist/centrifuge.js"></script>
53
56
  ```
54
57
 
55
- See also [centrifuge-js on cdnjs](https://cdnjs.com/libraries/centrifuge). Note that `centrifuge-js` browser builds target [ES6](https://caniuse.com/es6).
58
+ See also [centrifuge-js on jsdelivr](https://www.jsdelivr.com/package/npm/centrifuge). Note that `centrifuge-js` browser builds target [ES6](https://caniuse.com/es6).
56
59
 
57
60
  **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.
58
61
 
@@ -850,6 +853,56 @@ removeSubscription allows removing Subcription from the internal registry.
850
853
 
851
854
  Get a map with all current client-side subscriptions registered in the client.
852
855
 
856
+ ## Stream subscriptions with `getState`
857
+
858
+ For positioned/recoverable stream channels, the SDK can call an app-supplied `getState` callback that loads the application's current state from its own source of truth (database, API, etc.) and returns the corresponding stream position. The SDK subscribes with recovery from that position, so any publications committed after the state was read arrive as `publication` events. This is the "app-owned state" pattern — Centrifugo delivers only change events, your database stays the canonical store.
859
+
860
+ The SDK invokes `getState`:
861
+
862
+ * on the initial subscribe (no saved position);
863
+ * on reconnect **only when server recovery fails** (server returns error 112 — unrecoverable position).
864
+
865
+ On a successful recovery, `getState` is **not** called — the SDK has a valid position and missed publications arrive as events.
866
+
867
+ Inside the callback, **read the stream position first, then read your data** so the position is a lower bound. Recovered publications may overlap data already loaded in `getState`; this is safe for idempotent updates, otherwise deduplicate by `offset`. See `SubscriptionOptions.getState` JSDoc for the full contract.
868
+
869
+ Requires **Centrifugo >= v6.8.0**.
870
+
871
+ References:
872
+
873
+ * Blog post — [Transactional publishing for stream subscriptions with PostgreSQL](https://centrifugal.dev/blog/2026/05/15/pg-stream-broker-benefits)
874
+ * Example — [pg_stream_broker kitchen orders demo](https://github.com/centrifugal/examples/tree/master/v6/pg_stream_broker)
875
+
876
+ ## Map subscriptions (experimental)
877
+
878
+ A **map subscription** delivers a real-time key-value collection whose lifecycle is managed by Centrifugo: clients receive a complete snapshot on subscribe, catch up on missed key changes after disconnects, and observe live per-key updates. Typical use cases include cursor positions, lobby members, feature flags, scoreboards, and per-key presence (`map_clients` / `map_users`).
879
+
880
+ Use `Centrifuge.newMapSubscription(channel, options?)` to create one. The variants `newMapClientsSubscription` and `newMapUsersSubscription` produce presence-style map subscriptions backed by `$clients:*` / `$users:*` channels. The returned `MapSubscription` emits a `sync` event whenever a fresh snapshot is delivered — on the initial subscribe, and again only when the SDK rebuilds state from scratch (e.g. after an unrecoverable position with the default `from_scratch` strategy). Every individual key change (set or remove) — both during live operation and on successful recovery after a disconnect — arrives as an `update` event; on successful recovery `sync` is suppressed because the application's existing snapshot is still valid. Call `publish(key, data)` / `remove(key)` to mutate.
881
+
882
+ > [!WARNING]
883
+ > Map subscriptions are **experimental** and require **Centrifugo >= v6.8.0**. The shape and behavior may change in a backwards-incompatible way in subsequent minor releases as the feature stabilizes.
884
+
885
+ References:
886
+
887
+ * Server docs — [Map subscriptions](https://centrifugal.dev/docs/server/map_subscriptions)
888
+ * PRO enhancements — [Map subscriptions (PRO)](https://centrifugal.dev/docs/pro/map_subscriptions)
889
+ * Blog series — Map subscriptions Part 1 (synchronized key-value state and presence) and Part 2 (PostgreSQL map broker with transactional publishing)
890
+
891
+ ## Shared poll subscriptions (experimental)
892
+
893
+ A **shared poll subscription** moves polling from clients to Centrifugo: clients register their interest in specific keys, and Centrifugo polls the backend once per configurable interval on behalf of everyone, fanning the changes back out. Backend load scales with the number of unique tracked items rather than the number of connected clients. Typical use cases include vote counts, prices, view counts, live scores, and configuration sync.
894
+
895
+ Use `Centrifuge.newSharedPollSubscription(channel, options?)`, then call `track(keys)` / `untrack(keys)` on the returned `SharedPollSubscription` to manage the interest set. Provide the `getSignature` callback in options to authorize tracked keys via per-key HMAC signatures (replayed on reconnect and refreshed on signature TTL). The subscription emits an `update` event per item whenever the backend reports a new version, including synthetic `removed: true` events when the server revokes a key.
896
+
897
+ > [!WARNING]
898
+ > Shared poll subscriptions are **experimental** and require **Centrifugo >= v6.8.0**. The shape and behavior may change in a backwards-incompatible way in subsequent minor releases as the feature stabilizes.
899
+
900
+ References:
901
+
902
+ * Server docs — [Shared poll subscriptions](https://centrifugal.dev/docs/server/shared_poll)
903
+ * PRO enhancements — [Shared poll (PRO)](https://centrifugal.dev/docs/pro/shared_poll)
904
+ * Blog post — [Shared poll subscriptions: O(unique items) polling with low-latency updates](https://centrifugal.dev/blog/2026/05/12/shared-poll-subscriptions)
905
+
853
906
  ## Message batching
854
907
 
855
908
  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.
@@ -1,5 +1,20 @@
1
- import { Subscription } from './subscription';
2
- import { State, Options, SubscriptionState, ClientEvents, TypedEventEmitter, RpcResult, SubscriptionOptions, HistoryOptions, HistoryResult, PublishResult, PresenceResult, PresenceStatsResult, TransportEndpoint } from './types';
1
+ import { Subscription, BaseSubscription as _BaseSubscription } from './subscription';
2
+ import { State, Options, SubscriptionState, ClientEvents, TypedEventEmitter, RpcResult, SubscriptionOptions, MapSubscriptionOptions, MapSubscriptionEvents, BaseSubscriptionEvents, SharedPollSubscriptionOptions, SharedPollSubscriptionEvents, SharedPollTrackItem, HistoryOptions, HistoryResult, PublishResult, PresenceResult, PresenceStatsResult, TransportEndpoint } from './types';
3
+ /** Common methods shared by all subscription types. */
4
+ type CommonSurface = Pick<_BaseSubscription, 'channel' | 'state' | 'type' | 'subscribe' | 'unsubscribe' | 'ready' | 'presence' | 'presenceStats' | 'setData' | 'deltaStats'>;
5
+ /** Common subscription surface — use for mixed-type registries. */
6
+ export type BaseSubscription = CommonSurface & TypedEventEmitter<BaseSubscriptionEvents>;
7
+ /** Map subscription: publish/remove + narrowed map events. */
8
+ export type MapSubscription = CommonSurface & Pick<_BaseSubscription, 'setTagsFilter'> & {
9
+ publish(key: string, data: any): Promise<PublishResult>;
10
+ remove(key: string): Promise<PublishResult>;
11
+ } & TypedEventEmitter<MapSubscriptionEvents>;
12
+ /** Shared poll subscription: track/untrack + narrowed shared poll events. */
13
+ export type SharedPollSubscription = CommonSurface & {
14
+ track(keysOrItems: string[] | SharedPollTrackItem[], signature?: string): void;
15
+ untrack(keys: string[]): void;
16
+ trackedKeys(): Set<string>;
17
+ } & TypedEventEmitter<SharedPollSubscriptionEvents>;
3
18
  export declare class UnauthorizedError extends Error {
4
19
  constructor(message: any);
5
20
  }
@@ -53,14 +68,57 @@ export declare class Centrifuge extends Centrifuge_base {
53
68
  * one subscription per channel per client this method throws if client already has
54
69
  * channel subscription in internal registry.
55
70
  * */
56
- newSubscription(channel: string, options?: Partial<SubscriptionOptions>): Subscription;
71
+ newSubscription(channel: string, options?: SubscriptionOptions): Subscription;
72
+ /** newMapSubscription allocates new map Subscription to a channel. Since server only allows
73
+ * one subscription per channel per client this method throws if client already has
74
+ * channel subscription in internal registry.
75
+ *
76
+ * Experimental. Requires Centrifugo >= v6.8.0. API may change in a backwards-incompatible
77
+ * way in subsequent minor releases. */
78
+ newMapSubscription(channel: string, options?: MapSubscriptionOptions): MapSubscription;
79
+ /** Create a map subscription for observing individual connections (clients presence).
80
+ * Each entry has key=clientId and contains full ClientInfo.
81
+ * Use this to track connections per channel.
82
+ * The channel should be the full presence channel name (e.g., "$clients:games").
83
+ *
84
+ * Experimental. Requires Centrifugo >= v6.8.0. API may change in a backwards-incompatible
85
+ * way in subsequent minor releases. */
86
+ newMapClientsSubscription(channel: string, options?: MapSubscriptionOptions): MapSubscription;
87
+ /** Create a map subscription for observing unique users (users presence).
88
+ * Each entry has key=userId (no ClientInfo stored).
89
+ * User entries expire via TTL, providing debounce for quick reconnects.
90
+ * The channel should be the full presence channel name (e.g., "$users:games").
91
+ *
92
+ * Experimental. Requires Centrifugo >= v6.8.0. API may change in a backwards-incompatible
93
+ * way in subsequent minor releases. */
94
+ newMapUsersSubscription(channel: string, options?: MapSubscriptionOptions): MapSubscription;
95
+ /** newSharedPollSubscription allocates a new shared poll Subscription to a channel.
96
+ * Shared poll subscriptions use server-side polling to aggregate interest sets
97
+ * and deliver periodic updates with version tracking. Track items after subscribing
98
+ * using the track() method on the returned Subscription.
99
+ *
100
+ * Experimental. Requires Centrifugo >= v6.8.0. API may change in a backwards-incompatible
101
+ * way in subsequent minor releases. */
102
+ newSharedPollSubscription(channel: string, options?: SharedPollSubscriptionOptions): SharedPollSubscription;
57
103
  /** getSubscription returns Subscription if it's registered in the internal
58
104
  * registry or null. */
59
105
  getSubscription(channel: string): Subscription | null;
106
+ /** Get a map subscription by channel. */
107
+ getMapSubscription(channel: string): MapSubscription | null;
108
+ /** Get a shared poll subscription by channel. */
109
+ getSharedPollSubscription(channel: string): SharedPollSubscription | null;
60
110
  /** removeSubscription allows removing Subcription from the internal registry. */
61
111
  removeSubscription(sub: Subscription | null): void;
112
+ /** Remove a map subscription. */
113
+ removeMapSubscription(sub: MapSubscription | null): void;
114
+ /** Remove a shared poll subscription. */
115
+ removeSharedPollSubscription(sub: SharedPollSubscription | null): void;
62
116
  /** Get a map with all current client-side subscriptions. */
63
117
  subscriptions(): Record<string, Subscription>;
118
+ /** Get all map subscriptions. */
119
+ mapSubscriptions(): Record<string, MapSubscription>;
120
+ /** Get all shared poll subscriptions. */
121
+ sharedPollSubscriptions(): Record<string, SharedPollSubscription>;
64
122
  /** ready returns a Promise which resolves upon client goes to Connected
65
123
  * state and rejects in case of client goes to Disconnected or Failed state.
66
124
  * Users can provide optional timeout in milliseconds. */
@@ -86,6 +144,17 @@ export declare class Centrifuge extends Centrifuge_base {
86
144
  rpc(method: string, data: any): Promise<RpcResult>;
87
145
  /** publish data to a channel. */
88
146
  publish(channel: string, data: any): Promise<PublishResult>;
147
+ /** Publish data to a key in a map channel without holding a MapSubscription.
148
+ * Use this when you need to write to a map channel from outside a subscription
149
+ * context (e.g. a standalone publisher). When you already hold a MapSubscription,
150
+ * prefer `sub.publish(key, data)` instead — it enforces the method-call guard and
151
+ * applies debounce configuration. */
152
+ mapPublish(channel: string, key: string, data: any): Promise<PublishResult>;
153
+ /** Remove a key from a map channel without holding a MapSubscription.
154
+ * Use this when you need to remove a key from outside a subscription context.
155
+ * When you already hold a MapSubscription, prefer `sub.remove(key)` instead —
156
+ * it enforces the method-call guard and cancels any pending debounced publish. */
157
+ mapRemove(channel: string, key: string): Promise<PublishResult>;
89
158
  /** history for a channel. By default it does not return publications (only current
90
159
  * StreamPosition data) – provide an explicit limit > 0 to load publications.*/
91
160
  history(channel: string, options?: HistoryOptions): Promise<HistoryResult>;
@@ -135,7 +204,7 @@ export declare class Centrifuge extends Centrifuge_base {
135
204
  private _getRefreshRetryDelay;
136
205
  private _refreshResponse;
137
206
  private _removeSubscription;
138
- protected _unsubscribe(sub: Subscription): Promise<void>;
207
+ protected _unsubscribe(sub: _BaseSubscription): Promise<void>;
139
208
  private _getSub;
140
209
  private _isServerSub;
141
210
  private _sendSubscribeCommands;
package/build/codes.d.ts CHANGED
@@ -10,7 +10,9 @@ export declare enum errorCodes {
10
10
  subscriptionRefreshToken = 9,
11
11
  transportWriteError = 10,
12
12
  connectionClosed = 11,
13
- badConfiguration = 12
13
+ badConfiguration = 12,
14
+ subscriptionGetState = 13,
15
+ sharedPollGetSignature = 14
14
16
  }
15
17
  export declare enum connectingCodes {
16
18
  connectCalled = 0,
@@ -35,5 +37,6 @@ export declare enum unsubscribedCodes {
35
37
  clientClosed = 2
36
38
  }
37
39
  export declare enum subscriptionFlags {
38
- channelCompaction = 1
40
+ channelCompaction = 1,
41
+ rejectUnrecovered = 2
39
42
  }
package/build/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Centrifuge, UnauthorizedError } from './centrifuge';
2
2
  import { Subscription } from './subscription';
3
+ export type { BaseSubscription, MapSubscription, SharedPollSubscription } from './centrifuge';
3
4
  export * from "./types";
4
5
  export * from "./codes";
5
- export { Centrifuge, UnauthorizedError, Subscription };
6
+ export { Centrifuge, UnauthorizedError, Subscription, };