pusher-js 7.4.1 → 7.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.
Files changed (57) hide show
  1. package/.github/workflows/release_pr.yml +3 -1
  2. package/.github/workflows/run-tests.yml +27 -3
  3. package/CHANGELOG.md +8 -0
  4. package/Makefile +1 -0
  5. package/README.md +11 -3
  6. package/dist/node/pusher.js +139 -28
  7. package/dist/node/pusher.js.map +1 -1
  8. package/dist/react-native/pusher.js +5 -5
  9. package/dist/react-native/pusher.js.map +1 -1
  10. package/dist/web/pusher-with-encryption.js +83 -9
  11. package/dist/web/pusher-with-encryption.js.map +1 -1
  12. package/dist/web/pusher-with-encryption.min.js +2 -2
  13. package/dist/web/pusher-with-encryption.min.js.map +1 -1
  14. package/dist/web/pusher.js +83 -9
  15. package/dist/web/pusher.js.map +1 -1
  16. package/dist/web/pusher.min.js +2 -2
  17. package/dist/web/pusher.min.js.map +1 -1
  18. package/dist/worker/pusher-with-encryption.worker.js +81 -8
  19. package/dist/worker/pusher-with-encryption.worker.js.map +1 -1
  20. package/dist/worker/pusher-with-encryption.worker.min.js +2 -2
  21. package/dist/worker/pusher-with-encryption.worker.min.js.map +1 -1
  22. package/dist/worker/pusher.worker.js +81 -8
  23. package/dist/worker/pusher.worker.js.map +1 -1
  24. package/dist/worker/pusher.worker.min.js +2 -2
  25. package/dist/worker/pusher.worker.min.js.map +1 -1
  26. package/integration_tests_server/index.js +176 -0
  27. package/integration_tests_server/package-lock.json +1177 -0
  28. package/integration_tests_server/package.json +15 -0
  29. package/package.json +6 -5
  30. package/spec/config/karma/config.common.js +1 -2
  31. package/spec/javascripts/helpers/node/integration.js +2 -2
  32. package/spec/javascripts/helpers/web/integration.js +2 -2
  33. package/spec/javascripts/integration/core/cluster_config_spec.js +1 -1
  34. package/spec/javascripts/integration/core/pusher_spec/test_builder.js +13 -43
  35. package/spec/javascripts/integration/web/dom/jsonp_spec.js +2 -2
  36. package/spec/javascripts/unit/core/config_spec.js +91 -3
  37. package/spec/javascripts/unit/core/connection/connection_manager_spec.js +11 -1
  38. package/spec/javascripts/unit/core/http/http_request_spec.js +0 -6
  39. package/spec/javascripts/unit/core/transports/transport_connection_spec.js +5 -0
  40. package/spec/javascripts/unit/core/utils/timers_spec.js +0 -4
  41. package/spec/javascripts/unit/core/watchlist_spec.js +48 -0
  42. package/spec/javascripts/unit/core_with_runtime/auth/channel_authorizer_spec.js +82 -0
  43. package/spec/javascripts/unit/core_with_runtime/auth/user_authorizer_spec.js +76 -0
  44. package/spec/javascripts/unit/web/pusher_authorizer_spec.js +28 -0
  45. package/spec/javascripts/unit/worker/channel_authorizer_spec.js +46 -0
  46. package/src/core/auth/channel_authorizer.ts +14 -3
  47. package/src/core/auth/options.ts +4 -0
  48. package/src/core/auth/user_authenticator.ts +14 -3
  49. package/src/core/pusher.ts +0 -1
  50. package/src/core/user.ts +5 -0
  51. package/src/core/watchlist.ts +31 -0
  52. package/src/runtimes/isomorphic/auth/xhr_auth.ts +6 -0
  53. package/src/runtimes/web/auth/jsonp_auth.ts +4 -1
  54. package/src/runtimes/worker/auth/fetch_auth.ts +7 -0
  55. package/types/src/core/auth/options.d.ts +4 -0
  56. package/types/src/core/user.d.ts +2 -0
  57. package/types/src/core/watchlist.d.ts +8 -0
@@ -33,4 +33,32 @@ describe('JSONP Authorizer', function() {
33
33
  'To send headers with the channel-authorization request, you must use AJAX, rather than JSONP.'
34
34
  );
35
35
  });
36
+
37
+ it('should raise a warning if headersProvider is passed', function() {
38
+ var headers = { foo: 'bar', n: 42 };
39
+ var channelAuthorizer = ChannelAuthorizer({
40
+ transport: 'jsonp',
41
+ headersProvider: () => headers
42
+ })
43
+
44
+ var document = Mocks.getDocument();
45
+ var script = Mocks.getDocumentElement();
46
+ var documentElement = Mocks.getDocumentElement();
47
+
48
+ document.createElement.and.returnValue(script);
49
+ document.getElementsByTagName.and.returnValue([]);
50
+ document.documentElement = documentElement;
51
+ spyOn(Runtime, 'getDocument').and.returnValue(document);
52
+
53
+ spyOn(Logger, 'warn');
54
+ channelAuthorizer({
55
+ socketId: '1.23',
56
+ channelName: 'chan',
57
+ }, function() {})
58
+
59
+ expect(Logger.warn).toHaveBeenCalledWith(
60
+ 'To send headers with the channel-authorization request, you must use AJAX, rather than JSONP.'
61
+ );
62
+ });
63
+
36
64
  });
@@ -35,6 +35,30 @@ describe('Fetch Authorizer', function() {
35
35
  expect(sentHeaders.get('n')).toEqual('42');
36
36
  });
37
37
 
38
+ it('should pass headers from headersProvider in the request', function() {
39
+ fetchMock.mock(endpoint, { body: { hello: 'world' } });
40
+
41
+ var headers = { foo: 'bar', n: 42 };
42
+ var channelAuthorizer = ChannelAuthorizer({
43
+ transport: 'ajax',
44
+ endpoint: endpoint,
45
+ headersProvider: () => headers
46
+ });
47
+
48
+ channelAuthorizer({
49
+ socketId: '1.23',
50
+ channelName: 'chan'
51
+ }, function() {});
52
+
53
+ var lastCall = fetchMock.lastCall(endpoint)[0];
54
+ var sentHeaders = lastCall.headers;
55
+ expect(sentHeaders.get('Content-Type')).toEqual(
56
+ 'application/x-www-form-urlencoded'
57
+ );
58
+ expect(sentHeaders.get('foo')).toEqual('bar');
59
+ expect(sentHeaders.get('n')).toEqual('42');
60
+ });
61
+
38
62
  it('should pass params in the query string', async function() {
39
63
  fetchMock.mock(endpoint, { body: { hello: 'world' } });
40
64
 
@@ -56,6 +80,28 @@ describe('Fetch Authorizer', function() {
56
80
  expect(body).toEqual("socket_id=1.23&channel_name=chan&a=1&b=2");
57
81
  });
58
82
 
83
+ it('should pass params from paramsProvider in the query string', async function() {
84
+ fetchMock.mock(endpoint, { body: { hello: 'world' } });
85
+
86
+ var params = { a: 1, b: 2 };
87
+ var channelAuthorizer = ChannelAuthorizer({
88
+ transport: 'ajax',
89
+ endpoint: endpoint,
90
+ paramsProvider: () => params
91
+ });
92
+
93
+ channelAuthorizer({
94
+ socketId: '1.23',
95
+ channelName: 'chan'
96
+ }, function() {});
97
+
98
+ await new Promise(resolve => setTimeout(resolve, 100));
99
+ var lastRequest = fetchMock.lastCall(endpoint)[0];
100
+ const body = await lastRequest.text()
101
+ expect(body).toEqual("socket_id=1.23&channel_name=chan&a=1&b=2");
102
+ });
103
+
104
+
59
105
  it('should call back with the auth result on success', async function() {
60
106
  var data = { foo: 'bar', number: 1 };
61
107
  var dataJSON = JSON.stringify(data);
@@ -16,12 +16,23 @@ const composeChannelQuery = (
16
16
 
17
17
  query += '&channel_name=' + encodeURIComponent(params.channelName);
18
18
 
19
- for (var i in authOptions.params) {
19
+ for (var key in authOptions.params) {
20
20
  query +=
21
21
  '&' +
22
- encodeURIComponent(i) +
22
+ encodeURIComponent(key) +
23
23
  '=' +
24
- encodeURIComponent(authOptions.params[i]);
24
+ encodeURIComponent(authOptions.params[key]);
25
+ }
26
+
27
+ if (authOptions.paramsProvider != null) {
28
+ let dynamicParams = authOptions.paramsProvider();
29
+ for (var key in dynamicParams) {
30
+ query +=
31
+ '&' +
32
+ encodeURIComponent(key) +
33
+ '=' +
34
+ encodeURIComponent(dynamicParams[key]);
35
+ }
25
36
  }
26
37
 
27
38
  return query;
@@ -56,6 +56,8 @@ export interface AuthOptionsT<AuthHandler> {
56
56
  endpoint: string;
57
57
  params?: any;
58
58
  headers?: any;
59
+ paramsProvider?: () => any;
60
+ headersProvider?: () => any;
59
61
  customHandler?: AuthHandler;
60
62
  }
61
63
 
@@ -71,4 +73,6 @@ export interface InternalAuthOptions {
71
73
  endpoint: string;
72
74
  params?: any;
73
75
  headers?: any;
76
+ paramsProvider?: () => any;
77
+ headersProvider?: () => any;
74
78
  }
@@ -14,12 +14,23 @@ const composeChannelQuery = (
14
14
  ) => {
15
15
  var query = 'socket_id=' + encodeURIComponent(params.socketId);
16
16
 
17
- for (var i in authOptions.params) {
17
+ for (var key in authOptions.params) {
18
18
  query +=
19
19
  '&' +
20
- encodeURIComponent(i) +
20
+ encodeURIComponent(key) +
21
21
  '=' +
22
- encodeURIComponent(authOptions.params[i]);
22
+ encodeURIComponent(authOptions.params[key]);
23
+ }
24
+
25
+ if (authOptions.paramsProvider != null) {
26
+ let dynamicParams = authOptions.paramsProvider();
27
+ for (var key in dynamicParams) {
28
+ query +=
29
+ '&' +
30
+ encodeURIComponent(key) +
31
+ '=' +
32
+ encodeURIComponent(dynamicParams[key]);
33
+ }
23
34
  }
24
35
 
25
36
  return query;
@@ -62,7 +62,6 @@ export default class Pusher {
62
62
  connection: ConnectionManager;
63
63
  timelineSenderTimer: PeriodicTimer;
64
64
  user: UserFacade;
65
-
66
65
  constructor(app_key: string, options?: Options) {
67
66
  checkAppKey(app_key);
68
67
  options = options || {};
package/src/core/user.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  UserAuthenticationCallback
6
6
  } from './auth/options';
7
7
  import Channel from './channels/channel';
8
+ import WatchlistFacade from './watchlist';
8
9
  import EventsDispatcher from './events/dispatcher';
9
10
  import flatPromise from './utils/flat_promise';
10
11
 
@@ -14,6 +15,7 @@ export default class UserFacade extends EventsDispatcher {
14
15
  user_data: any = null;
15
16
  serverToUserChannel: Channel = null;
16
17
  signinDonePromise: Promise<any> = null;
18
+ watchlist: WatchlistFacade;
17
19
  private _signinDoneResolve: Function = null;
18
20
 
19
21
  public constructor(pusher: Pusher) {
@@ -30,6 +32,9 @@ export default class UserFacade extends EventsDispatcher {
30
32
  this._newSigninPromiseIfNeeded();
31
33
  }
32
34
  });
35
+
36
+ this.watchlist = new WatchlistFacade(pusher);
37
+
33
38
  this.pusher.connection.bind('message', event => {
34
39
  var eventName = event.event;
35
40
  if (eventName === 'pusher:signin_success') {
@@ -0,0 +1,31 @@
1
+ import Logger from './logger';
2
+ import Pusher from './pusher';
3
+ import EventsDispatcher from './events/dispatcher';
4
+
5
+ export default class WatchlistFacade extends EventsDispatcher {
6
+ private pusher: Pusher;
7
+
8
+ public constructor(pusher: Pusher) {
9
+ super(function(eventName, data) {
10
+ Logger.debug(`No callbacks on watchlist events for ${eventName}`);
11
+ });
12
+
13
+ this.pusher = pusher;
14
+ this.bindWatchlistInternalEvent();
15
+ }
16
+
17
+ handleEvent(pusherEvent) {
18
+ pusherEvent.data.events.forEach(watchlistEvent => {
19
+ this.emit(watchlistEvent.name, watchlistEvent);
20
+ });
21
+ }
22
+
23
+ private bindWatchlistInternalEvent() {
24
+ this.pusher.connection.bind('message', pusherEvent => {
25
+ var eventName = pusherEvent.event;
26
+ if (eventName === 'pusher_internal:watchlist_events') {
27
+ this.handleEvent(pusherEvent);
28
+ }
29
+ });
30
+ }
31
+ }
@@ -27,6 +27,12 @@ const ajax: AuthTransport = function(
27
27
  for (var headerName in authOptions.headers) {
28
28
  xhr.setRequestHeader(headerName, authOptions.headers[headerName]);
29
29
  }
30
+ if (authOptions.headersProvider != null) {
31
+ let dynamicHeaders = authOptions.headersProvider();
32
+ for (var headerName in dynamicHeaders) {
33
+ xhr.setRequestHeader(headerName, dynamicHeaders[headerName]);
34
+ }
35
+ }
30
36
 
31
37
  xhr.onreadystatechange = function() {
32
38
  if (xhr.readyState === 4) {
@@ -16,7 +16,10 @@ var jsonp: AuthTransport = function(
16
16
  authRequestType: AuthRequestType,
17
17
  callback: AuthTransportCallback
18
18
  ) {
19
- if (authOptions.headers !== undefined) {
19
+ if (
20
+ authOptions.headers !== undefined ||
21
+ authOptions.headersProvider != null
22
+ ) {
20
23
  Logger.warn(
21
24
  `To send headers with the ${authRequestType.toString()} request, you must use AJAX, rather than JSONP.`
22
25
  );
@@ -21,6 +21,13 @@ var fetchAuth: AuthTransport = function(
21
21
  headers.set(headerName, authOptions.headers[headerName]);
22
22
  }
23
23
 
24
+ if (authOptions.headersProvider != null) {
25
+ const dynamicHeaders = authOptions.headersProvider();
26
+ for (var headerName in dynamicHeaders) {
27
+ headers.set(headerName, dynamicHeaders[headerName]);
28
+ }
29
+ }
30
+
24
31
  var body = query;
25
32
  var request = new Request(authOptions.endpoint, {
26
33
  headers,
@@ -32,6 +32,8 @@ export interface AuthOptionsT<AuthHandler> {
32
32
  endpoint: string;
33
33
  params?: any;
34
34
  headers?: any;
35
+ paramsProvider?: () => any;
36
+ headersProvider?: () => any;
35
37
  customHandler?: AuthHandler;
36
38
  }
37
39
  export declare type UserAuthenticationOptions = AuthOptionsT<UserAuthenticationHandler>;
@@ -41,4 +43,6 @@ export interface InternalAuthOptions {
41
43
  endpoint: string;
42
44
  params?: any;
43
45
  headers?: any;
46
+ paramsProvider?: () => any;
47
+ headersProvider?: () => any;
44
48
  }
@@ -1,5 +1,6 @@
1
1
  import Pusher from './pusher';
2
2
  import Channel from './channels/channel';
3
+ import WatchlistFacade from './watchlist';
3
4
  import EventsDispatcher from './events/dispatcher';
4
5
  export default class UserFacade extends EventsDispatcher {
5
6
  pusher: Pusher;
@@ -7,6 +8,7 @@ export default class UserFacade extends EventsDispatcher {
7
8
  user_data: any;
8
9
  serverToUserChannel: Channel;
9
10
  signinDonePromise: Promise<any>;
11
+ watchlist: WatchlistFacade;
10
12
  private _signinDoneResolve;
11
13
  constructor(pusher: Pusher);
12
14
  signin(): void;
@@ -0,0 +1,8 @@
1
+ import Pusher from './pusher';
2
+ import EventsDispatcher from './events/dispatcher';
3
+ export default class WatchlistFacade extends EventsDispatcher {
4
+ private pusher;
5
+ constructor(pusher: Pusher);
6
+ handleEvent(pusherEvent: any): void;
7
+ private bindWatchlistInternalEvent;
8
+ }