@webex/internal-plugin-mobius-socket 0.0.0-next.1

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.
@@ -0,0 +1,916 @@
1
+ "use strict";
2
+
3
+ var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");
4
+ var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");
5
+ var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");
6
+ var _Array$isArray = require("@babel/runtime-corejs2/core-js/array/is-array");
7
+ var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
8
+ var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
9
+ var _Object$getOwnPropertyDescriptor2 = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
10
+ var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
11
+ var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
12
+ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
13
+ var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
14
+ _Object$defineProperty(exports, "__esModule", {
15
+ value: true
16
+ });
17
+ exports.default = void 0;
18
+ var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
19
+ var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
20
+ var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
21
+ var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
22
+ var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
23
+ var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
24
+ var _deleteProperty = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/reflect/delete-property"));
25
+ var _getOwnPropertyDescriptor = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor"));
26
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/toConsumableArray"));
27
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
28
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
29
+ var _applyDecoratedDescriptor2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/applyDecoratedDescriptor"));
30
+ var _url = _interopRequireDefault(require("url"));
31
+ var _webexCore = require("@webex/webex-core");
32
+ var _common = require("@webex/common");
33
+ var _lodash = require("lodash");
34
+ var _backoff = _interopRequireDefault(require("backoff"));
35
+ var _socket = _interopRequireDefault(require("./socket"));
36
+ var _errors = require("./errors");
37
+ var _dec, _dec2, _obj;
38
+ /* eslint-disable require-jsdoc */
39
+ /*!
40
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
41
+ */
42
+ function ownKeys(e, r) { var t = _Object$keys2(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor2(e, r).enumerable; })), t.push.apply(t, o); } return t; }
43
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor2(t, r)); }); } return e; }
44
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof _Symbol && r[_Symbol$iterator] || r["@@iterator"]; if (!t) { if (_Array$isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
45
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? _Array$from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
46
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
47
+ var normalReconnectReasons = ['idle', 'done (forced)', 'pong not received', 'pong mismatch'];
48
+ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mercury#listen(): Use Mercury#connect() instead'), _dec2 = (0, _common.deprecated)('Mercury#stopListening(): Use Mercury#disconnect() instead'), _obj = {
49
+ namespace: 'Mercury',
50
+ lastError: undefined,
51
+ defaultSessionId: 'mercury-default-session',
52
+ session: {
53
+ connected: {
54
+ default: false,
55
+ type: 'boolean'
56
+ },
57
+ connecting: {
58
+ default: false,
59
+ type: 'boolean'
60
+ },
61
+ hasEverConnected: {
62
+ default: false,
63
+ type: 'boolean'
64
+ },
65
+ sockets: {
66
+ default: function _default() {
67
+ return new _map.default();
68
+ },
69
+ type: 'object'
70
+ },
71
+ backoffCalls: {
72
+ default: function _default() {
73
+ return new _map.default();
74
+ },
75
+ type: 'object'
76
+ },
77
+ _shutdownSwitchoverBackoffCalls: {
78
+ default: function _default() {
79
+ return new _map.default();
80
+ },
81
+ type: 'object'
82
+ },
83
+ localClusterServiceUrls: 'object',
84
+ mercuryTimeOffset: {
85
+ default: undefined,
86
+ type: 'number'
87
+ }
88
+ },
89
+ derived: {
90
+ listening: {
91
+ deps: ['connected'],
92
+ fn: function fn() {
93
+ return this.connected;
94
+ }
95
+ }
96
+ },
97
+ initialize: function initialize() {
98
+ var _this = this;
99
+ /*
100
+ When one of these legacy feature gets updated, this event would be triggered
101
+ * group-message-notifications
102
+ * mention-notifications
103
+ * thread-notifications
104
+ */
105
+ this.on('event:featureToggle_update', function (envelope) {
106
+ if (envelope && envelope.data) {
107
+ _this.webex.internal.feature.updateFeature(envelope.data.featureToggle);
108
+ }
109
+ });
110
+ /*
111
+ * When Cluster Migrations, notify clients using ActiveClusterStatusEvent via mercury
112
+ * https://wwwin-github.cisco.com/pages/Webex/crr-docs/techdocs/rr-002.html#wip-notifying-clients-of-cluster-migrations
113
+ * */
114
+ this.on('event:ActiveClusterStatusEvent', function (envelope) {
115
+ var _this$webex$internal$;
116
+ if (typeof ((_this$webex$internal$ = _this.webex.internal.services) === null || _this$webex$internal$ === void 0 ? void 0 : _this$webex$internal$.switchActiveClusterIds) === 'function' && envelope && envelope.data) {
117
+ var _envelope$data;
118
+ _this.webex.internal.services.switchActiveClusterIds((_envelope$data = envelope.data) === null || _envelope$data === void 0 ? void 0 : _envelope$data.activeClusters);
119
+ }
120
+ });
121
+ /*
122
+ * Using cache-invalidation via mercury to instead the method of polling via the new /timestamp endpoint from u2c
123
+ * https://wwwin-github.cisco.com/pages/Webex/crr-docs/techdocs/rr-005.html#websocket-notifications
124
+ * */
125
+ this.on('event:u2c.cache-invalidation', function (envelope) {
126
+ var _this$webex$internal$2;
127
+ if (typeof ((_this$webex$internal$2 = _this.webex.internal.services) === null || _this$webex$internal$2 === void 0 ? void 0 : _this$webex$internal$2.invalidateCache) === 'function' && envelope && envelope.data) {
128
+ var _envelope$data2;
129
+ _this.webex.internal.services.invalidateCache((_envelope$data2 = envelope.data) === null || _envelope$data2 === void 0 ? void 0 : _envelope$data2.timestamp);
130
+ }
131
+ });
132
+ },
133
+ /**
134
+ * Attach event listeners to a socket.
135
+ * @param {Socket} socket - The socket to attach listeners to
136
+ * @param {sessionId} sessionId - The socket related session ID
137
+ * @returns {void}
138
+ */
139
+ _attachSocketEventListeners: function _attachSocketEventListeners(socket, sessionId) {
140
+ var _this2 = this;
141
+ socket.on('close', function (event) {
142
+ return _this2._onclose(sessionId, event, socket);
143
+ });
144
+ socket.on('message', function () {
145
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
146
+ args[_key] = arguments[_key];
147
+ }
148
+ return _this2._onmessage.apply(_this2, [sessionId].concat(args));
149
+ });
150
+ socket.on('pong', function () {
151
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
152
+ args[_key2] = arguments[_key2];
153
+ }
154
+ return _this2._setTimeOffset.apply(_this2, [sessionId].concat(args));
155
+ });
156
+ socket.on('sequence-mismatch', function () {
157
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
158
+ args[_key3] = arguments[_key3];
159
+ }
160
+ return _this2._emit.apply(_this2, [sessionId, 'sequence-mismatch'].concat(args));
161
+ });
162
+ socket.on('ping-pong-latency', function () {
163
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
164
+ args[_key4] = arguments[_key4];
165
+ }
166
+ return _this2._emit.apply(_this2, [sessionId, 'ping-pong-latency'].concat(args));
167
+ });
168
+ },
169
+ /**
170
+ * Handle imminent shutdown by establishing a new connection while keeping
171
+ * the current one alive (make-before-break).
172
+ * Idempotent: will no-op if already in progress.
173
+ * @param {string} sessionId - The session ID for which the shutdown is imminent
174
+ * @returns {void}
175
+ */
176
+ _handleImminentShutdown: function _handleImminentShutdown(sessionId) {
177
+ var _this3 = this;
178
+ var oldSocket = this.sockets.get(sessionId);
179
+ try {
180
+ // Idempotent: if we already have a switchover backoff call for this session,
181
+ // a switchover is in progress – do nothing.
182
+ if (this._shutdownSwitchoverBackoffCalls.get(sessionId)) {
183
+ this.logger.info("".concat(this.namespace, ": [shutdown] switchover already in progress for ").concat(sessionId));
184
+ return;
185
+ }
186
+ this._shutdownSwitchoverId = "".concat((0, _now.default)());
187
+ this.logger.info("".concat(this.namespace, ": [shutdown] switchover start, id=").concat(this._shutdownSwitchoverId, " for ").concat(sessionId));
188
+ this._connectWithBackoff(undefined, sessionId, {
189
+ isShutdownSwitchover: true,
190
+ attemptOptions: {
191
+ isShutdownSwitchover: true,
192
+ onSuccess: function onSuccess(newSocket, webSocketUrl) {
193
+ _this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover connected, url: ").concat(webSocketUrl, " for ").concat(sessionId));
194
+
195
+ // Atomically switch active socket reference
196
+ _this3.socket = _this3.sockets.get(_this3.defaultSessionId);
197
+ _this3.connected = _this3.hasConnectedSockets(); // remain connected throughout
198
+
199
+ _this3._emit(sessionId, 'event:mercury_shutdown_switchover_complete', {
200
+ url: webSocketUrl
201
+ });
202
+ if (oldSocket) {
203
+ _this3.logger.info("".concat(_this3.namespace, ": [shutdown] old socket retained; server will close with 4001"));
204
+ }
205
+ }
206
+ }
207
+ }).then(function () {
208
+ _this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover completed successfully for ").concat(sessionId));
209
+ }).catch(function (err) {
210
+ _this3.logger.info("".concat(_this3.namespace, ": [shutdown] switchover exhausted retries; will fall back to normal reconnection for ").concat(sessionId, ": "), err);
211
+ _this3._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {
212
+ reason: err
213
+ });
214
+ // Old socket will eventually close with 4001, triggering normal reconnection
215
+ });
216
+ } catch (e) {
217
+ this.logger.error("".concat(this.namespace, ": [shutdown] error during switchover for ").concat(sessionId), e);
218
+ this._shutdownSwitchoverBackoffCalls.delete(sessionId);
219
+ this._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {
220
+ reason: e
221
+ });
222
+ }
223
+ },
224
+ /**
225
+ * Get the last error.
226
+ * @returns {any} The last error.
227
+ */
228
+ getLastError: function getLastError() {
229
+ return this.lastError;
230
+ },
231
+ /**
232
+ * Get all active socket connections
233
+ * @returns {Map} Map of sessionId to socket instances
234
+ */
235
+ getSockets: function getSockets() {
236
+ return this.sockets;
237
+ },
238
+ /**
239
+ * Get a specific socket by connection ID
240
+ * @param {string} sessionId - The connection identifier
241
+ * @returns {Socket|undefined} The socket instance or undefined if not found
242
+ */
243
+ getSocket: function getSocket() {
244
+ var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
245
+ return this.sockets.get(sessionId);
246
+ },
247
+ /**
248
+ * Check if a socket is connected
249
+ * @param {string} [sessionId=this.defaultSessionId] - The session identifier
250
+ * @returns {boolean|undefined} True if the socket is connected
251
+ */
252
+ hasConnectedSockets: function hasConnectedSockets() {
253
+ var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
254
+ var socket = this.sockets.get(sessionId || this.defaultSessionId);
255
+ return socket === null || socket === void 0 ? void 0 : socket.connected;
256
+ },
257
+ /**
258
+ * Check if any sockets are connecting
259
+ * @param {string} [sessionId=this.defaultSessionId] - The session identifier
260
+ * @returns {boolean|undefined} True if the socket is connecting
261
+ */
262
+ hasConnectingSockets: function hasConnectingSockets() {
263
+ var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
264
+ var socket = this.sockets.get(sessionId || this.defaultSessionId);
265
+ return socket === null || socket === void 0 ? void 0 : socket.connecting;
266
+ },
267
+ /**
268
+ * Connect to Mercury for a specific session.
269
+ * @param {string} [webSocketUrl] - Optional websocket URL override. Falls back to the device websocket URL.
270
+ * @param {string} [sessionId=this.defaultSessionId] - The session identifier for this connection.
271
+ * @returns {Promise<void>} Resolves when connection flow completes for the session.
272
+ */
273
+ connect: function connect(webSocketUrl) {
274
+ var _this4 = this;
275
+ var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
276
+ if (!this._connectPromises) this._connectPromises = new _map.default();
277
+
278
+ // First check if there's already a connection promise for this session
279
+ if (this._connectPromises.has(sessionId)) {
280
+ this.logger.info("".concat(this.namespace, ": connection ").concat(sessionId, " already in progress, returning existing promise"));
281
+ return this._connectPromises.get(sessionId);
282
+ }
283
+ var sessionSocket = this.sockets.get(sessionId);
284
+ if (sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connected || sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connecting) {
285
+ this.logger.info("".concat(this.namespace, ": connection ").concat(sessionId, " already connected, will not connect again"));
286
+ return _promise.default.resolve();
287
+ }
288
+ this.connecting = true;
289
+ this.logger.info("".concat(this.namespace, ": starting connection attempt for ").concat(sessionId));
290
+ this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
291
+ var connectPromise = _promise.default.resolve(this.webex.internal.device.registered || this.webex.internal.device.register()).then(function () {
292
+ _this4.logger.info("".concat(_this4.namespace, ": connecting ").concat(sessionId));
293
+ return _this4._connectWithBackoff(webSocketUrl, sessionId);
294
+ }).finally(function () {
295
+ _this4._connectPromises.delete(sessionId);
296
+ });
297
+ this._connectPromises.set(sessionId, connectPromise);
298
+ return connectPromise;
299
+ },
300
+ logout: function logout() {
301
+ this.logger.info("".concat(this.namespace, ": logout() called"));
302
+ this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
303
+ return this.disconnectAll(this.config.beforeLogoutOptionsCloseReason && !normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason) ? {
304
+ code: 3050,
305
+ reason: this.config.beforeLogoutOptionsCloseReason
306
+ } : undefined);
307
+ },
308
+ /**
309
+ * Disconnect a Mercury socket for a specific session.
310
+ * @param {object} [options] - Optional websocket close options (for example: `{code, reason}`).
311
+ * @param {string} [sessionId=this.defaultSessionId] - The session identifier to disconnect.
312
+ * @returns {Promise<void>} Resolves after disconnect cleanup and close handling are initiated/completed.
313
+ */
314
+ disconnect: function disconnect(options) {
315
+ var _this5 = this;
316
+ var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
317
+ this.logger.info("".concat(this.namespace, "#disconnect: connecting state: ").concat(this.connecting, ", connected state: ").concat(this.connected, ", socket exists: ").concat(!!this.socket, ", options: ").concat((0, _stringify.default)(options)));
318
+ return new _promise.default(function (resolve) {
319
+ var backoffCall = _this5.backoffCalls.get(sessionId);
320
+ if (backoffCall) {
321
+ _this5.logger.info("".concat(_this5.namespace, ": aborting connection ").concat(sessionId));
322
+ backoffCall.abort();
323
+ _this5.backoffCalls.delete(sessionId);
324
+ }
325
+ var shutdownSwitchoverBackoffCall = _this5._shutdownSwitchoverBackoffCalls.get(sessionId);
326
+ if (shutdownSwitchoverBackoffCall) {
327
+ _this5.logger.info("".concat(_this5.namespace, ": aborting shutdown switchover connection ").concat(sessionId));
328
+ shutdownSwitchoverBackoffCall.abort();
329
+ _this5._shutdownSwitchoverBackoffCalls.delete(sessionId);
330
+ }
331
+ // Clean up any pending connection promises
332
+ if (_this5._connectPromises) {
333
+ _this5._connectPromises.delete(sessionId);
334
+ }
335
+ var sessionSocket = _this5.sockets.get(sessionId);
336
+ var suffix = sessionId === _this5.defaultSessionId ? '' : ":".concat(sessionId);
337
+ if (sessionSocket) {
338
+ sessionSocket.removeAllListeners('message');
339
+ sessionSocket.connecting = false;
340
+ sessionSocket.connected = false;
341
+ _this5.once(sessionId === _this5.defaultSessionId ? 'offline' : "offline".concat(suffix), resolve);
342
+ resolve(sessionSocket.close(options || undefined));
343
+ }
344
+ resolve();
345
+
346
+ // Update overall connected status
347
+ _this5.connected = _this5.hasConnectedSockets();
348
+ });
349
+ },
350
+ /**
351
+ * Disconnect all socket connections
352
+ * @param {object} options - Close options
353
+ * @returns {Promise} Promise that resolves when all connections are closed
354
+ */
355
+ disconnectAll: function disconnectAll(options) {
356
+ var _this6 = this;
357
+ var disconnectPromises = [];
358
+ var _iterator = _createForOfIteratorHelper(this.sockets.keys()),
359
+ _step;
360
+ try {
361
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
362
+ var sessionId = _step.value;
363
+ disconnectPromises.push(this.disconnect(options, sessionId));
364
+ }
365
+ } catch (err) {
366
+ _iterator.e(err);
367
+ } finally {
368
+ _iterator.f();
369
+ }
370
+ return _promise.default.all(disconnectPromises).then(function () {
371
+ _this6.connected = false;
372
+ _this6.sockets.clear();
373
+ _this6.backoffCalls.clear();
374
+ // Clear connection promises to prevent stale promises
375
+ if (_this6._connectPromises) {
376
+ _this6._connectPromises.clear();
377
+ }
378
+ });
379
+ },
380
+ listen: function listen() {
381
+ /* eslint no-invalid-this: [0] */
382
+ return this.connect();
383
+ },
384
+ stopListening: function stopListening() {
385
+ /* eslint no-invalid-this: [0] */
386
+ return this.disconnect();
387
+ },
388
+ processRegistrationStatusEvent: function processRegistrationStatusEvent(message) {
389
+ this.localClusterServiceUrls = message.localClusterServiceUrls;
390
+ },
391
+ _applyOverrides: function _applyOverrides(event) {
392
+ if (!event || !event.headers) {
393
+ return;
394
+ }
395
+ var headerKeys = (0, _keys.default)(event.headers);
396
+ headerKeys.forEach(function (keyPath) {
397
+ (0, _lodash.set)(event, keyPath, event.headers[keyPath]);
398
+ });
399
+ },
400
+ _prepareUrl: function _prepareUrl(webSocketUrl) {
401
+ var _this7 = this;
402
+ if (!webSocketUrl) {
403
+ webSocketUrl = this.webex.internal.device.webSocketUrl;
404
+ }
405
+ return this.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
406
+ if (haMessagingEnabled) {
407
+ var highPrioritySocketUrl;
408
+ try {
409
+ highPrioritySocketUrl = _this7.webex.internal.services.convertUrlToPriorityHostUrl(webSocketUrl);
410
+ } catch (e) {
411
+ _this7.logger.warn("".concat(_this7.namespace, ": error converting to high priority url"), e);
412
+ }
413
+ if (!highPrioritySocketUrl) {
414
+ var _url$parse;
415
+ var hostFromUrl = (_url$parse = _url.default.parse(webSocketUrl, true)) === null || _url$parse === void 0 ? void 0 : _url$parse.host;
416
+ var isValidHost = _this7.webex.internal.services.isValidHost(hostFromUrl);
417
+ if (!isValidHost) {
418
+ _this7.logger.error("".concat(_this7.namespace, ": host ").concat(hostFromUrl, " is not a valid host from host catalog"));
419
+ return '';
420
+ }
421
+ }
422
+ return highPrioritySocketUrl || webSocketUrl;
423
+ }
424
+ return webSocketUrl;
425
+ }).then(function (wsUrl) {
426
+ webSocketUrl = wsUrl;
427
+ }).then(function () {
428
+ return _this7.webex.internal.feature.getFeature('developer', 'web-shared-mercury');
429
+ }).then(function (webSharedMercury) {
430
+ if (!webSocketUrl) {
431
+ return '';
432
+ }
433
+ webSocketUrl = _url.default.parse(webSocketUrl, true);
434
+ (0, _assign.default)(webSocketUrl.query, {
435
+ outboundWireFormat: 'text',
436
+ bufferStates: true,
437
+ aliasHttpStatus: true
438
+ });
439
+ if (webSharedMercury) {
440
+ (0, _assign.default)(webSocketUrl.query, {
441
+ mercuryRegistrationStatus: true,
442
+ isRegistrationRefreshEnabled: true
443
+ });
444
+ (0, _deleteProperty.default)(webSocketUrl.query, 'bufferStates');
445
+ }
446
+ if ((0, _lodash.get)(_this7, 'webex.config.device.ephemeral', false)) {
447
+ webSocketUrl.query.multipleConnections = true;
448
+ }
449
+ webSocketUrl.query.clientTimestamp = (0, _now.default)();
450
+ delete webSocketUrl.search;
451
+ return _url.default.format(webSocketUrl);
452
+ });
453
+ },
454
+ _attemptConnection: function _attemptConnection(socketUrl, sessionId, callback) {
455
+ var _this8 = this;
456
+ var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
457
+ var _options$isShutdownSw = options.isShutdownSwitchover,
458
+ isShutdownSwitchover = _options$isShutdownSw === void 0 ? false : _options$isShutdownSw,
459
+ _options$onSuccess = options.onSuccess,
460
+ onSuccess = _options$onSuccess === void 0 ? null : _options$onSuccess;
461
+ var socket = new _socket.default();
462
+ socket.connecting = true;
463
+ var newWSUrl;
464
+ this._attachSocketEventListeners(socket, sessionId);
465
+ var backoffCall = isShutdownSwitchover ? this._shutdownSwitchoverBackoffCalls.get(sessionId) : this.backoffCalls.get(sessionId);
466
+
467
+ // Check appropriate backoff call based on connection type
468
+ if (!backoffCall) {
469
+ var mode = isShutdownSwitchover ? 'switchover backoff call' : 'backoffCall';
470
+ var msg = "".concat(this.namespace, ": prevent socket open when ").concat(mode, " no longer defined for ").concat(sessionId);
471
+ var err = new Error(msg);
472
+ this.logger.info(msg);
473
+
474
+ // Call the callback with the error before rejecting
475
+ callback(err);
476
+ return _promise.default.reject(err);
477
+ }
478
+
479
+ // For shutdown switchover, don't set socket yet (make-before-break)
480
+ // For normal connection, set socket before opening to allow disconnect() to close it
481
+ if (!isShutdownSwitchover) {
482
+ this.sockets.set(sessionId, socket);
483
+ }
484
+ return this._prepareAndOpenSocket(socket, socketUrl, sessionId, isShutdownSwitchover).then(function (webSocketUrl) {
485
+ newWSUrl = webSocketUrl;
486
+ _this8.logger.info("".concat(_this8.namespace, ": ").concat(isShutdownSwitchover ? '[shutdown] switchover' : '', " connected to mercury, success, action: connected for ").concat(sessionId, ", url: ").concat(newWSUrl));
487
+
488
+ // Custom success handler for shutdown switchover
489
+ if (onSuccess) {
490
+ onSuccess(socket, webSocketUrl);
491
+ callback();
492
+ return _promise.default.resolve();
493
+ }
494
+
495
+ // Default behavior for normal connection
496
+ callback();
497
+ return _this8.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
498
+ if (haMessagingEnabled) {
499
+ return _this8.webex.internal.device.refresh();
500
+ }
501
+ return _promise.default.resolve();
502
+ });
503
+ }).catch(function (reason) {
504
+ // For shutdown, simpler error handling - just callback for retry
505
+ if (isShutdownSwitchover) {
506
+ _this8.logger.info("".concat(_this8.namespace, ": [shutdown] switchover attempt failed for ").concat(sessionId), reason);
507
+ return callback(reason);
508
+ }
509
+
510
+ // Normal connection error handling (existing complex logic)
511
+ _this8.lastError = reason; // remember the last error
512
+
513
+ var backoffCallNormal = _this8.backoffCalls.get(sessionId);
514
+ // Suppress connection errors that appear to be network related. This
515
+ // may end up suppressing metrics during outages, but we might not care
516
+ // (especially since many of our outages happen in a way that client
517
+ // metrics can't be trusted).
518
+ if (reason.code !== 1006 && backoffCallNormal && (backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()) > 0) {
519
+ _this8._emit(sessionId, 'connection_failed', reason, {
520
+ sessionId: sessionId,
521
+ retries: backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()
522
+ });
523
+ }
524
+ _this8.logger.info("".concat(_this8.namespace, ": connection attempt failed for ").concat(sessionId), reason, (backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()) === 0 ? reason.stack : '');
525
+ // UnknownResponse is produced by IE for any 4XXX; treated it like a bad
526
+ // web socket url and let WDM handle the token checking
527
+ if (reason instanceof _errors.UnknownResponse) {
528
+ _this8.logger.info("".concat(_this8.namespace, ": received unknown response code for ").concat(sessionId, ", refreshing device registration"));
529
+ return _this8.webex.internal.device.refresh().then(function () {
530
+ return callback(reason);
531
+ });
532
+ }
533
+ // NotAuthorized implies expired token
534
+ if (reason instanceof _errors.NotAuthorized) {
535
+ _this8.logger.info("".concat(_this8.namespace, ": received authorization error for ").concat(sessionId, ", reauthorizing"));
536
+ return _this8.webex.credentials.refresh({
537
+ force: true
538
+ }).then(function () {
539
+ return callback(reason);
540
+ });
541
+ }
542
+ // // NotFound implies expired web socket url
543
+ // else if (reason instanceof NotFound) {
544
+ // this.logger.info(`mercury: received not found error, refreshing device registration`);
545
+ // return this.webex.internal.device.refresh()
546
+ // .then(() => callback(reason));
547
+ // }
548
+ // BadRequest implies current credentials are for a Service Account
549
+ // Forbidden implies current user is not entitle for Webex
550
+ if (reason instanceof _errors.BadRequest || reason instanceof _errors.Forbidden) {
551
+ _this8.logger.warn("".concat(_this8.namespace, ": received unrecoverable response from mercury for ").concat(sessionId));
552
+ backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.abort();
553
+ return callback(reason);
554
+ }
555
+ if (reason instanceof _errors.ConnectionError) {
556
+ return _this8.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
557
+ if (haMessagingEnabled) {
558
+ _this8.logger.info("".concat(_this8.namespace, ": received a generic connection error for ").concat(sessionId, ", will try to connect to another datacenter. failed, action: 'failed', url: ").concat(newWSUrl, " error: ").concat(reason.message));
559
+ return _this8.webex.internal.services.markFailedUrl(newWSUrl);
560
+ }
561
+ return null;
562
+ }).then(function () {
563
+ return callback(reason);
564
+ });
565
+ }
566
+ return callback(reason);
567
+ }).catch(function (reason) {
568
+ _this8.logger.error("".concat(_this8.namespace, ": failed to handle connection failure for ").concat(sessionId), reason);
569
+ callback(reason);
570
+ });
571
+ },
572
+ _prepareAndOpenSocket: function _prepareAndOpenSocket(socket, socketUrl, sessionId) {
573
+ var _this9 = this;
574
+ var isShutdownSwitchover = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
575
+ var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
576
+ return _promise.default.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(function (_ref) {
577
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
578
+ webSocketUrl = _ref2[0],
579
+ token = _ref2[1];
580
+ var options = {
581
+ forceCloseDelay: _this9.config.forceCloseDelay,
582
+ pingInterval: _this9.config.pingInterval,
583
+ pongTimeout: _this9.config.pongTimeout,
584
+ token: token.toString(),
585
+ trackingId: "".concat(_this9.webex.sessionId, "_").concat((0, _now.default)()),
586
+ logger: _this9.logger
587
+ };
588
+ if (_this9.webex.config.defaultMercuryOptions) {
589
+ var customOptionsMsg = isShutdownSwitchover ? 'setting custom options for switchover' : 'setting custom options';
590
+ _this9.logger.info("".concat(_this9.namespace, ": ").concat(customOptionsMsg));
591
+ options = _objectSpread(_objectSpread({}, options), _this9.webex.config.defaultMercuryOptions);
592
+ }
593
+
594
+ // Set the socket before opening it. This allows a disconnect() to close
595
+ // the socket if it is in the process of being opened.
596
+ _this9.sockets.set(sessionId, socket);
597
+ _this9.socket = _this9.sockets.get(_this9.defaultSessionId);
598
+ _this9.logger.info("".concat(_this9.namespace, " ").concat(logPrefix, " url for ").concat(sessionId, ": ").concat(webSocketUrl));
599
+ return socket.open(webSocketUrl, options).then(function () {
600
+ return webSocketUrl;
601
+ });
602
+ });
603
+ },
604
+ _connectWithBackoff: function _connectWithBackoff(webSocketUrl, sessionId) {
605
+ var _this0 = this;
606
+ var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
607
+ var _context$isShutdownSw = context.isShutdownSwitchover,
608
+ isShutdownSwitchover = _context$isShutdownSw === void 0 ? false : _context$isShutdownSw,
609
+ _context$attemptOptio = context.attemptOptions,
610
+ attemptOptions = _context$attemptOptio === void 0 ? {} : _context$attemptOptio;
611
+ return new _promise.default(function (resolve, reject) {
612
+ // eslint gets confused about whether call is actually used
613
+ // eslint-disable-next-line prefer-const
614
+ var call;
615
+ var onComplete = function onComplete(err) {
616
+ var sid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : sessionId;
617
+ if (isShutdownSwitchover) {
618
+ _this0._shutdownSwitchoverBackoffCalls.delete(sid);
619
+ } else {
620
+ _this0.backoffCalls.delete(sid);
621
+ }
622
+ var sessionSocket = _this0.sockets.get(sid);
623
+ if (err) {
624
+ var msg = isShutdownSwitchover ? "[shutdown] switchover failed after ".concat(call.getNumRetries(), " retries") : "failed to connect after ".concat(call.getNumRetries(), " retries");
625
+ _this0.logger.info("".concat(_this0.namespace, ": ").concat(msg, "; log statement about next retry was inaccurate; ").concat(err));
626
+ if (sessionSocket) {
627
+ sessionSocket.connecting = false;
628
+ sessionSocket.connected = false;
629
+ }
630
+ return reject(err);
631
+ }
632
+
633
+ // Update overall connected status
634
+ if (sessionSocket) {
635
+ sessionSocket.connecting = false;
636
+ sessionSocket.connected = true;
637
+ }
638
+ // Default success handling for normal connections
639
+ if (!isShutdownSwitchover) {
640
+ _this0.connecting = _this0.hasConnectingSockets();
641
+ _this0.connected = _this0.hasConnectedSockets();
642
+ _this0.hasEverConnected = true;
643
+ _this0._emit(sid, 'online');
644
+ if (_this0.connected) {
645
+ _this0.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
646
+ }
647
+ }
648
+ return resolve();
649
+ };
650
+ // eslint-disable-next-line prefer-reflect
651
+ call = _backoff.default.call(function (callback) {
652
+ var attemptNum = call.getNumRetries();
653
+ var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
654
+ _this0.logger.info("".concat(_this0.namespace, ": executing ").concat(logPrefix, " attempt ").concat(attemptNum, " for ").concat(sessionId));
655
+ _this0._attemptConnection(webSocketUrl, sessionId, callback, attemptOptions);
656
+ }, function (err) {
657
+ return onComplete(err, sessionId);
658
+ });
659
+ call.setStrategy(new _backoff.default.ExponentialStrategy({
660
+ initialDelay: _this0.config.backoffTimeReset,
661
+ maxDelay: _this0.config.backoffTimeMax
662
+ }));
663
+ if (_this0.config.initialConnectionMaxRetries && !_this0.hasEverConnected && !isShutdownSwitchover) {
664
+ call.failAfter(_this0.config.initialConnectionMaxRetries);
665
+ } else if (_this0.config.maxRetries) {
666
+ call.failAfter(_this0.config.maxRetries);
667
+ }
668
+
669
+ // Store the call BEFORE setting up event handlers to prevent race conditions
670
+ // Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
671
+ if (isShutdownSwitchover) {
672
+ _this0._shutdownSwitchoverBackoffCalls.set(sessionId, call);
673
+ } else {
674
+ _this0.backoffCalls.set(sessionId, call);
675
+ }
676
+ call.on('abort', function () {
677
+ var msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
678
+ _this0.logger.info("".concat(_this0.namespace, ": ").concat(msg, " aborted for ").concat(sessionId));
679
+ reject(new Error("Mercury ".concat(msg, " Aborted for ").concat(sessionId)));
680
+ });
681
+ call.on('callback', function (err) {
682
+ if (err) {
683
+ var number = call.getNumRetries();
684
+ var delay = Math.min(call.strategy_.nextBackoffDelay_, _this0.config.backoffTimeMax);
685
+ var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
686
+ _this0.logger.info("".concat(_this0.namespace, ": ").concat(logPrefix, " failed to connect; attempting retry ").concat(number + 1, " in ").concat(delay, " ms for ").concat(sessionId));
687
+ /* istanbul ignore if */
688
+ if (process.env.NODE_ENV === 'development') {
689
+ _this0.logger.debug("".concat(_this0.namespace, ": "), err, err.stack);
690
+ }
691
+ return;
692
+ }
693
+ _this0.logger.info("".concat(_this0.namespace, ": connected ").concat(sessionId));
694
+ });
695
+ call.start();
696
+ });
697
+ },
698
+ _emit: function _emit() {
699
+ for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
700
+ args[_key5] = arguments[_key5];
701
+ }
702
+ try {
703
+ if (!args || args.length === 0) {
704
+ return;
705
+ }
706
+
707
+ // New signature: _emit(sessionId, eventName, ...rest)
708
+ // Backwards compatibility: if the first arg isn't a known sessionId (or defaultSessionId),
709
+ // treat the call as the old signature and forward directly to trigger(...)
710
+ var first = args[0],
711
+ second = args[1],
712
+ rest = _arrayLikeToArray(args).slice(2);
713
+ if (typeof first === 'string' && typeof second === 'string') {
714
+ var sessionId = first;
715
+ var eventName = second;
716
+ var suffix = sessionId === this.defaultSessionId ? '' : ":".concat(sessionId);
717
+ this.trigger.apply(this, ["".concat(eventName).concat(suffix)].concat((0, _toConsumableArray2.default)(rest)));
718
+ } else {
719
+ // Old usage: _emit(eventName, ...args)
720
+ this.trigger.apply(this, args);
721
+ }
722
+ } catch (error) {
723
+ // Safely handle errors without causing additional issues during cleanup
724
+ try {
725
+ this.logger.error("".concat(this.namespace, ": error occurred in event handler:"), error, ' with args: ', args);
726
+ } catch (logError) {
727
+ // If even logging fails, just ignore to prevent cascading errors during cleanup
728
+ // eslint-disable-next-line no-console
729
+ console.error('Mercury _emit error handling failed:', logError);
730
+ }
731
+ }
732
+ },
733
+ _getEventHandlers: function _getEventHandlers(eventType) {
734
+ if (!eventType) {
735
+ return [];
736
+ }
737
+ var _eventType$split = eventType.split('.'),
738
+ _eventType$split2 = (0, _slicedToArray2.default)(_eventType$split, 2),
739
+ namespace = _eventType$split2[0],
740
+ name = _eventType$split2[1];
741
+ var handlers = [];
742
+ if (!this.webex[namespace] && !this.webex.internal[namespace]) {
743
+ return handlers;
744
+ }
745
+ var handlerName = (0, _lodash.camelCase)("process_".concat(name, "_event"));
746
+ if ((this.webex[namespace] || this.webex.internal[namespace])[handlerName]) {
747
+ handlers.push({
748
+ name: handlerName,
749
+ namespace: namespace
750
+ });
751
+ }
752
+ return handlers;
753
+ },
754
+ _onclose: function _onclose(sessionId, event, sourceSocket) {
755
+ // I don't see any way to avoid the complexity or statement count in here.
756
+ /* eslint complexity: [0] */
757
+
758
+ try {
759
+ var reason = event.reason && event.reason.toLowerCase();
760
+ var sessionSocket = this.sockets.get(sessionId);
761
+ var socketUrl;
762
+ event.sessionId = sessionId;
763
+ var isActiveSocket = sourceSocket === sessionSocket;
764
+ if (sourceSocket) {
765
+ socketUrl = sourceSocket.url;
766
+ }
767
+ this.sockets.delete(sessionId);
768
+ if (isActiveSocket) {
769
+ // Only tear down state if the currently active socket closed
770
+ if (sessionSocket) {
771
+ sessionSocket.removeAllListeners();
772
+ if (sessionId === this.defaultSessionId) this.unset('socket');
773
+ this._emit(sessionId, 'offline', event);
774
+ }
775
+ // Update overall connected status
776
+ this.connecting = this.hasConnectingSockets();
777
+ this.connected = this.hasConnectedSockets();
778
+ if (!this.connected) {
779
+ this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
780
+ }
781
+ } else {
782
+ // Old socket closed; do not flip connection state
783
+ this.logger.info("".concat(this.namespace, ": [shutdown] non-active socket closed, code=").concat(event.code, " for ").concat(sessionId));
784
+ // Clean up listeners from old socket now that it's closed
785
+ if (sourceSocket) {
786
+ sourceSocket.removeAllListeners();
787
+ }
788
+ }
789
+ switch (event.code) {
790
+ case 1003:
791
+ // metric: disconnect
792
+ this.logger.info("".concat(this.namespace, ": Mercury service rejected last message for ").concat(sessionId, "; will not reconnect: ").concat(event.reason));
793
+ if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
794
+ break;
795
+ case 4000:
796
+ // metric: disconnect
797
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " replaced; will not reconnect"));
798
+ if (isActiveSocket) this._emit(sessionId, 'offline.replaced', event);
799
+ // If not active, nothing to do
800
+ break;
801
+ case 4001:
802
+ // replaced during shutdown
803
+ if (isActiveSocket) {
804
+ // Server closed active socket with 4001, meaning it expected this connection
805
+ // to be replaced, but the switchover in _handleImminentShutdown failed.
806
+ // This is a permanent failure - do not reconnect.
807
+ this.logger.warn("".concat(this.namespace, ": active socket closed with 4001; shutdown switchover failed for ").concat(sessionId));
808
+ this._emit(sessionId, 'offline.permanent', event);
809
+ } else {
810
+ // Expected: old socket closed after successful switchover
811
+ this.logger.info("".concat(this.namespace, ": old socket closed with 4001 (replaced during shutdown); no reconnect needed for ").concat(sessionId));
812
+ this._emit(sessionId, 'offline.replaced', event);
813
+ }
814
+ break;
815
+ case 1001:
816
+ case 1005:
817
+ case 1006:
818
+ case 1011:
819
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; reconnecting"));
820
+ if (isActiveSocket) {
821
+ this._emit(sessionId, 'offline.transient', event);
822
+ this.logger.info("".concat(this.namespace, ": [shutdown] reconnecting active socket to recover for ").concat(sessionId));
823
+ this._reconnect(socketUrl, sessionId);
824
+ }
825
+ // metric: disconnect
826
+ // if (code == 1011 && reason !== ping error) metric: unexpected disconnect
827
+ break;
828
+ case 1000:
829
+ case 3050:
830
+ // 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
831
+ if (normalReconnectReasons.includes(reason)) {
832
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; reconnecting"));
833
+ if (isActiveSocket) {
834
+ this._emit(sessionId, 'offline.transient', event);
835
+ this.logger.info("".concat(this.namespace, ": [shutdown] reconnecting due to normal close for ").concat(sessionId));
836
+ this._reconnect(socketUrl, sessionId);
837
+ }
838
+ // metric: disconnect
839
+ // if (reason === done forced) metric: force closure
840
+ } else {
841
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; will not reconnect: ").concat(event.reason));
842
+ if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
843
+ }
844
+ break;
845
+ default:
846
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected unexpectedly; will not reconnect"));
847
+ // unexpected disconnect
848
+ if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
849
+ }
850
+ } catch (error) {
851
+ this.logger.error("".concat(this.namespace, ": error occurred in close handler for ").concat(sessionId), error);
852
+ }
853
+ },
854
+ _onmessage: function _onmessage(sessionId, event) {
855
+ var _this1 = this;
856
+ this._setTimeOffset(sessionId, event);
857
+ var envelope = event.data;
858
+ if (process.env.ENABLE_MERCURY_LOGGING) {
859
+ this.logger.debug("".concat(this.namespace, ": message envelope from ").concat(sessionId, ": "), envelope);
860
+ }
861
+ envelope.sessionId = sessionId;
862
+
863
+ // Handle shutdown message shape: { type: 'shutdown' }
864
+ if (envelope && envelope.type === 'shutdown') {
865
+ this.logger.info("".concat(this.namespace, ": [shutdown] imminent shutdown message received for ").concat(sessionId));
866
+ this._emit(sessionId, 'event:mercury_shutdown_imminent', envelope);
867
+ this._handleImminentShutdown(sessionId);
868
+ return _promise.default.resolve();
869
+ }
870
+ envelope.sessionId = sessionId;
871
+ var data = envelope.data;
872
+ this._applyOverrides(data);
873
+ if (!data || !data.eventType) {
874
+ this._emit(sessionId, 'event', envelope);
875
+ return _promise.default.resolve();
876
+ }
877
+ return this._getEventHandlers(data.eventType).reduce(function (promise, handler) {
878
+ return promise.then(function () {
879
+ var namespace = handler.namespace,
880
+ name = handler.name;
881
+ return new _promise.default(function (resolve) {
882
+ return resolve((_this1.webex[namespace] || _this1.webex.internal[namespace])[name](data));
883
+ }).catch(function (reason) {
884
+ return _this1.logger.error("".concat(_this1.namespace, ": error occurred in autowired event handler for ").concat(data.eventType, " from ").concat(sessionId), reason);
885
+ });
886
+ });
887
+ }, _promise.default.resolve()).then(function () {
888
+ _this1._emit(sessionId, 'event', envelope);
889
+ var _data$eventType$split = data.eventType.split('.'),
890
+ _data$eventType$split2 = (0, _slicedToArray2.default)(_data$eventType$split, 1),
891
+ namespace = _data$eventType$split2[0];
892
+ if (namespace === data.eventType) {
893
+ _this1._emit(sessionId, "event:".concat(namespace), envelope);
894
+ } else {
895
+ _this1._emit(sessionId, "event:".concat(namespace), envelope);
896
+ _this1._emit(sessionId, "event:".concat(data.eventType), envelope);
897
+ }
898
+ }).catch(function (reason) {
899
+ _this1.logger.error("".concat(_this1.namespace, ": error occurred processing socket message from ").concat(sessionId), reason);
900
+ });
901
+ },
902
+ _setTimeOffset: function _setTimeOffset(sessionId, event) {
903
+ var wsWriteTimestamp = event.data.wsWriteTimestamp;
904
+ if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) {
905
+ this.mercuryTimeOffset = (0, _now.default)() - wsWriteTimestamp;
906
+ }
907
+ },
908
+ _reconnect: function _reconnect(webSocketUrl) {
909
+ var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
910
+ this.logger.info("".concat(this.namespace, ": reconnecting ").concat(sessionId));
911
+ return this.connect(webSocketUrl, sessionId);
912
+ },
913
+ version: "0.0.0-next.1"
914
+ }, (0, _applyDecoratedDescriptor2.default)(_obj, "listen", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "listen"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "stopListening", [_dec2], (0, _getOwnPropertyDescriptor.default)(_obj, "stopListening"), _obj), _obj));
915
+ var _default2 = exports.default = Mercury;
916
+ //# sourceMappingURL=mercury.js.map