pusher-js 7.3.0 → 7.4.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.
Files changed (44) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/.github/workflows/release_pr.yml +1 -1
  3. package/.github/workflows/run-tests.yml +2 -2
  4. package/.gitmodules +1 -1
  5. package/CHANGELOG.md +4 -0
  6. package/README.md +10 -30
  7. package/dist/node/pusher.js +127 -37
  8. package/dist/node/pusher.js.map +1 -1
  9. package/dist/react-native/pusher.js +2 -2
  10. package/dist/react-native/pusher.js.map +1 -1
  11. package/dist/web/pusher-with-encryption.js +127 -37
  12. package/dist/web/pusher-with-encryption.js.map +1 -1
  13. package/dist/web/pusher-with-encryption.min.js +2 -2
  14. package/dist/web/pusher-with-encryption.min.js.map +1 -1
  15. package/dist/web/pusher.js +127 -37
  16. package/dist/web/pusher.js.map +1 -1
  17. package/dist/web/pusher.min.js +2 -2
  18. package/dist/web/pusher.min.js.map +1 -1
  19. package/dist/worker/pusher-with-encryption.worker.js +127 -37
  20. package/dist/worker/pusher-with-encryption.worker.js.map +1 -1
  21. package/dist/worker/pusher-with-encryption.worker.min.js +2 -2
  22. package/dist/worker/pusher-with-encryption.worker.min.js.map +1 -1
  23. package/dist/worker/pusher.worker.js +127 -37
  24. package/dist/worker/pusher.worker.js.map +1 -1
  25. package/dist/worker/pusher.worker.min.js +2 -2
  26. package/dist/worker/pusher.worker.min.js.map +1 -1
  27. package/package.json +5 -4
  28. package/spec/javascripts/helpers/timers/promises.js +9 -0
  29. package/spec/javascripts/unit/core/channels/presence_channel_spec.js +85 -16
  30. package/spec/javascripts/unit/core/user_spec.js +13 -6
  31. package/src/core/channels/presence_channel.ts +21 -12
  32. package/src/core/http/http_socket.ts +3 -1
  33. package/src/core/pusher.ts +1 -1
  34. package/src/core/user.ts +65 -27
  35. package/src/core/utils/flat_promise.ts +10 -0
  36. package/src/runtimes/interface.ts +1 -0
  37. package/src/runtimes/node/runtime.ts +5 -0
  38. package/src/runtimes/react-native/runtime.ts +5 -0
  39. package/src/runtimes/web/runtime.ts +14 -0
  40. package/src/runtimes/worker/runtime.ts +14 -0
  41. package/types/src/core/strategies/transport_strategy.d.ts +3 -0
  42. package/types/src/core/user.d.ts +5 -1
  43. package/types/src/core/utils/flat_promise.d.ts +6 -0
  44. package/types/src/runtimes/interface.d.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pusher-js",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "description": "Pusher Channels JavaScript library for browsers, React Native, NodeJS and web workers",
5
5
  "main": "dist/node/pusher.js",
6
6
  "browser": "dist/web/pusher.js",
@@ -38,7 +38,7 @@
38
38
  "faye-websocket": "^0.11.3",
39
39
  "fetch-mock": "git+https://git@github.com/jpatel531/fetch-mock.git",
40
40
  "isomorphic-fetch": "^3.0.0",
41
- "jasmine": "^3.8.0",
41
+ "jasmine": "^3.99.0",
42
42
  "jasmine-spec-reporter": "^7.0.0",
43
43
  "karma": "^6.4.0",
44
44
  "karma-browserstack-launcher": "^1.6.0",
@@ -54,7 +54,7 @@
54
54
  "prettier": "^1.19.1",
55
55
  "source-map-loader": "^1.1.3",
56
56
  "ts-loader": "^6.0.4",
57
- "typescript": "^3.4.5",
57
+ "typescript": "^3.9.0",
58
58
  "uglify-js": "^2.6.2",
59
59
  "webpack": "^4.46.0",
60
60
  "webpack-cli": "^3.3.12",
@@ -63,6 +63,7 @@
63
63
  "xmlhttprequest": "^1.8.0"
64
64
  },
65
65
  "dependencies": {
66
- "tweetnacl": "^1.0.3"
66
+ "tweetnacl": "^1.0.3",
67
+ "@types/node": "^14.14.31"
67
68
  }
68
69
  }
@@ -0,0 +1,9 @@
1
+
2
+ const setTimeoutPromise = (duration) => {
3
+ return new Promise((resolve) => {
4
+ setTimeout(resolve, duration);
5
+ });
6
+ }
7
+ export default {
8
+ setTimeout: setTimeoutPromise
9
+ };
@@ -4,6 +4,8 @@ var Members = require('core/channels/members').default;
4
4
  var Errors = require('core/errors');
5
5
  var Factory = require('core/utils/factory').default;
6
6
  var Mocks = require("mocks");
7
+ var flatPromise = require("core/utils/flat_promise").default;
8
+ var { setTimeout } = require("../../../helpers/timers/promises").default;
7
9
 
8
10
  describe("PresenceChannel", function() {
9
11
  var pusher;
@@ -47,7 +49,7 @@ describe("PresenceChannel", function() {
47
49
  });
48
50
 
49
51
  describe("#authorize", function() {
50
-
52
+
51
53
  it("should call channelAuthorizer", function() {
52
54
  const callback = function(){}
53
55
  channel.authorize("1.23", callback);
@@ -56,30 +58,97 @@ describe("PresenceChannel", function() {
56
58
  { socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
57
59
  });
58
60
 
59
- it("should call the callback if an authorizaiton error is encountered", function() {
61
+ it("should call the callback if an authorization error is encountered", function() {
60
62
  const callback = jasmine.createSpy("callback")
61
63
  channel.authorize("1.23", callback);
62
64
  expect(channelAuthorizer.calls.count()).toEqual(1);
63
65
  expect(channelAuthorizer).toHaveBeenCalledWith(
64
66
  { socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
65
67
  const presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
66
-
68
+
67
69
  presenceChannelCallback("error", {})
68
70
  expect(callback).toHaveBeenCalledWith("error", {})
69
71
  });
70
72
 
71
- it("should call the callback with error if auth data doesn't have channel_data", function() {
72
- const callback = jasmine.createSpy("callback")
73
- channel.authorize("1.23", callback);
74
- expect(channelAuthorizer.calls.count()).toEqual(1);
75
- expect(channelAuthorizer).toHaveBeenCalledWith(
76
- { socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
77
- const presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
78
-
79
- presenceChannelCallback(null, {
80
- foo: 'bar'
81
- })
82
- expect(callback).toHaveBeenCalledWith("Invalid auth response")
73
+ describe("when channel_data isn't present", function() {
74
+ let callback;
75
+ let presenceChannelCallback;
76
+ const authWithoutChannelData = {foo: 'bar'}
77
+
78
+ beforeEach(function() {
79
+ pusher.user = jasmine.createSpy("user");
80
+
81
+ callback = jasmine.createSpy("callback")
82
+ channel.authorize("1.23", callback);
83
+ expect(channelAuthorizer.calls.count()).toEqual(1);
84
+ expect(channelAuthorizer).toHaveBeenCalledWith(
85
+ { socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
86
+ presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
87
+ });
88
+
89
+ it("should call the callback with an error if no signin is in progress", async function() {
90
+ pusher.user.signinDonePromise = null;
91
+
92
+ presenceChannelCallback(null, authWithoutChannelData);
93
+ await setTimeout(10);
94
+ expect(callback).toHaveBeenCalledWith("Invalid auth response");
95
+ });
96
+
97
+ it("should wait for the in-progress sign in and call the callback with an error if signin failed", async function() {
98
+ const {promise, resolve} = flatPromise();
99
+ pusher.user.signinDonePromise = promise
100
+
101
+ // signin is in progress
102
+ presenceChannelCallback(null, authWithoutChannelData)
103
+ await setTimeout(10);
104
+ expect(callback).not.toHaveBeenCalled()
105
+
106
+ // Signin failed
107
+ pusher.user.user_data = null
108
+ resolve()
109
+ await setTimeout(10);
110
+ expect(callback).toHaveBeenCalledWith("Invalid auth response")
111
+ });
112
+
113
+ it("should wait for the in-progress sign in and call the callback if signin succeeded", async function() {
114
+ const {promise, resolve} = flatPromise();
115
+ pusher.user.signinDonePromise = promise
116
+
117
+ // signin is in progress
118
+ presenceChannelCallback(null, authWithoutChannelData)
119
+ await setTimeout(10);
120
+ expect(callback).not.toHaveBeenCalled()
121
+
122
+ // Signin succeeded
123
+ pusher.user.user_data = {id: '123'}
124
+ resolve()
125
+ await setTimeout(10);
126
+ expect(callback).toHaveBeenCalledWith(null, authWithoutChannelData)
127
+ });
128
+
129
+ it("should call the callback if the user is already signed in", async function() {
130
+ const {promise, resolve} = flatPromise();
131
+ pusher.user.signinDonePromise = promise
132
+ resolve()
133
+ pusher.user.user_data = {id: '123'}
134
+
135
+ // signin is in progress
136
+ presenceChannelCallback(null, authWithoutChannelData)
137
+ await setTimeout(10);
138
+ expect(callback).toHaveBeenCalledWith(null, authWithoutChannelData)
139
+ });
140
+
141
+ it("should call the callback with an error if the user signin already failed", async function() {
142
+ const {promise, resolve} = flatPromise();
143
+ pusher.user.signinDonePromise = promise
144
+ resolve()
145
+ pusher.user.user_data = null
146
+
147
+ // signin is in progress
148
+ presenceChannelCallback(null, authWithoutChannelData)
149
+ await setTimeout(10);
150
+ expect(callback).toHaveBeenCalledWith("Invalid auth response")
151
+ });
83
152
  });
84
153
 
85
154
  it("should call the callback with auth data", function() {
@@ -89,7 +158,7 @@ describe("PresenceChannel", function() {
89
158
  expect(channelAuthorizer).toHaveBeenCalledWith(
90
159
  { socketId: "1.23", channelName: "presence-test" }, jasmine.any(Function));
91
160
  const presenceChannelCallback = channelAuthorizer.calls.mostRecent().args[1];
92
-
161
+
93
162
  const authdata = {
94
163
  channel_data: "{\"user_id\":\"123\"}",
95
164
  foo: 'bar'
@@ -82,7 +82,7 @@ describe("Pusher (User)", function () {
82
82
  });
83
83
 
84
84
  pusher.connection.state = "connected";
85
- pusher.connection.emit('connected');
85
+ pusher.connection.emit('state_change', {previous:'connecting', current:'connected'});
86
86
 
87
87
  expect(pusher.config.userAuthenticator).toHaveBeenCalledWith(
88
88
  { socketId: "1.23" },
@@ -116,11 +116,11 @@ describe("Pusher (User)", function () {
116
116
  pusher.config.userAuthenticator.calls.reset()
117
117
 
118
118
  pusher.connection.state == "disconnected";
119
- pusher.connection.emit("disconnected");
119
+ pusher.connection.emit('state_change', {previous:'connected', current:'disconnected'});
120
120
  pusher.connection.state == "connecting";
121
- pusher.connection.emit("connecting");
121
+ pusher.connection.emit('state_change', {previous:'disconnected', current:'connecting'});
122
122
  pusher.connection.state == "connected";
123
- pusher.connection.emit("connected");
123
+ pusher.connection.emit('state_change', {previous:'connecting', current:'connected'});
124
124
 
125
125
  expect(pusher.config.userAuthenticator).toHaveBeenCalledWith(
126
126
  { socketId: "1.23" },
@@ -134,7 +134,7 @@ describe("Pusher (User)", function () {
134
134
 
135
135
  it("should not signin when the connection is connected if signin() was never called", function () {
136
136
  pusher.connection.state = "connected";
137
- pusher.connection.emit('connected');
137
+ pusher.connection.emit('state_change', {previous:'connecting', current:'connected'});
138
138
  expect(pusher.config.userAuthenticator).not.toHaveBeenCalled();
139
139
  })
140
140
 
@@ -172,6 +172,7 @@ describe("Pusher (User)", function () {
172
172
  });
173
173
 
174
174
  it('should process pusher:signin_success', async function () {
175
+ pusher.user._signinDoneResolve = jasmine.createSpy('signinDoneResolve');
175
176
  transport.emit('message', {
176
177
  data: JSON.stringify({
177
178
  event: 'pusher:signin_success',
@@ -183,6 +184,7 @@ describe("Pusher (User)", function () {
183
184
 
184
185
  expect(pusher.user.user_data).toEqual({ id: '1', name: 'test' });
185
186
  expect(pusher.user.serverToUserChannel.subscriptionPending).toBe(true);
187
+ expect(pusher.user._signinDoneResolve).toHaveBeenCalled();
186
188
  });
187
189
 
188
190
  it('should log warning if user_data is not JSON', async function () {
@@ -220,6 +222,7 @@ describe("Pusher (User)", function () {
220
222
  expect(barCallback).not.toHaveBeenCalled();
221
223
 
222
224
  // Sign in successfully
225
+ pusher.user._signinDoneResolve = jasmine.createSpy('signinDoneResolve');
223
226
  transport.emit('message', {
224
227
  data: JSON.stringify({
225
228
  event: 'pusher:signin_success',
@@ -242,6 +245,7 @@ describe("Pusher (User)", function () {
242
245
  'pusher.user.serverToUserChannel.subscribed to be true',
243
246
  500
244
247
  );
248
+ expect(pusher.user._signinDoneResolve).toHaveBeenCalled();
245
249
 
246
250
  // Send events on channel
247
251
  transport.emit('message', {
@@ -259,6 +263,7 @@ describe("Pusher (User)", function () {
259
263
 
260
264
  it('should cleanup the signed in state when disconnected', async function () {
261
265
  // Sign in successfully
266
+ pusher.user._signinDoneResolve = jasmine.createSpy('signinDoneResolve');
262
267
  transport.emit('message', {
263
268
  data: JSON.stringify({
264
269
  event: 'pusher:signin_success',
@@ -281,11 +286,13 @@ describe("Pusher (User)", function () {
281
286
  'pusher.user.serverToUserChannel.subscribed to be true',
282
287
  500
283
288
  );
289
+ expect(pusher.user._signinDoneResolve).toHaveBeenCalled();
290
+
284
291
  expect(pusher.user.user_data).toEqual({ id: '1', name: 'test' });
285
292
  expect(pusher.user.serverToUserChannel.subscribed).toBe(true);
286
293
 
287
294
  // Disconnect
288
- pusher.connection.emit('disconnected');
295
+ pusher.connection.emit('state_change', {previous:'connected', current:'disconnected'});
289
296
 
290
297
  expect(pusher.user.user_data).toEqual(null);
291
298
  expect(pusher.user.serverToUserChannel).toEqual(null);
@@ -20,26 +20,35 @@ export default class PresenceChannel extends PrivateChannel {
20
20
  this.members = new Members();
21
21
  }
22
22
 
23
- /** Authenticates the connection as a member of the channel.
23
+ /** Authorizes the connection as a member of the channel.
24
24
  *
25
25
  * @param {String} socketId
26
26
  * @param {Function} callback
27
27
  */
28
28
  authorize(socketId: string, callback: Function) {
29
- super.authorize(socketId, (error, authData) => {
29
+ super.authorize(socketId, async (error, authData) => {
30
30
  if (!error) {
31
31
  authData = authData as ChannelAuthorizationData;
32
- if (authData.channel_data === undefined) {
33
- let suffix = UrlStore.buildLogSuffix('authenticationEndpoint');
34
- Logger.error(
35
- `Invalid auth response for channel '${this.name}',` +
36
- `expected 'channel_data' field. ${suffix}`
37
- );
38
- callback('Invalid auth response');
39
- return;
32
+ if (authData.channel_data != null) {
33
+ var channelData = JSON.parse(authData.channel_data);
34
+ this.members.setMyID(channelData.user_id);
35
+ } else {
36
+ await this.pusher.user.signinDonePromise;
37
+ if (this.pusher.user.user_data != null) {
38
+ // If the user is signed in, get the id of the authenticated user
39
+ // and allow the presence authorization to continue.
40
+ this.members.setMyID(this.pusher.user.user_data.id);
41
+ } else {
42
+ let suffix = UrlStore.buildLogSuffix('authorizationEndpoint');
43
+ Logger.error(
44
+ `Invalid auth response for channel '${this.name}', ` +
45
+ `expected 'channel_data' field. ${suffix}, ` +
46
+ `or the user should be signed in.`
47
+ );
48
+ callback('Invalid auth response');
49
+ return;
50
+ }
40
51
  }
41
- var channelData = JSON.parse(authData.channel_data);
42
- this.members.setMyID(channelData.user_id);
43
52
  }
44
53
  callback(error, authData);
45
54
  });
@@ -204,14 +204,16 @@ function replaceHost(url: string, hostname: string): string {
204
204
  }
205
205
 
206
206
  function randomNumber(max: number): number {
207
- return Math.floor(Math.random() * max);
207
+ return Runtime.randomInt(max);
208
208
  }
209
209
 
210
210
  function randomString(length: number): string {
211
211
  var result = [];
212
+
212
213
  for (var i = 0; i < length; i++) {
213
214
  result.push(randomNumber(32).toString(32));
214
215
  }
216
+
215
217
  return result.join('');
216
218
  }
217
219
 
@@ -83,7 +83,7 @@ export default class Pusher {
83
83
 
84
84
  this.channels = Factory.createChannels();
85
85
  this.global_emitter = new EventsDispatcher();
86
- this.sessionID = Math.floor(Math.random() * 1000000000);
86
+ this.sessionID = Runtime.randomInt(1000000000);
87
87
 
88
88
  this.timeline = new Timeline(this.key, this.sessionID, {
89
89
  cluster: this.config.cluster,
package/src/core/user.ts CHANGED
@@ -6,26 +6,29 @@ import {
6
6
  } from './auth/options';
7
7
  import Channel from './channels/channel';
8
8
  import EventsDispatcher from './events/dispatcher';
9
+ import flatPromise from './utils/flat_promise';
9
10
 
10
11
  export default class UserFacade extends EventsDispatcher {
11
12
  pusher: Pusher;
12
13
  signin_requested: boolean = false;
13
14
  user_data: any = null;
14
15
  serverToUserChannel: Channel = null;
16
+ signinDonePromise: Promise<any> = null;
17
+ private _signinDoneResolve: Function = null;
15
18
 
16
19
  public constructor(pusher: Pusher) {
17
20
  super(function(eventName, data) {
18
21
  Logger.debug('No callbacks on user for ' + eventName);
19
22
  });
20
23
  this.pusher = pusher;
21
- this.pusher.connection.bind('connected', () => {
22
- this._signin();
23
- });
24
- this.pusher.connection.bind('connecting', () => {
25
- this._disconnect();
26
- });
27
- this.pusher.connection.bind('disconnected', () => {
28
- this._disconnect();
24
+ this.pusher.connection.bind('state_change', ({ previous, current }) => {
25
+ if (previous !== 'connected' && current === 'connected') {
26
+ this._signin();
27
+ }
28
+ if (previous === 'connected' && current !== 'connected') {
29
+ this._cleanup();
30
+ this._newSigninPromiseIfNeeded();
31
+ }
29
32
  });
30
33
  this.pusher.connection.bind('message', event => {
31
34
  var eventName = event.event;
@@ -55,41 +58,45 @@ export default class UserFacade extends EventsDispatcher {
55
58
  return;
56
59
  }
57
60
 
61
+ this._newSigninPromiseIfNeeded();
62
+
58
63
  if (this.pusher.connection.state !== 'connected') {
59
64
  // Signin will be attempted when the connection is connected
60
65
  return;
61
66
  }
62
67
 
63
- const onAuthorize: UserAuthenticationCallback = (
64
- err,
65
- authData: UserAuthenticationData
66
- ) => {
67
- if (err) {
68
- Logger.warn(`Error during signin: ${err}`);
69
- return;
70
- }
71
-
72
- this.pusher.send_event('pusher:signin', {
73
- auth: authData.auth,
74
- user_data: authData.user_data
75
- });
76
-
77
- // Later when we get pusher:singin_success event, the user will be marked as signed in
78
- };
79
-
80
68
  this.pusher.config.userAuthenticator(
81
69
  {
82
70
  socketId: this.pusher.connection.socket_id
83
71
  },
84
- onAuthorize
72
+ this._onAuthorize
85
73
  );
86
74
  }
87
75
 
76
+ private _onAuthorize: UserAuthenticationCallback = (
77
+ err,
78
+ authData: UserAuthenticationData
79
+ ) => {
80
+ if (err) {
81
+ Logger.warn(`Error during signin: ${err}`);
82
+ this._cleanup();
83
+ return;
84
+ }
85
+
86
+ this.pusher.send_event('pusher:signin', {
87
+ auth: authData.auth,
88
+ user_data: authData.user_data
89
+ });
90
+
91
+ // Later when we get pusher:singin_success event, the user will be marked as signed in
92
+ };
93
+
88
94
  private _onSigninSuccess(data: any) {
89
95
  try {
90
96
  this.user_data = JSON.parse(data.user_data);
91
97
  } catch (e) {
92
98
  Logger.error(`Failed parsing user data after signin: ${data.user_data}`);
99
+ this._cleanup();
93
100
  return;
94
101
  }
95
102
 
@@ -97,9 +104,12 @@ export default class UserFacade extends EventsDispatcher {
97
104
  Logger.error(
98
105
  `user_data doesn't contain an id. user_data: ${this.user_data}`
99
106
  );
107
+ this._cleanup();
100
108
  return;
101
109
  }
102
110
 
111
+ // Signin succeeded
112
+ this._signinDoneResolve();
103
113
  this._subscribeChannels();
104
114
  }
105
115
 
@@ -132,12 +142,40 @@ export default class UserFacade extends EventsDispatcher {
132
142
  ensure_subscribed(this.serverToUserChannel);
133
143
  }
134
144
 
135
- private _disconnect() {
145
+ private _cleanup() {
136
146
  this.user_data = null;
137
147
  if (this.serverToUserChannel) {
138
148
  this.serverToUserChannel.unbind_all();
139
149
  this.serverToUserChannel.disconnect();
140
150
  this.serverToUserChannel = null;
141
151
  }
152
+
153
+ if (this.signin_requested) {
154
+ // If signin is in progress and cleanup is called,
155
+ // Mark the current signin process as done.
156
+ this._signinDoneResolve();
157
+ }
158
+ }
159
+
160
+ private _newSigninPromiseIfNeeded() {
161
+ if (!this.signin_requested) {
162
+ return;
163
+ }
164
+
165
+ // If there is a promise and it is not resolved, return without creating a new one.
166
+ if (this.signinDonePromise && !(this.signinDonePromise as any).done) {
167
+ return;
168
+ }
169
+
170
+ // This promise is never rejected.
171
+ // It gets resolved when the signin process is done whether it failed or succeeded
172
+ const { promise, resolve, reject: _ } = flatPromise();
173
+ (promise as any).done = false;
174
+ const setDone = () => {
175
+ (promise as any).done = true;
176
+ };
177
+ promise.then(setDone).catch(setDone);
178
+ this.signinDonePromise = promise;
179
+ this._signinDoneResolve = resolve;
142
180
  }
143
181
  }
@@ -0,0 +1,10 @@
1
+ function flatPromise() {
2
+ let resolve, reject;
3
+ const promise = new Promise((res, rej) => {
4
+ resolve = res;
5
+ reject = rej;
6
+ });
7
+ return { promise, resolve, reject };
8
+ }
9
+
10
+ export default flatPromise;
@@ -46,6 +46,7 @@ interface Runtime {
46
46
  HTTPFactory: HTTPFactory;
47
47
  isXHRSupported(): boolean;
48
48
  createSocketRequest(method: string, url: string): HTTPRequest;
49
+ randomInt(max: number): number;
49
50
 
50
51
  // these methods/types are only implemented in the web Runtime, so they're
51
52
  // optional but must be included in the interface
@@ -6,6 +6,7 @@ import { Network } from './net_info';
6
6
  import xhrAuth from 'isomorphic/auth/xhr_auth';
7
7
  import { AuthTransports } from 'core/auth/auth_transports';
8
8
  import xhrTimeline from 'isomorphic/timeline/xhr_timeline';
9
+ import { randomInt } from 'crypto';
9
10
 
10
11
  // Very verbose but until unavoidable until
11
12
  // TypeScript 2.1, when spread attributes will be
@@ -57,6 +58,10 @@ const NodeJS: Runtime = {
57
58
 
58
59
  getNetwork() {
59
60
  return Network;
61
+ },
62
+
63
+ randomInt(max: number): number {
64
+ return randomInt(max);
60
65
  }
61
66
  };
62
67
 
@@ -4,6 +4,7 @@ import { Network } from './net_info';
4
4
  import xhrAuth from 'isomorphic/auth/xhr_auth';
5
5
  import { AuthTransports } from 'core/auth/auth_transports';
6
6
  import xhrTimeline from 'isomorphic/timeline/xhr_timeline';
7
+ import { randomInt } from 'crypto';
7
8
 
8
9
  // Very verbose but until unavoidable until
9
10
  // TypeScript 2.1, when spread attributes will be
@@ -55,6 +56,10 @@ const ReactNative: Runtime = {
55
56
 
56
57
  getNetwork() {
57
58
  return Network;
59
+ },
60
+
61
+ randomInt(max: number): number {
62
+ return randomInt(max);
58
63
  }
59
64
  };
60
65
 
@@ -154,6 +154,20 @@ var Runtime: Browser = {
154
154
  } else if (window.detachEvent !== undefined) {
155
155
  window.detachEvent('onunload', listener);
156
156
  }
157
+ },
158
+
159
+ randomInt(max: number): number {
160
+ /**
161
+ * Return values in the range of [0, 1[
162
+ */
163
+ const random = function() {
164
+ const crypto = window.crypto || window['msCrypto'];
165
+ const random = crypto.getRandomValues(new Uint32Array(1))[0];
166
+
167
+ return random / 2 ** 32;
168
+ };
169
+
170
+ return Math.floor(random() * max);
157
171
  }
158
172
  };
159
173
 
@@ -55,6 +55,20 @@ const Worker: Runtime = {
55
55
 
56
56
  getNetwork() {
57
57
  return Network;
58
+ },
59
+
60
+ randomInt(max: number): number {
61
+ /**
62
+ * Return values in the range of [0, 1[
63
+ */
64
+ const random = function() {
65
+ const crypto = window.crypto || window['msCrypto'];
66
+ const random = crypto.getRandomValues(new Uint32Array(1))[0];
67
+
68
+ return random / 2 ** 32;
69
+ };
70
+
71
+ return Math.floor(random() * max);
58
72
  }
59
73
  };
60
74
 
@@ -9,6 +9,9 @@ export default class TransportStrategy implements Strategy {
9
9
  constructor(name: string, priority: number, transport: Transport, options: StrategyOptions);
10
10
  isSupported(): boolean;
11
11
  connect(minPriority: number, callback: Function): {
12
+ abort: () => void;
13
+ forceMinPriority: () => void;
14
+ } | {
12
15
  abort: () => void;
13
16
  forceMinPriority: (p: any) => void;
14
17
  };
@@ -6,10 +6,14 @@ export default class UserFacade extends EventsDispatcher {
6
6
  signin_requested: boolean;
7
7
  user_data: any;
8
8
  serverToUserChannel: Channel;
9
+ signinDonePromise: Promise<any>;
10
+ private _signinDoneResolve;
9
11
  constructor(pusher: Pusher);
10
12
  signin(): void;
11
13
  private _signin;
14
+ private _onAuthorize;
12
15
  private _onSigninSuccess;
13
16
  private _subscribeChannels;
14
- private _disconnect;
17
+ private _cleanup;
18
+ private _newSigninPromiseIfNeeded;
15
19
  }
@@ -0,0 +1,6 @@
1
+ declare function flatPromise(): {
2
+ promise: Promise<unknown>;
3
+ resolve: any;
4
+ reject: any;
5
+ };
6
+ export default flatPromise;
@@ -33,6 +33,7 @@ interface Runtime {
33
33
  HTTPFactory: HTTPFactory;
34
34
  isXHRSupported(): boolean;
35
35
  createSocketRequest(method: string, url: string): HTTPRequest;
36
+ randomInt(max: number): number;
36
37
  getDocument?(): Document;
37
38
  createScriptRequest?(url: string): any;
38
39
  createJSONPRequest?(url: string, data: any): JSONPRequest;