centrifuge 5.3.0 → 5.3.2

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
@@ -5,7 +5,7 @@ This SDK provides a client to connect to [Centrifugo](https://github.com/centrif
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
 
8
- > `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.
8
+ > `centrifuge-js` v5.x is compatible with [Centrifugo](https://github.com/centrifugal/centrifugo) server v6, v5 and v4, 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.
9
9
 
10
10
  * [Install](#install)
11
11
  * [Quick start](#quick-start)
@@ -131,14 +131,14 @@ Supported transports are:
131
131
  * `websocket`
132
132
  * `http_stream`
133
133
  * `sse`
134
- * `sockjs` - SockJS can also be used as a fallback, SockJS is currently in DEPRECATED status in Centrifugal ecosystem. Also, sticky sessions must be used on the backend in distributed case with it. See more details below
134
+ * `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
135
135
  * `webtransport` - this SDK also supports WebTransport in experimental form. See details below
136
136
 
137
137
  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.
138
138
 
139
139
  ### Using SockJS
140
140
 
141
- **SockJS usage is DEPRECATED in the Centrifugal ecosystem**
141
+ **SockJS usage is DEPRECATED**. Its support was removed in Centrifugo v6, and it will also be removed from this SDK in v6 release.
142
142
 
143
143
  If you want to use SockJS you must also import SockJS client before centrifuge.js
144
144
 
@@ -112,6 +112,7 @@ export declare class Centrifuge extends Centrifuge_base {
112
112
  private _initializeTransport;
113
113
  private _sendConnect;
114
114
  private _startReconnecting;
115
+ private _handleGetDataError;
115
116
  private _connectError;
116
117
  private _scheduleReconnect;
117
118
  private _constructConnectCommand;
package/build/index.js CHANGED
@@ -651,12 +651,10 @@ class Subscription extends EventEmitter$1 {
651
651
  // @ts-ignore – we are hiding some symbols from public API autocompletion.
652
652
  if (this._centrifuge._debugEnabled) {
653
653
  this.on('state', (ctx) => {
654
- // @ts-ignore we are hiding some symbols from public API autocompletion.
655
- this._centrifuge._debug('subscription state', channel, ctx.oldState, '->', ctx.newState);
654
+ this._debug('subscription state', channel, ctx.oldState, '->', ctx.newState);
656
655
  });
657
656
  this.on('error', (ctx) => {
658
- // @ts-ignore we are hiding some symbols from public API autocompletion.
659
- this._centrifuge._debug('subscription error', channel, ctx);
657
+ this._debug('subscription error', channel, ctx);
660
658
  });
661
659
  }
662
660
  else {
@@ -837,119 +835,121 @@ class Subscription extends EventEmitter$1 {
837
835
  });
838
836
  }
839
837
  _subscribe() {
838
+ this._debug('subscribing on', this.channel);
839
+ if (!this._isTransportOpen()) {
840
+ this._debug('delay subscribe on', this.channel, 'till connected');
841
+ return null;
842
+ }
843
+ if (this._inflight) {
844
+ return null;
845
+ }
846
+ this._inflight = true;
847
+ if (this._canSubscribeWithoutGettingToken()) {
848
+ return this._subscribeWithoutToken();
849
+ }
850
+ this._getSubscriptionToken()
851
+ .then(token => this._handleTokenResponse(token))
852
+ .catch(e => this._handleTokenError(e));
853
+ return null;
854
+ }
855
+ _isTransportOpen() {
840
856
  // @ts-ignore – we are hiding some symbols from public API autocompletion.
841
- this._centrifuge._debug('subscribing on', this.channel);
842
- // need to check transport readiness here, because there's no point for calling getData or getToken
843
- // if transport is not ready yet
844
- // @ts-ignore we are hiding some symbols from public API autocompletion.
845
- if (!this._centrifuge._transportIsOpen) {
846
- // @ts-ignore – we are hiding some symbols from public API autocompletion.
847
- this._centrifuge._debug('delay subscribe on', this.channel, 'till connected');
848
- // subscribe will be called later automatically.
857
+ return this._centrifuge._transportIsOpen;
858
+ }
859
+ _canSubscribeWithoutGettingToken() {
860
+ return !this._usesToken() || !!this._token;
861
+ }
862
+ _subscribeWithoutToken() {
863
+ if (this._getData) {
864
+ this._getDataAndSubscribe(this._token);
849
865
  return null;
850
866
  }
851
- const self = this;
852
- const getDataCtx = {
853
- channel: self.channel
854
- };
855
- if (!this._usesToken() || this._token) {
856
- if (self._getData) {
857
- self._getData(getDataCtx).then(function (data) {
858
- if (!self._isSubscribing()) {
859
- return;
860
- }
861
- self._data = data;
862
- self._sendSubscribe(self._token);
863
- });
864
- return null;
865
- }
866
- else {
867
- return self._sendSubscribe(self._token);
868
- }
867
+ else {
868
+ return this._sendSubscribe(this._token);
869
869
  }
870
- this._getSubscriptionToken().then(function (token) {
871
- if (!self._isSubscribing()) {
872
- return;
873
- }
874
- if (!token) {
875
- self._failUnauthorized();
876
- return;
877
- }
878
- self._token = token;
879
- if (self._getData) {
880
- self._getData(getDataCtx).then(function (data) {
881
- if (!self._isSubscribing()) {
882
- return;
883
- }
884
- self._data = data;
885
- self._sendSubscribe(token);
886
- });
887
- }
888
- else {
889
- self._sendSubscribe(token);
890
- }
891
- }).catch(function (e) {
892
- if (!self._isSubscribing()) {
870
+ }
871
+ _getDataAndSubscribe(token) {
872
+ if (!this._getData) {
873
+ this._inflight = false;
874
+ return;
875
+ }
876
+ this._getData({ channel: this.channel })
877
+ .then(data => {
878
+ if (!this._isSubscribing()) {
879
+ this._inflight = false;
893
880
  return;
894
881
  }
895
- if (e instanceof UnauthorizedError) {
896
- self._failUnauthorized();
897
- return;
882
+ this._data = data;
883
+ this._sendSubscribe(token);
884
+ })
885
+ .catch(e => this._handleGetDataError(e));
886
+ }
887
+ _handleGetDataError(error) {
888
+ if (!this._isSubscribing()) {
889
+ this._inflight = false;
890
+ return;
891
+ }
892
+ if (error instanceof UnauthorizedError) {
893
+ this._inflight = false;
894
+ this._failUnauthorized();
895
+ return;
896
+ }
897
+ this.emit('error', {
898
+ type: 'subscribeData',
899
+ channel: this.channel,
900
+ error: {
901
+ code: exports.errorCodes.badConfiguration,
902
+ message: (error === null || error === void 0 ? void 0 : error.toString()) || ''
898
903
  }
899
- self.emit('error', {
900
- type: 'subscribeToken',
901
- channel: self.channel,
902
- error: {
903
- code: exports.errorCodes.subscriptionSubscribeToken,
904
- message: e !== undefined ? e.toString() : ''
905
- }
906
- });
907
- self._scheduleResubscribe();
908
904
  });
909
- return null;
905
+ this._inflight = false;
906
+ this._scheduleResubscribe();
910
907
  }
911
- _sendSubscribe(token) {
912
- // we also need to check for transport state before sending subscription
913
- // because it may change for subscription with side effects (getData, getToken options)
914
- // @ts-ignore – we are hiding some symbols from public API autocompletion.
915
- if (!this._centrifuge._transportIsOpen) {
916
- return null;
908
+ _handleTokenResponse(token) {
909
+ if (!this._isSubscribing()) {
910
+ this._inflight = false;
911
+ return;
917
912
  }
918
- const channel = this.channel;
919
- const req = {
920
- channel: channel
921
- };
922
- if (token) {
923
- req.token = token;
913
+ if (!token) {
914
+ this._inflight = false;
915
+ this._failUnauthorized();
916
+ return;
924
917
  }
925
- if (this._data) {
926
- req.data = this._data;
918
+ this._token = token;
919
+ if (this._getData) {
920
+ this._getDataAndSubscribe(token);
927
921
  }
928
- if (this._positioned) {
929
- req.positioned = true;
922
+ else {
923
+ this._sendSubscribe(token);
930
924
  }
931
- if (this._recoverable) {
932
- req.recoverable = true;
925
+ }
926
+ _handleTokenError(error) {
927
+ if (!this._isSubscribing()) {
928
+ this._inflight = false;
929
+ return;
933
930
  }
934
- if (this._joinLeave) {
935
- req.join_leave = true;
931
+ if (error instanceof UnauthorizedError) {
932
+ this._inflight = false;
933
+ this._failUnauthorized();
934
+ return;
936
935
  }
937
- if (this._needRecover()) {
938
- req.recover = true;
939
- const offset = this._getOffset();
940
- if (offset) {
941
- req.offset = offset;
936
+ this.emit('error', {
937
+ type: 'subscribeToken',
938
+ channel: this.channel,
939
+ error: {
940
+ code: exports.errorCodes.subscriptionSubscribeToken,
941
+ message: (error === null || error === void 0 ? void 0 : error.toString()) || ''
942
942
  }
943
- const epoch = this._getEpoch();
944
- if (epoch) {
945
- req.epoch = epoch;
946
- }
947
- }
948
- if (this._delta) {
949
- req.delta = this._delta;
943
+ });
944
+ this._inflight = false;
945
+ this._scheduleResubscribe();
946
+ }
947
+ _sendSubscribe(token) {
948
+ if (!this._isTransportOpen()) {
949
+ this._inflight = false;
950
+ return null;
950
951
  }
951
- const cmd = { subscribe: req };
952
- this._inflight = true;
952
+ const cmd = this._buildSubscribeCommand(token);
953
953
  // @ts-ignore – we are hiding some symbols from public API autocompletion.
954
954
  this._centrifuge._call(cmd).then(resolveCtx => {
955
955
  this._inflight = false;
@@ -970,6 +970,35 @@ class Subscription extends EventEmitter$1 {
970
970
  });
971
971
  return cmd;
972
972
  }
973
+ _buildSubscribeCommand(token) {
974
+ const req = { channel: this.channel };
975
+ if (token)
976
+ req.token = token;
977
+ if (this._data)
978
+ req.data = this._data;
979
+ if (this._positioned)
980
+ req.positioned = true;
981
+ if (this._recoverable)
982
+ req.recoverable = true;
983
+ if (this._joinLeave)
984
+ req.join_leave = true;
985
+ if (this._needRecover()) {
986
+ req.recover = true;
987
+ const offset = this._getOffset();
988
+ if (offset)
989
+ req.offset = offset;
990
+ const epoch = this._getEpoch();
991
+ if (epoch)
992
+ req.epoch = epoch;
993
+ }
994
+ if (this._delta)
995
+ req.delta = this._delta;
996
+ return { subscribe: req };
997
+ }
998
+ _debug(...args) {
999
+ // @ts-ignore – we are hiding some symbols from public API autocompletion.
1000
+ this._centrifuge._debug(...args);
1001
+ }
973
1002
  _handleSubscribeError(error) {
974
1003
  if (!this._isSubscribing()) {
975
1004
  return;
@@ -1006,6 +1035,7 @@ class Subscription extends EventEmitter$1 {
1006
1035
  }
1007
1036
  this._clearSubscribingState();
1008
1037
  }
1038
+ this._inflight = false;
1009
1039
  if (this._setState(exports.SubscriptionState.Unsubscribed)) {
1010
1040
  this.emit('unsubscribed', { channel: this.channel, code: code, reason: reason });
1011
1041
  }
@@ -1061,6 +1091,10 @@ class Subscription extends EventEmitter$1 {
1061
1091
  }
1062
1092
  }
1063
1093
  _scheduleResubscribe() {
1094
+ if (!this._isSubscribing()) {
1095
+ this._debug('not in subscribing state, skip resubscribe scheduling', this.channel);
1096
+ return;
1097
+ }
1064
1098
  const self = this;
1065
1099
  const delay = this._getResubscribeDelay();
1066
1100
  this._resubscribeTimeout = setTimeout(function () {
@@ -1068,6 +1102,7 @@ class Subscription extends EventEmitter$1 {
1068
1102
  self._subscribe();
1069
1103
  }
1070
1104
  }, delay);
1105
+ this._debug('resubscribe scheduled after ' + delay, this.channel);
1071
1106
  }
1072
1107
  _subscribeError(err) {
1073
1108
  if (!this._isSubscribing()) {
@@ -1166,8 +1201,7 @@ class Subscription extends EventEmitter$1 {
1166
1201
  }
1167
1202
  }
1168
1203
  _getSubscriptionToken() {
1169
- // @ts-ignore we are hiding some methods from public API autocompletion.
1170
- this._centrifuge._debug('get subscription token for channel', this.channel);
1204
+ this._debug('get subscription token for channel', this.channel);
1171
1205
  const ctx = {
1172
1206
  channel: this.channel
1173
1207
  };
@@ -1240,8 +1274,7 @@ class Subscription extends EventEmitter$1 {
1240
1274
  if (!this._isSubscribed()) {
1241
1275
  return;
1242
1276
  }
1243
- // @ts-ignore we are hiding some methods from public API autocompletion.
1244
- this._centrifuge._debug('subscription token refreshed, channel', this.channel);
1277
+ this._debug('subscription token refreshed, channel', this.channel);
1245
1278
  this._clearRefreshTimeout();
1246
1279
  if (result.expires === true) {
1247
1280
  this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));
@@ -2803,24 +2836,25 @@ class Centrifuge extends EventEmitter$1 {
2803
2836
  return;
2804
2837
  }
2805
2838
  this._reconnecting = true;
2806
- const self = this;
2807
2839
  const emptyToken = this._token === '';
2808
2840
  const needTokenRefresh = this._refreshRequired || (emptyToken && this._config.getToken !== null);
2809
2841
  if (!needTokenRefresh) {
2810
2842
  if (this._config.getData) {
2811
- this._config.getData().then(function (data) {
2812
- if (!self._isConnecting()) {
2843
+ this._config.getData().then(data => {
2844
+ if (!this._isConnecting()) {
2813
2845
  return;
2814
2846
  }
2815
- self._data = data;
2816
- self._initializeTransport();
2817
- });
2847
+ this._data = data;
2848
+ this._initializeTransport();
2849
+ })
2850
+ .catch(e => this._handleGetDataError(e));
2818
2851
  }
2819
2852
  else {
2820
2853
  this._initializeTransport();
2821
2854
  }
2822
2855
  return;
2823
2856
  }
2857
+ const self = this;
2824
2858
  this._getToken().then(function (token) {
2825
2859
  if (!self._isConnecting()) {
2826
2860
  return;
@@ -2838,7 +2872,8 @@ class Centrifuge extends EventEmitter$1 {
2838
2872
  }
2839
2873
  self._data = data;
2840
2874
  self._initializeTransport();
2841
- });
2875
+ })
2876
+ .catch(e => self._handleGetDataError(e));
2842
2877
  }
2843
2878
  else {
2844
2879
  self._initializeTransport();
@@ -2859,13 +2894,32 @@ class Centrifuge extends EventEmitter$1 {
2859
2894
  }
2860
2895
  });
2861
2896
  const delay = self._getReconnectDelay();
2862
- self._debug('error on connection token refresh, reconnect after ' + delay + ' milliseconds', e);
2897
+ self._debug('error on getting connection token, reconnect after ' + delay + ' milliseconds', e);
2863
2898
  self._reconnecting = false;
2864
2899
  self._reconnectTimeout = setTimeout(() => {
2865
2900
  self._startReconnecting();
2866
2901
  }, delay);
2867
2902
  });
2868
2903
  }
2904
+ _handleGetDataError(e) {
2905
+ if (e instanceof UnauthorizedError) {
2906
+ this._failUnauthorized();
2907
+ return;
2908
+ }
2909
+ this.emit('error', {
2910
+ type: 'connectData',
2911
+ error: {
2912
+ code: exports.errorCodes.badConfiguration,
2913
+ message: (e === null || e === void 0 ? void 0 : e.toString()) || ''
2914
+ }
2915
+ });
2916
+ const delay = this._getReconnectDelay();
2917
+ this._debug('error on getting connect data, reconnect after ' + delay + ' milliseconds', e);
2918
+ this._reconnecting = false;
2919
+ this._reconnectTimeout = setTimeout(() => {
2920
+ this._startReconnecting();
2921
+ }, delay);
2922
+ }
2869
2923
  _connectError(err) {
2870
2924
  if (this.state !== exports.State.Connecting) {
2871
2925
  return;