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