centrifuge 5.3.1 → 5.3.3

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
@@ -27,6 +27,7 @@ The features implemented by this SDK can be found in [SDK feature matrix](https:
27
27
  * [Protobuf support](#protobuf-support)
28
28
  * [Using with NodeJS](#using-with-nodejs)
29
29
  * [Custom WebSocket constructor](#custom-websocket-constructor)
30
+ * [Using with React Native on Android](#using-with-react-native-on-android)
30
31
  * [Run tests locally](#run-tests-locally)
31
32
 
32
33
  ## Install
@@ -817,6 +818,10 @@ var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
817
818
 
818
819
  See a basic example with React Native where this technique is used [in this comment](https://github.com/centrifugal/centrifuge-js/issues/224#issuecomment-1538820023).
819
820
 
821
+ ## Using with React Native on Android
822
+
823
+ If you have issues with the connection on Android when using React Native – [check out this comment](https://github.com/centrifugal/centrifuge-js/issues/242#issuecomment-2569474401) – you may be using non-secure endpoint schemes and need to explicitly allow it.
824
+
820
825
  ## Run tests locally
821
826
 
822
827
  If you want to run `centrifuge-js` tests locally, start test Centrifugo server:
@@ -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 || this._inflight) {
916
- return null;
908
+ _handleTokenResponse(token) {
909
+ if (!this._isSubscribing()) {
910
+ this._inflight = false;
911
+ return;
917
912
  }
918
- this._inflight = true;
919
- const channel = this.channel;
920
- const req = {
921
- channel: channel
922
- };
923
- if (token) {
924
- req.token = token;
913
+ if (!token) {
914
+ this._inflight = false;
915
+ this._failUnauthorized();
916
+ return;
925
917
  }
926
- if (this._data) {
927
- req.data = this._data;
918
+ this._token = token;
919
+ if (this._getData) {
920
+ this._getDataAndSubscribe(token);
928
921
  }
929
- if (this._positioned) {
930
- req.positioned = true;
922
+ else {
923
+ this._sendSubscribe(token);
931
924
  }
932
- if (this._recoverable) {
933
- req.recoverable = true;
925
+ }
926
+ _handleTokenError(error) {
927
+ if (!this._isSubscribing()) {
928
+ this._inflight = false;
929
+ return;
934
930
  }
935
- if (this._joinLeave) {
936
- req.join_leave = true;
931
+ if (error instanceof UnauthorizedError) {
932
+ this._inflight = false;
933
+ this._failUnauthorized();
934
+ return;
937
935
  }
938
- if (this._needRecover()) {
939
- req.recover = true;
940
- const offset = this._getOffset();
941
- if (offset) {
942
- 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()) || ''
943
942
  }
944
- const epoch = this._getEpoch();
945
- if (epoch) {
946
- req.epoch = epoch;
947
- }
948
- }
949
- if (this._delta) {
950
- 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;
951
951
  }
952
- const cmd = { subscribe: req };
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;
@@ -1062,6 +1091,10 @@ class Subscription extends EventEmitter$1 {
1062
1091
  }
1063
1092
  }
1064
1093
  _scheduleResubscribe() {
1094
+ if (!this._isSubscribing()) {
1095
+ this._debug('not in subscribing state, skip resubscribe scheduling', this.channel);
1096
+ return;
1097
+ }
1065
1098
  const self = this;
1066
1099
  const delay = this._getResubscribeDelay();
1067
1100
  this._resubscribeTimeout = setTimeout(function () {
@@ -1069,6 +1102,7 @@ class Subscription extends EventEmitter$1 {
1069
1102
  self._subscribe();
1070
1103
  }
1071
1104
  }, delay);
1105
+ this._debug('resubscribe scheduled after ' + delay, this.channel);
1072
1106
  }
1073
1107
  _subscribeError(err) {
1074
1108
  if (!this._isSubscribing()) {
@@ -1167,8 +1201,7 @@ class Subscription extends EventEmitter$1 {
1167
1201
  }
1168
1202
  }
1169
1203
  _getSubscriptionToken() {
1170
- // @ts-ignore we are hiding some methods from public API autocompletion.
1171
- this._centrifuge._debug('get subscription token for channel', this.channel);
1204
+ this._debug('get subscription token for channel', this.channel);
1172
1205
  const ctx = {
1173
1206
  channel: this.channel
1174
1207
  };
@@ -1241,8 +1274,7 @@ class Subscription extends EventEmitter$1 {
1241
1274
  if (!this._isSubscribed()) {
1242
1275
  return;
1243
1276
  }
1244
- // @ts-ignore we are hiding some methods from public API autocompletion.
1245
- this._centrifuge._debug('subscription token refreshed, channel', this.channel);
1277
+ this._debug('subscription token refreshed, channel', this.channel);
1246
1278
  this._clearRefreshTimeout();
1247
1279
  if (result.expires === true) {
1248
1280
  this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));
@@ -1559,7 +1591,6 @@ class HttpStreamTransport {
1559
1591
  body: body,
1560
1592
  mode: 'cors',
1561
1593
  credentials: 'same-origin',
1562
- cache: 'no-cache'
1563
1594
  };
1564
1595
  fetchFunc(this.options.emulationEndpoint, fetchOptions);
1565
1596
  }
@@ -1644,7 +1675,6 @@ class SseTransport {
1644
1675
  body: body,
1645
1676
  mode: 'cors',
1646
1677
  credentials: 'same-origin',
1647
- cache: 'no-cache'
1648
1678
  };
1649
1679
  fetchFunc(this.options.emulationEndpoint, fetchOptions);
1650
1680
  }
@@ -2555,7 +2585,7 @@ class Centrifuge extends EventEmitter$1 {
2555
2585
  websocket: websocket
2556
2586
  });
2557
2587
  if (!this._transport.supported()) {
2558
- throw new Error('WebSocket not available');
2588
+ throw new Error('WebSocket constructor not found, make sure it is available globally or passed as a dependency in Centrifuge options');
2559
2589
  }
2560
2590
  }
2561
2591
  }
@@ -2804,24 +2834,25 @@ class Centrifuge extends EventEmitter$1 {
2804
2834
  return;
2805
2835
  }
2806
2836
  this._reconnecting = true;
2807
- const self = this;
2808
2837
  const emptyToken = this._token === '';
2809
2838
  const needTokenRefresh = this._refreshRequired || (emptyToken && this._config.getToken !== null);
2810
2839
  if (!needTokenRefresh) {
2811
2840
  if (this._config.getData) {
2812
- this._config.getData().then(function (data) {
2813
- if (!self._isConnecting()) {
2841
+ this._config.getData().then(data => {
2842
+ if (!this._isConnecting()) {
2814
2843
  return;
2815
2844
  }
2816
- self._data = data;
2817
- self._initializeTransport();
2818
- });
2845
+ this._data = data;
2846
+ this._initializeTransport();
2847
+ })
2848
+ .catch(e => this._handleGetDataError(e));
2819
2849
  }
2820
2850
  else {
2821
2851
  this._initializeTransport();
2822
2852
  }
2823
2853
  return;
2824
2854
  }
2855
+ const self = this;
2825
2856
  this._getToken().then(function (token) {
2826
2857
  if (!self._isConnecting()) {
2827
2858
  return;
@@ -2839,7 +2870,8 @@ class Centrifuge extends EventEmitter$1 {
2839
2870
  }
2840
2871
  self._data = data;
2841
2872
  self._initializeTransport();
2842
- });
2873
+ })
2874
+ .catch(e => self._handleGetDataError(e));
2843
2875
  }
2844
2876
  else {
2845
2877
  self._initializeTransport();
@@ -2860,13 +2892,32 @@ class Centrifuge extends EventEmitter$1 {
2860
2892
  }
2861
2893
  });
2862
2894
  const delay = self._getReconnectDelay();
2863
- self._debug('error on connection token refresh, reconnect after ' + delay + ' milliseconds', e);
2895
+ self._debug('error on getting connection token, reconnect after ' + delay + ' milliseconds', e);
2864
2896
  self._reconnecting = false;
2865
2897
  self._reconnectTimeout = setTimeout(() => {
2866
2898
  self._startReconnecting();
2867
2899
  }, delay);
2868
2900
  });
2869
2901
  }
2902
+ _handleGetDataError(e) {
2903
+ if (e instanceof UnauthorizedError) {
2904
+ this._failUnauthorized();
2905
+ return;
2906
+ }
2907
+ this.emit('error', {
2908
+ type: 'connectData',
2909
+ error: {
2910
+ code: exports.errorCodes.badConfiguration,
2911
+ message: (e === null || e === void 0 ? void 0 : e.toString()) || ''
2912
+ }
2913
+ });
2914
+ const delay = this._getReconnectDelay();
2915
+ this._debug('error on getting connect data, reconnect after ' + delay + ' milliseconds', e);
2916
+ this._reconnecting = false;
2917
+ this._reconnectTimeout = setTimeout(() => {
2918
+ this._startReconnecting();
2919
+ }, delay);
2920
+ }
2870
2921
  _connectError(err) {
2871
2922
  if (this.state !== exports.State.Connecting) {
2872
2923
  return;