laravel-echo-api-gateway 0.5.5 → 0.5.9

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.
@@ -1,871 +1,516 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var axios = require('axios');
6
-
7
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
-
9
- var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
10
-
11
- function _classCallCheck(instance, Constructor) {
12
- if (!(instance instanceof Constructor)) {
13
- throw new TypeError("Cannot call a class as a function");
14
- }
15
- }
16
-
17
- function _defineProperties(target, props) {
18
- for (var i = 0; i < props.length; i++) {
19
- var descriptor = props[i];
20
- descriptor.enumerable = descriptor.enumerable || false;
21
- descriptor.configurable = true;
22
- if ("value" in descriptor) descriptor.writable = true;
23
- Object.defineProperty(target, descriptor.key, descriptor);
24
- }
25
- }
26
-
27
- function _createClass(Constructor, protoProps, staticProps) {
28
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
29
- if (staticProps) _defineProperties(Constructor, staticProps);
30
- Object.defineProperty(Constructor, "prototype", {
31
- writable: false
32
- });
33
- return Constructor;
34
- }
35
-
36
- function _extends() {
37
- _extends = Object.assign || function (target) {
38
- for (var i = 1; i < arguments.length; i++) {
39
- var source = arguments[i];
40
-
41
- for (var key in source) {
42
- if (Object.prototype.hasOwnProperty.call(source, key)) {
43
- target[key] = source[key];
44
- }
45
- }
46
- }
47
-
48
- return target;
49
- };
50
-
51
- return _extends.apply(this, arguments);
52
- }
53
-
54
- function _inherits(subClass, superClass) {
55
- if (typeof superClass !== "function" && superClass !== null) {
56
- throw new TypeError("Super expression must either be null or a function");
57
- }
58
-
59
- Object.defineProperty(subClass, "prototype", {
60
- value: Object.create(superClass && superClass.prototype, {
61
- constructor: {
62
- value: subClass,
63
- writable: true,
64
- configurable: true
65
- }
66
- }),
67
- writable: false
68
- });
69
- if (superClass) _setPrototypeOf(subClass, superClass);
70
- }
71
-
72
- function _getPrototypeOf(o) {
73
- _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
74
- return o.__proto__ || Object.getPrototypeOf(o);
75
- };
76
- return _getPrototypeOf(o);
77
- }
78
-
79
- function _setPrototypeOf(o, p) {
80
- _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
81
- o.__proto__ = p;
82
- return o;
83
- };
84
-
85
- return _setPrototypeOf(o, p);
86
- }
87
-
88
- function _isNativeReflectConstruct() {
89
- if (typeof Reflect === "undefined" || !Reflect.construct) return false;
90
- if (Reflect.construct.sham) return false;
91
- if (typeof Proxy === "function") return true;
92
-
93
- try {
94
- Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
95
- return true;
96
- } catch (e) {
97
- return false;
98
- }
99
- }
100
-
101
- function _assertThisInitialized(self) {
102
- if (self === void 0) {
103
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
104
- }
105
-
106
- return self;
107
- }
108
-
109
- function _possibleConstructorReturn(self, call) {
110
- if (call && (typeof call === "object" || typeof call === "function")) {
111
- return call;
112
- } else if (call !== void 0) {
113
- throw new TypeError("Derived constructors may only return object or undefined");
114
- }
115
-
116
- return _assertThisInitialized(self);
117
- }
118
-
119
- function _createSuper(Derived) {
120
- var hasNativeReflectConstruct = _isNativeReflectConstruct();
121
-
122
- return function _createSuperInternal() {
123
- var Super = _getPrototypeOf(Derived),
124
- result;
125
-
126
- if (hasNativeReflectConstruct) {
127
- var NewTarget = _getPrototypeOf(this).constructor;
128
-
129
- result = Reflect.construct(Super, arguments, NewTarget);
130
- } else {
131
- result = Super.apply(this, arguments);
132
- }
133
-
134
- return _possibleConstructorReturn(this, result);
135
- };
136
- }
137
-
138
- function _unsupportedIterableToArray(o, minLen) {
139
- if (!o) return;
140
- if (typeof o === "string") return _arrayLikeToArray(o, minLen);
141
- var n = Object.prototype.toString.call(o).slice(8, -1);
142
- if (n === "Object" && o.constructor) n = o.constructor.name;
143
- if (n === "Map" || n === "Set") return Array.from(o);
144
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
145
- }
146
-
147
- function _arrayLikeToArray(arr, len) {
148
- if (len == null || len > arr.length) len = arr.length;
149
-
150
- for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
151
-
152
- return arr2;
153
- }
154
-
155
- function _createForOfIteratorHelper(o, allowArrayLike) {
156
- var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
157
-
158
- if (!it) {
159
- if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
160
- if (it) o = it;
161
- var i = 0;
162
-
163
- var F = function () {};
164
-
165
- return {
166
- s: F,
167
- n: function () {
168
- if (i >= o.length) return {
169
- done: true
170
- };
171
- return {
172
- done: false,
173
- value: o[i++]
174
- };
175
- },
176
- e: function (e) {
177
- throw e;
178
- },
179
- f: F
180
- };
181
- }
182
-
183
- throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
184
- }
185
-
186
- var normalCompletion = true,
187
- didErr = false,
188
- err;
189
- return {
190
- s: function () {
191
- it = it.call(o);
192
- },
193
- n: function () {
194
- var step = it.next();
195
- normalCompletion = step.done;
196
- return step;
197
- },
198
- e: function (e) {
199
- didErr = true;
200
- err = e;
201
- },
202
- f: function () {
203
- try {
204
- if (!normalCompletion && it.return != null) it.return();
205
- } finally {
206
- if (didErr) throw err;
207
- }
208
- }
209
- };
210
- }
211
-
212
- class Connector {
213
- /**
214
- * Create a new class instance.
215
- */
3
+ const LOG_PREFIX$2 = '[LE-AG-Websocket]';
4
+ const OPEN = 1;
5
+ class Websocket {
216
6
  constructor(options) {
7
+ this.buffer = [];
217
8
  /**
218
- * Default connector options.
9
+ * Every channel that should be subscribed, re-subscribed each time a new connection is identified.
219
10
  */
220
- this._defaultOptions = {
221
- auth: {
222
- headers: {},
223
- },
224
- authEndpoint: '/broadcasting/auth',
225
- broadcaster: 'pusher',
226
- csrfToken: null,
227
- host: null,
228
- key: null,
229
- namespace: 'App.Events',
11
+ this.channels = new Map();
12
+ this.listeners = {};
13
+ this.closing = false;
14
+ this.reconnectAttempts = 0;
15
+ this.options = options;
16
+ if (this.options.host) {
17
+ this.connect();
18
+ }
19
+ }
20
+ connect() {
21
+ const host = this.options.host;
22
+ this.debug(`Trying to connect to ${host}...`);
23
+ const websocket = new WebSocket(host);
24
+ this.websocket = websocket;
25
+ websocket.onopen = () => {
26
+ this.debug('Connected !');
27
+ this.reconnectAttempts = 0;
28
+ this.send({ event: 'whoami' });
29
+ while (this.buffer.length) {
30
+ this.send(this.buffer.shift());
31
+ }
32
+ this.startPing();
33
+ };
34
+ websocket.onmessage = (messageEvent) => {
35
+ this.handleMessage(messageEvent.data);
36
+ };
37
+ websocket.onerror = () => {
38
+ // A close event always follows an error, so reconnecting is handled in onclose.
39
+ this.debug('Connection error.');
40
+ };
41
+ websocket.onclose = () => {
42
+ if (this.websocket !== websocket) {
43
+ return;
44
+ }
45
+ this.debug('Connection closed.');
46
+ this.stopPing();
47
+ this.socketId = undefined;
48
+ if (!this.closing) {
49
+ this.scheduleReconnect();
50
+ }
230
51
  };
231
- this.setOptions(options);
232
- this.connect();
233
52
  }
234
- /**
235
- * Merge the custom options with the defaults.
236
- */
237
- setOptions(options) {
238
- this.options = Object.assign(this._defaultOptions, options);
239
- if (this.csrfToken()) {
240
- this.options.auth.headers['X-CSRF-TOKEN'] = this.csrfToken();
241
- }
242
- return options;
53
+ scheduleReconnect() {
54
+ var _a, _b;
55
+ const baseDelay = (_a = this.options.reconnectDelay) !== null && _a !== void 0 ? _a : 1000;
56
+ const maxDelay = (_b = this.options.maxReconnectDelay) !== null && _b !== void 0 ? _b : 30000;
57
+ const delay = Math.min(baseDelay * 2 ** this.reconnectAttempts, maxDelay);
58
+ this.reconnectAttempts++;
59
+ this.debug(`Connection lost, reconnecting in ${delay}ms...`);
60
+ clearTimeout(this.reconnectTimer);
61
+ this.reconnectTimer = setTimeout(() => this.connect(), delay);
62
+ }
63
+ startPing() {
64
+ var _a;
65
+ this.stopPing();
66
+ this.pingTimer = setInterval(() => {
67
+ if (this.socketIsReady()) {
68
+ this.debug('Sending ping');
69
+ this.send({ event: 'ping' });
70
+ }
71
+ }, (_a = this.options.pingInterval) !== null && _a !== void 0 ? _a : 60 * 1000);
243
72
  }
244
- /**
245
- * Extract the CSRF token from the page.
246
- */
247
- csrfToken() {
248
- let selector;
249
- if (typeof window !== 'undefined' && window['Laravel'] && window['Laravel'].csrfToken) {
250
- return window['Laravel'].csrfToken;
73
+ stopPing() {
74
+ clearInterval(this.pingTimer);
75
+ this.pingTimer = undefined;
76
+ }
77
+ handleMessage(body) {
78
+ var _a;
79
+ const message = this.parseMessage(body);
80
+ if (!message) {
81
+ return;
251
82
  }
252
- else if (this.options.csrfToken) {
253
- return this.options.csrfToken;
83
+ this.debug('onmessage', body);
84
+ if (message.channel) {
85
+ this.dispatch(message.channel, message.event, message.data);
86
+ return;
254
87
  }
255
- else if (typeof document !== 'undefined' &&
256
- typeof document.querySelector === 'function' &&
257
- (selector = document.querySelector('meta[name="csrf-token"]'))) {
258
- return selector.getAttribute('content');
88
+ if (message.event === 'whoami') {
89
+ this.socketId = (_a = message.data) === null || _a === void 0 ? void 0 : _a.socket_id;
90
+ this.debug(`Just set socketId to ${this.socketId}`);
91
+ this.channels.forEach((channel) => this.actuallySubscribe(channel));
259
92
  }
260
- return null;
261
93
  }
262
- }
263
-
264
- var LOG_PREFIX = '[LE-AG-Websocket]';
265
- var Websocket = /*#__PURE__*/function () {
266
- function Websocket(options) {
267
- _classCallCheck(this, Websocket);
268
-
269
- this.buffer = [];
270
- this.listeners = {};
271
- this.internalListeners = {};
272
- this.channelBacklog = [];
273
- this.closing = false;
274
- this.hasConnected = false;
275
- this.options = options;
276
- this.connect(this.options.host);
277
- return this;
278
- }
279
-
280
- _createClass(Websocket, [{
281
- key: "connect",
282
- value: function connect(host) {
283
- var _this = this;
284
-
285
- if (!host) {
286
- this.options.debug && console.error(LOG_PREFIX + "Cannont connect without host !");
287
- return;
288
- }
289
-
290
- this.options.debug && console.log(LOG_PREFIX + "Trying to connect to ".concat(host, "..."));
291
- this.websocket = new WebSocket(host);
292
-
293
- this.websocket.onerror = function () {
294
- if (!_this.hasConnected) {
295
- setTimeout(function () {
296
- _this.socketId = undefined;
297
-
298
- _this.connect(host);
299
- }, 3000);
94
+ dispatch(channelName, event, data) {
95
+ var _a, _b;
96
+ const callbacks = (_b = (_a = this.listeners[channelName]) === null || _a === void 0 ? void 0 : _a[event]) !== null && _b !== void 0 ? _b : [];
97
+ callbacks.slice().forEach((callback) => callback(data));
98
+ }
99
+ parseMessage(body) {
100
+ try {
101
+ return JSON.parse(body);
300
102
  }
301
- };
302
-
303
- this.websocket.onopen = function () {
304
- _this.options.debug && console.log(LOG_PREFIX + ' Connected !');
305
- _this.hasConnected = true;
306
-
307
- _this.send({
308
- event: 'whoami'
309
- });
310
-
311
- while (_this.buffer.length) {
312
- var message = _this.buffer[0];
313
-
314
- _this.send(message);
315
-
316
- _this.buffer.splice(0, 1);
317
- } // Register events only once connected, or they won't be registered if connection failed/lost
318
-
319
-
320
- _this.websocket.onmessage = function (messageEvent) {
321
- var message = _this.parseMessage(messageEvent.data);
322
-
323
- _this.options.debug && console.log(LOG_PREFIX + ' onmessage', messageEvent.data);
324
-
325
- if (!message) {
326
- return;
327
- }
328
-
329
- if (message.channel) {
330
- _this.options.debug && console.log("".concat(LOG_PREFIX, " Received event ").concat(message.event, " on channel ").concat(message.channel));
331
-
332
- if (_this.listeners[message.channel] && _this.listeners[message.channel][message.event]) {
333
- _this.listeners[message.channel][message.event](message.data);
334
- }
335
-
103
+ catch (error) {
104
+ this.options.debug && console.error(error);
105
+ return undefined;
106
+ }
107
+ }
108
+ getSocketId() {
109
+ return this.socketId;
110
+ }
111
+ socketIsReady() {
112
+ var _a;
113
+ return ((_a = this.websocket) === null || _a === void 0 ? void 0 : _a.readyState) === OPEN;
114
+ }
115
+ send(message) {
116
+ if (this.socketIsReady()) {
117
+ this.websocket.send(JSON.stringify(message));
336
118
  return;
337
- }
338
-
339
- if (_this.internalListeners[message.event]) {
340
- _this.internalListeners[message.event](message.data);
341
- }
342
- }; // send ping every 60 seconds to keep connection alive
343
-
344
-
345
- _this.pingInterval = setInterval(function () {
346
- if (_this.websocket.readyState === _this.websocket.OPEN) {
347
- _this.options.debug && console.log(LOG_PREFIX + ' Sending ping');
348
-
349
- _this.send({
350
- event: 'ping'
351
- });
352
- }
353
- }, 60 * 1000);
354
- };
355
-
356
- this.websocket.onclose = function () {
357
- _this.options.debug && console.info('Connection closed.');
358
-
359
- if (_this.closing) {
360
- return;
361
119
  }
362
-
363
- _this.hasConnected = false;
364
- _this.options.debug && console.info('Connection lost, reconnecting...');
365
- setTimeout(function () {
366
- _this.socketId = undefined;
367
-
368
- _this.connect(host);
369
- }, 1000);
370
- };
371
-
372
- this.on('whoami', function (_ref) {
373
- var socketId = _ref.socket_id;
374
- _this.socketId = socketId;
375
- _this.options.debug && console.log("".concat(LOG_PREFIX, " Just set socketId to ").concat(socketId)); // Handle the backlog and don't empty it, we'll need it if we lose connection
376
-
377
- var channel;
378
-
379
- var _iterator = _createForOfIteratorHelper(_this.channelBacklog),
380
- _step;
381
-
382
- try {
383
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
384
- channel = _step.value;
385
-
386
- _this.actuallySubscribe(channel);
387
- }
388
- } catch (err) {
389
- _iterator.e(err);
390
- } finally {
391
- _iterator.f();
120
+ this.buffer.push(message);
121
+ }
122
+ close() {
123
+ var _a;
124
+ this.closing = true;
125
+ clearTimeout(this.reconnectTimer);
126
+ this.stopPing();
127
+ (_a = this.websocket) === null || _a === void 0 ? void 0 : _a.close();
128
+ }
129
+ subscribe(channel) {
130
+ this.channels.set(channel.name, channel);
131
+ if (this.socketId && this.socketIsReady()) {
132
+ this.actuallySubscribe(channel);
392
133
  }
393
- });
394
- }
395
- }, {
396
- key: "parseMessage",
397
- value: function parseMessage(body) {
398
- try {
399
- return JSON.parse(body);
400
- } catch (error) {
401
- this.options.debug && console.error(error);
402
- return undefined;
403
- }
404
- }
405
- }, {
406
- key: "getSocketId",
407
- value: function getSocketId() {
408
- return this.socketId;
409
- }
410
- }, {
411
- key: "socketIsReady",
412
- value: function socketIsReady() {
413
- return this.websocket.readyState === this.websocket.OPEN;
414
- }
415
- }, {
416
- key: "send",
417
- value: function send(message) {
418
- if (this.socketIsReady()) {
419
- this.websocket.send(JSON.stringify(message));
420
- return;
421
- }
422
-
423
- this.buffer.push(message);
424
- }
425
- }, {
426
- key: "close",
427
- value: function close() {
428
- this.closing = true;
429
- this.internalListeners = {};
430
- clearInterval(this.pingInterval);
431
- this.pingInterval = undefined;
432
- this.websocket.close();
433
- }
434
- }, {
435
- key: "subscribe",
436
- value: function subscribe(channel) {
437
- if (this.getSocketId()) {
438
- this.actuallySubscribe(channel);
439
- } else {
440
- this.options.debug && console.log("".concat(LOG_PREFIX, " subscribe - push channel backlog for channel ").concat(channel.name));
441
- this.channelBacklog.push(channel);
442
- }
443
- }
444
- }, {
445
- key: "actuallySubscribe",
446
- value: function actuallySubscribe(channel) {
447
- var _this2 = this;
448
-
449
- if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
450
- this.options.debug && console.log("".concat(LOG_PREFIX, " Sending auth request for channel ").concat(channel.name));
451
-
452
- if (this.options.bearerToken) {
453
- this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
134
+ else {
135
+ this.debug(`Channel ${channel.name} will be subscribed once connected`);
454
136
  }
455
-
456
- axios__default['default'].post(this.options.authEndpoint, {
457
- socket_id: this.getSocketId(),
458
- channel_name: channel.name
459
- }, {
460
- headers: this.options.auth.headers || {}
461
- }).then(function (response) {
462
- _this2.options.debug && console.log("".concat(LOG_PREFIX, " Subscribing to private channel ").concat(channel.name));
463
-
464
- _this2.send({
465
- event: 'subscribe',
466
- data: _extends({
467
- channel: channel.name
468
- }, response.data)
469
- });
470
- })["catch"](function (error) {
471
- _this2.options.debug && console.log("".concat(LOG_PREFIX, " Auth request for channel ").concat(channel.name, " failed"));
472
- _this2.options.debug && console.error(error);
137
+ }
138
+ actuallySubscribe(channel) {
139
+ if (!channel.name.startsWith('private-') && !channel.name.startsWith('presence-')) {
140
+ this.debug(`Subscribing to channel ${channel.name}`);
141
+ this.send({ event: 'subscribe', data: { channel: channel.name } });
142
+ return;
143
+ }
144
+ const socketId = this.socketId;
145
+ this.debug(`Sending auth request for channel ${channel.name}`);
146
+ this.authorize(channel.name, socketId).then((data) => {
147
+ // Skip outdated authorizations: the connection changed or the channel was left meanwhile.
148
+ if (socketId !== this.socketId || this.channels.get(channel.name) !== channel) {
149
+ return;
150
+ }
151
+ this.debug(`Subscribing to private channel ${channel.name}`);
152
+ this.send({ event: 'subscribe', data: Object.assign({ channel: channel.name }, data) });
153
+ }).catch((error) => {
154
+ this.debug(`Auth request for channel ${channel.name} failed`, error);
155
+ this.dispatch(channel.name, 'error', error);
473
156
  });
474
- } else {
475
- this.options.debug && console.log("".concat(LOG_PREFIX, " Subscribing to channel ").concat(channel.name));
476
- this.send({
477
- event: 'subscribe',
478
- data: {
479
- channel: channel.name
480
- }
157
+ }
158
+ authorize(channelName, socketId) {
159
+ var _a, _b, _c;
160
+ const channelAuthorization = (_a = this.options.channelAuthorization) !== null && _a !== void 0 ? _a : {};
161
+ if (typeof channelAuthorization.customHandler === 'function') {
162
+ return new Promise((resolve, reject) => {
163
+ channelAuthorization.customHandler({ socketId, channelName }, (error, data) => {
164
+ var _a;
165
+ if (error) {
166
+ reject(this.authorizationError(error, (_a = error === null || error === void 0 ? void 0 : error.status) !== null && _a !== void 0 ? _a : null));
167
+ }
168
+ else {
169
+ resolve(data);
170
+ }
171
+ });
172
+ });
173
+ }
174
+ return fetch((_b = channelAuthorization.endpoint) !== null && _b !== void 0 ? _b : this.options.authEndpoint, {
175
+ method: 'POST',
176
+ headers: Object.assign(Object.assign({ 'Content-Type': 'application/json', 'Accept': 'application/json' }, (_c = this.options.auth) === null || _c === void 0 ? void 0 : _c.headers), channelAuthorization.headers),
177
+ body: JSON.stringify({
178
+ socket_id: socketId,
179
+ channel_name: channelName,
180
+ }),
181
+ }).then((response) => {
182
+ if (!response.ok) {
183
+ throw this.authorizationError(new Error(`Auth request failed: ${response.status}`), response.status);
184
+ }
185
+ return response.json();
186
+ }, (error) => {
187
+ throw this.authorizationError(error, null);
481
188
  });
482
- }
483
- }
484
- }, {
485
- key: "unsubscribe",
486
- value: function unsubscribe(channel) {
487
- this.options.debug && console.log("".concat(LOG_PREFIX, " unsubscribe for channel ").concat(channel.name));
488
- this.send({
489
- event: 'unsubscribe',
490
- data: {
491
- channel: channel.name
189
+ }
190
+ authorizationError(error, status) {
191
+ return { type: 'AuthError', status, error };
192
+ }
193
+ unsubscribe(channel) {
194
+ this.debug(`unsubscribe for channel ${channel.name}`);
195
+ if (this.channels.get(channel.name) === channel) {
196
+ this.channels.delete(channel.name);
197
+ delete this.listeners[channel.name];
198
+ }
199
+ if (this.socketId && this.socketIsReady()) {
200
+ this.send({ event: 'unsubscribe', data: { channel: channel.name } });
492
201
  }
493
- });
494
-
495
- if (this.listeners[channel.name]) {
496
- delete this.listeners[channel.name];
497
- }
498
- }
499
- }, {
500
- key: "on",
501
- value: function on(event) {
502
- var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
503
- this.options.debug && console.log("".concat(LOG_PREFIX, " on event ").concat(event, " ..."));
504
- this.internalListeners[event] = callback;
505
- }
506
- }, {
507
- key: "bind",
508
- value: function bind(channel, event, callback) {
509
- this.options.debug && console.log("".concat(LOG_PREFIX, " bind event ").concat(event, " for channel ").concat(channel.name, " ..."));
510
-
511
- if (!this.listeners[channel.name]) {
512
- this.listeners[channel.name] = {};
513
- }
514
-
515
- this.listeners[channel.name][event] = callback;
516
202
  }
517
- }, {
518
- key: "unbindEvent",
519
- value: function unbindEvent(channel, event) {
520
- var callback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
521
- this.options.debug && console.log("".concat(LOG_PREFIX, " unbind event ").concat(event, " for channel ").concat(channel.name, " ..."));
522
-
523
- if (this.internalListeners[event] && (callback === null || this.internalListeners[event] === callback)) {
524
- delete this.internalListeners[event];
525
- }
203
+ bind(channel, event, callback) {
204
+ var _a, _b;
205
+ var _c, _d, _e;
206
+ this.debug(`bind event ${event} for channel ${channel.name} ...`);
207
+ (_a = (_c = this.listeners)[_d = channel.name]) !== null && _a !== void 0 ? _a : (_c[_d] = {});
208
+ (_b = (_e = this.listeners[channel.name])[event]) !== null && _b !== void 0 ? _b : (_e[event] = []);
209
+ this.listeners[channel.name][event].push(callback);
210
+ }
211
+ unbind(channel, event, callback) {
212
+ var _a;
213
+ this.debug(`unbind event ${event} for channel ${channel.name} ...`);
214
+ const callbacks = (_a = this.listeners[channel.name]) === null || _a === void 0 ? void 0 : _a[event];
215
+ if (!callbacks) {
216
+ return;
217
+ }
218
+ if (callback) {
219
+ this.listeners[channel.name][event] = callbacks.filter((existing) => existing !== callback);
220
+ }
221
+ else {
222
+ delete this.listeners[channel.name][event];
223
+ }
526
224
  }
527
- }]);
528
-
529
- return Websocket;
530
- }();
225
+ debug(...messages) {
226
+ this.options.debug && console.log(LOG_PREFIX$2, ...messages);
227
+ }
228
+ }
531
229
 
532
230
  /**
533
- * Event name formatter
231
+ * Formats event names the same way laravel-echo does, so `listen('OrderCreated')` matches
232
+ * `App\Events\OrderCreated` and `listen('.custom-name')` matches `custom-name`.
534
233
  */
535
234
  class EventFormatter {
536
- /**
537
- * Create a new class instance.
538
- */
539
235
  constructor(namespace) {
540
- this.setNamespace(namespace);
236
+ this.namespace = namespace;
541
237
  }
542
- /**
543
- * Format the given event name.
544
- */
545
238
  format(event) {
546
- if (event.charAt(0) === '.' || event.charAt(0) === '\\') {
547
- return event.substr(1);
239
+ if (['.', '\\'].includes(event.charAt(0))) {
240
+ return event.substring(1);
548
241
  }
549
- else if (this.namespace) {
242
+ if (this.namespace) {
550
243
  event = this.namespace + '.' + event;
551
244
  }
552
245
  return event.replace(/\./g, '\\');
553
246
  }
554
- /**
555
- * Set the event namespace.
556
- */
557
- setNamespace(value) {
558
- this.namespace = value;
247
+ setNamespace(namespace) {
248
+ this.namespace = namespace;
559
249
  }
560
250
  }
561
251
 
252
+ const LOG_PREFIX$1 = '[LE-AG-Channel]';
253
+ const NOTIFICATION_EVENT = '.Illuminate\\Notifications\\Events\\BroadcastNotificationCreated';
562
254
  /**
563
- * This class represents a basic channel.
255
+ * A channel on the API Gateway websocket. It implements the public, private and presence channel
256
+ * interfaces of laravel-echo (v1 and v2) without extending its internal classes.
564
257
  */
565
258
  class Channel {
259
+ /**
260
+ * Create a new class instance.
261
+ */
262
+ constructor(socket, name, options) {
263
+ this.name = name;
264
+ this.socket = socket;
265
+ this.options = options;
266
+ this.eventFormatter = new EventFormatter(this.options.namespace);
267
+ this.subscribe();
268
+ }
269
+ /**
270
+ * Subscribe to the channel.
271
+ */
272
+ subscribe() {
273
+ this.options.debug && console.log(`${LOG_PREFIX$1} subscribe for channel ${this.name} ...`);
274
+ this.socket.subscribe(this);
275
+ }
276
+ /**
277
+ * Unsubscribe from the channel.
278
+ */
279
+ unsubscribe() {
280
+ this.options.debug && console.log(`${LOG_PREFIX$1} unsubscribe for channel ${this.name} ...`);
281
+ this.socket.unsubscribe(this);
282
+ }
283
+ /**
284
+ * Listen for an event on the channel instance.
285
+ */
286
+ listen(event, callback) {
287
+ this.options.debug && console.log(`${LOG_PREFIX$1} listen to ${event} for channel ${this.name} ...`);
288
+ return this.on(this.eventFormatter.format(event), callback);
289
+ }
290
+ /**
291
+ * Stop listening for an event on the channel instance. Without a callback, every listener of the event is removed.
292
+ */
293
+ stopListening(event, callback) {
294
+ this.options.debug && console.log(`${LOG_PREFIX$1} stop listening to ${event} for channel ${this.name} ...`);
295
+ this.socket.unbind(this, this.eventFormatter.format(event), callback);
296
+ return this;
297
+ }
566
298
  /**
567
299
  * Listen for a whisper event on the channel instance.
568
300
  */
569
301
  listenForWhisper(event, callback) {
570
302
  return this.listen('.client-' + event, callback);
571
303
  }
304
+ /**
305
+ * Stop listening for a whisper event on the channel instance.
306
+ */
307
+ stopListeningForWhisper(event, callback) {
308
+ return this.stopListening('.client-' + event, callback);
309
+ }
572
310
  /**
573
311
  * Listen for an event on the channel instance.
574
312
  */
575
313
  notification(callback) {
576
- return this.listen('.Illuminate\\Notifications\\Events\\BroadcastNotificationCreated', callback);
314
+ return this.listen(NOTIFICATION_EVENT, callback);
577
315
  }
578
316
  /**
579
- * Stop listening for a whisper event on the channel instance.
317
+ * Stop listening for notification events on the channel instance.
580
318
  */
581
- stopListeningForWhisper(event, callback) {
582
- return this.stopListening('.client-' + event, callback);
319
+ stopListeningForNotification(callback) {
320
+ return this.stopListening(NOTIFICATION_EVENT, callback);
583
321
  }
584
- }
585
-
586
- var LOG_PREFIX$1 = '[LE-AG-Channel]';
587
- /**
588
- * This class represents a Pusher channel.
589
- */
590
-
591
- var Channel$1 = /*#__PURE__*/function (_BaseChannel) {
592
- _inherits(Channel, _BaseChannel);
593
-
594
- var _super = _createSuper(Channel);
595
-
596
- /**
597
- * Create a new class instance.
598
- */
599
- function Channel(socket, name, options) {
600
- var _this;
601
-
602
- _classCallCheck(this, Channel);
603
-
604
- _this = _super.call(this);
605
- _this.name = name;
606
- _this.socket = socket;
607
- _this.options = options;
608
- _this.eventFormatter = new EventFormatter(_this.options["namespace"]);
609
-
610
- _this.subscribe();
611
-
612
- return _this;
613
- }
614
- /**
615
- * Subscribe to a Pusher channel.
616
- */
617
-
618
-
619
- _createClass(Channel, [{
620
- key: "subscribe",
621
- value: function subscribe() {
622
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " subscribe for channel ").concat(this.name, " ..."));
623
- this.socket.subscribe(this);
322
+ /**
323
+ * Register a callback to be called anytime a subscription succeeds.
324
+ */
325
+ subscribed(callback) {
326
+ return this.on('subscription_succeeded', () => {
327
+ callback();
328
+ });
624
329
  }
625
330
  /**
626
- * Unsubscribe from a Pusher channel.
331
+ * Register a callback to be called anytime a subscription or authorization error occurs.
627
332
  */
628
-
629
- }, {
630
- key: "unsubscribe",
631
- value: function unsubscribe() {
632
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " unsubscribe for channel ").concat(this.name, " ..."));
633
- this.socket.unsubscribe(this);
333
+ error(callback) {
334
+ return this.on('error', callback);
634
335
  }
635
336
  /**
636
- * Listen for an event on the channel instance.
337
+ * Bind a channel to an event.
637
338
  */
638
-
639
- }, {
640
- key: "listen",
641
- value: function listen(event, callback) {
642
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " listen to ").concat(event, " for channel ").concat(this.name, " ..."));
643
- this.on(this.eventFormatter.format(event), callback);
644
- return this;
339
+ on(event, callback) {
340
+ this.options.debug && console.log(`${LOG_PREFIX$1} on ${event} for channel ${this.name} ...`);
341
+ this.socket.bind(this, event, callback);
342
+ return this;
645
343
  }
646
344
  /**
647
- * Stop listening for an event on the channel instance.
345
+ * Send a client event to the other members of the channel.
648
346
  */
649
-
650
- }, {
651
- key: "stopListening",
652
- value: function stopListening(event, callback) {
653
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " stop listening to ").concat(event, " for channel ").concat(this.name, " ..."));
654
- this.socket.unbindEvent(this, event, callback);
655
- return this;
347
+ whisper(event, data) {
348
+ this.socket.send({
349
+ event: 'client-' + event,
350
+ channel: this.name,
351
+ data,
352
+ });
353
+ return this;
656
354
  }
657
355
  /**
658
- * Register a callback to be called anytime a subscription succeeds.
356
+ * Presence channels are not supported yet: member tracking is not implemented on the server.
659
357
  */
660
-
661
- }, {
662
- key: "subscribed",
663
- value: function subscribed(callback) {
664
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " subscribed for channel ").concat(this.name, " ..."));
665
- this.on('subscription_succeeded', function () {
666
- callback();
667
- });
668
- return this;
358
+ here(_callback) {
359
+ return this;
669
360
  }
670
361
  /**
671
- * Register a callback to be called anytime a subscription error occurs.
362
+ * Presence channels are not supported yet: member tracking is not implemented on the server.
672
363
  */
673
-
674
- }, {
675
- key: "error",
676
- value: function error(callback) {
677
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " error for channel ").concat(this.name, " ..."));
678
- this.on('error', function (status) {
679
- callback(status);
680
- });
681
- return this;
364
+ joining(_callback) {
365
+ return this;
682
366
  }
683
367
  /**
684
- * Bind a channel to an event.
368
+ * Presence channels are not supported yet: member tracking is not implemented on the server.
685
369
  */
370
+ leaving(_callback) {
371
+ return this;
372
+ }
373
+ }
686
374
 
687
- }, {
688
- key: "on",
689
- value: function on(event, callback) {
690
- this.options["debug"] && console.log("".concat(LOG_PREFIX$1, " on ").concat(event, " for channel ").concat(this.name, " ..."));
691
- this.socket.bind(this, event, callback);
692
- return this;
693
- }
694
- }, {
695
- key: "whisper",
696
- value: function whisper(event, data) {
697
- var channel = this.name;
698
- var formattedEvent = "client-" + event;
699
- this.socket.send({
700
- "event": formattedEvent,
701
- data: data,
702
- channel: channel
703
- });
704
- return this;
705
- }
706
- }, {
707
- key: "here",
708
- value: function here(callback) {
709
- // TODO: implement
710
- return this;
375
+ const LOG_PREFIX = '[LE-AG-Connector]';
376
+ /**
377
+ * Laravel Echo connector for API Gateway websockets.
378
+ *
379
+ * It does not extend laravel-echo's internal classes, so it works with laravel-echo v1 and v2:
380
+ * both create custom connectors with `new options.broadcaster(options)`.
381
+ */
382
+ class Connector {
383
+ /**
384
+ * Create a new class instance. Without a host no connection is opened, which keeps
385
+ * laravel-echo v2's `new broadcaster()` capability check free of side effects.
386
+ */
387
+ constructor(options = {}) {
388
+ /**
389
+ * All of the subscribed channel names.
390
+ */
391
+ this.channels = {};
392
+ this.setOptions(options);
393
+ this.connect();
711
394
  }
712
395
  /**
713
- * Listen for someone joining the channel.
396
+ * Merge the custom options with the defaults and add the CSRF and bearer token headers.
714
397
  */
715
-
716
- }, {
717
- key: "joining",
718
- value: function joining(callback) {
719
- // TODO: implement
720
- return this;
398
+ setOptions(options) {
399
+ var _a, _b;
400
+ this.options = Object.assign(Object.assign(Object.assign({}, Connector._defaultOptions), options), { auth: {
401
+ headers: Object.assign({}, ((_b = (_a = options.auth) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : {})),
402
+ } });
403
+ const csrfToken = this.csrfToken();
404
+ if (csrfToken) {
405
+ this.options.auth.headers['X-CSRF-TOKEN'] = csrfToken;
406
+ }
407
+ if (this.options.bearerToken) {
408
+ this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
409
+ }
721
410
  }
722
411
  /**
723
- * Listen for someone leaving the channel.
412
+ * Extract the CSRF token from the page.
724
413
  */
725
-
726
- }, {
727
- key: "leaving",
728
- value: function leaving(callback) {
729
- // TODO: implement
730
- return this;
414
+ csrfToken() {
415
+ var _a, _b, _c;
416
+ if (typeof window !== 'undefined' && ((_a = window.Laravel) === null || _a === void 0 ? void 0 : _a.csrfToken)) {
417
+ return window.Laravel.csrfToken;
418
+ }
419
+ if (this.options.csrfToken) {
420
+ return this.options.csrfToken;
421
+ }
422
+ if (typeof document !== 'undefined' && typeof document.querySelector === 'function') {
423
+ return (_c = (_b = document.querySelector('meta[name="csrf-token"]')) === null || _b === void 0 ? void 0 : _b.getAttribute('content')) !== null && _c !== void 0 ? _c : null;
424
+ }
425
+ return null;
731
426
  }
732
- }]);
733
-
734
- return Channel;
735
- }(Channel);
736
-
737
- var broadcaster = function broadcaster(options) {
738
- return new Connector$1(options);
739
- };
740
- var LOG_PREFIX$2 = '[LE-AG-Connector]';
741
- var Connector$1 = /*#__PURE__*/function (_BaseConnector) {
742
- _inherits(Connector, _BaseConnector);
743
-
744
- var _super = _createSuper(Connector);
745
-
746
- /**
747
- * Create a new class instance.
748
- */
749
- function Connector(options) {
750
- var _this;
751
-
752
- _classCallCheck(this, Connector);
753
-
754
- _this = _super.call(this, options);
755
427
  /**
756
- * All of the subscribed channel names.
428
+ * Create a fresh websocket connection.
757
429
  */
758
-
759
- _this.channels = {};
760
- return _this;
761
- }
762
- /**
763
- * Create a fresh Socket.io connection.
764
- */
765
-
766
-
767
- _createClass(Connector, [{
768
- key: "connect",
769
- value: function connect() {
770
- this.options.debug && console.log(LOG_PREFIX$2 + 'Connect ...');
771
- this.socket = new Websocket(this.options);
772
- return; //
773
- // this.socket.on('reconnect', () => {
774
- // Object.values(this.channels).forEach((channel) => {
775
- // channel.subscribe();
776
- // });
777
- // });
778
- //
779
- // return this.socket;
430
+ connect() {
431
+ this.options.debug && console.log(LOG_PREFIX + ' Connect ...');
432
+ this.socket = new Websocket(this.options);
433
+ }
434
+ /**
435
+ * Listen for an event on a channel instance.
436
+ */
437
+ listen(name, event, callback) {
438
+ return this.channel(name).listen(event, callback);
780
439
  }
781
440
  /**
782
441
  * Get a channel instance by name.
783
442
  */
784
-
785
- }, {
786
- key: "channel",
787
- value: function channel(name) {
788
- if (!this.channels[name]) {
789
- this.channels[name] = new Channel$1(this.socket, name, this.options);
790
- }
791
-
792
- return this.channels[name];
443
+ channel(name) {
444
+ if (!this.channels[name]) {
445
+ this.channels[name] = new Channel(this.socket, name, this.options);
446
+ }
447
+ return this.channels[name];
793
448
  }
794
449
  /**
795
450
  * Get a private channel instance by name.
796
451
  */
797
-
798
- }, {
799
- key: "privateChannel",
800
- value: function privateChannel(name) {
801
- if (!this.channels['private-' + name]) {
802
- this.channels['private-' + name] = new Channel$1(this.socket, 'private-' + name, this.options);
803
- }
804
-
805
- return this.channels['private-' + name];
452
+ privateChannel(name) {
453
+ return this.channel('private-' + name);
806
454
  }
807
455
  /**
808
456
  * Get a presence channel instance by name.
809
457
  */
810
-
811
- }, {
812
- key: "presenceChannel",
813
- value: function presenceChannel(name) {
814
- if (!this.channels['presence-' + name]) {
815
- this.channels['presence-' + name] = new Channel$1(this.socket, 'presence-' + name, this.options);
816
- }
817
-
818
- return this.channels['presence-' + name];
458
+ presenceChannel(name) {
459
+ return this.channel('presence-' + name);
819
460
  }
820
461
  /**
821
462
  * Leave the given channel, as well as its private and presence variants.
822
463
  */
823
-
824
- }, {
825
- key: "leave",
826
- value: function leave(name) {
827
- var _this2 = this;
828
-
829
- var channels = [name, 'private-' + name, 'presence-' + name];
830
- channels.forEach(function (name) {
831
- _this2.leaveChannel(name);
832
- });
464
+ leave(name) {
465
+ [name, 'private-' + name, 'presence-' + name].forEach((channelName) => {
466
+ this.leaveChannel(channelName);
467
+ });
833
468
  }
834
469
  /**
835
470
  * Leave the given channel.
836
471
  */
837
-
838
- }, {
839
- key: "leaveChannel",
840
- value: function leaveChannel(name) {
841
- if (this.channels[name]) {
842
- this.channels[name].unsubscribe();
843
- delete this.channels[name];
844
- }
472
+ leaveChannel(name) {
473
+ if (this.channels[name]) {
474
+ this.channels[name].unsubscribe();
475
+ delete this.channels[name];
476
+ }
845
477
  }
846
478
  /**
847
479
  * Get the socket ID for the connection.
848
480
  */
849
-
850
- }, {
851
- key: "socketId",
852
- value: function socketId() {
853
- return this.socket.getSocketId();
481
+ socketId() {
482
+ return this.socket.getSocketId();
854
483
  }
855
484
  /**
856
485
  * Disconnect socket connection.
857
486
  */
858
-
859
- }, {
860
- key: "disconnect",
861
- value: function disconnect() {
862
- this.options.debug && console.log(LOG_PREFIX$2 + 'Disconnect ...');
863
- this.socket.close();
487
+ disconnect() {
488
+ this.options.debug && console.log(LOG_PREFIX + ' Disconnect ...');
489
+ this.socket.close();
864
490
  }
865
- }]);
866
-
867
- return Connector;
868
- }(Connector);
491
+ }
492
+ /**
493
+ * Default connector options, matching laravel-echo's defaults.
494
+ */
495
+ Connector._defaultOptions = {
496
+ auth: {
497
+ headers: {},
498
+ },
499
+ authEndpoint: '/broadcasting/auth',
500
+ csrfToken: null,
501
+ bearerToken: null,
502
+ host: null,
503
+ namespace: 'App.Events',
504
+ };
505
+ /**
506
+ * Kept for backwards compatibility: `new Echo({ broadcaster })`. A function declaration (not an arrow
507
+ * function) so laravel-echo can call it with `new`.
508
+ */
509
+ function broadcaster(options) {
510
+ return new Connector(options);
511
+ }
869
512
 
870
- exports.Connector = Connector$1;
513
+ exports.Channel = Channel;
514
+ exports.Connector = Connector;
515
+ exports.EventFormatter = EventFormatter;
871
516
  exports.broadcaster = broadcaster;