@webex/internal-plugin-mercury 3.8.1 → 3.9.0-multiple-llm.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.
package/dist/mercury.js CHANGED
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
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");
3
7
  var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
4
8
  var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
5
9
  var _Object$getOwnPropertyDescriptor2 = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
@@ -11,6 +15,7 @@ _Object$defineProperty(exports, "__esModule", {
11
15
  value: true
12
16
  });
13
17
  exports.default = void 0;
18
+ var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
14
19
  var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
15
20
  var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
16
21
  var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
@@ -34,10 +39,14 @@ var _dec, _dec2, _obj;
34
39
  */
35
40
  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; }
36
41
  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; }
42
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof _Symbol !== "undefined" && o[_Symbol$iterator] || o["@@iterator"]; if (!it) { if (_Array$isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, 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 normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
43
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
44
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
37
45
  var normalReconnectReasons = ['idle', 'done (forced)', 'pong not received', 'pong mismatch'];
38
46
  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 = {
39
47
  namespace: 'Mercury',
40
48
  lastError: undefined,
49
+ defaultSessionId: 'mercury-default-session',
41
50
  session: {
42
51
  connected: {
43
52
  default: false,
@@ -51,7 +60,18 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
51
60
  default: false,
52
61
  type: 'boolean'
53
62
  },
54
- socket: 'object',
63
+ sockets: {
64
+ default: function _default() {
65
+ return new _map.default();
66
+ },
67
+ type: 'object'
68
+ },
69
+ backoffCalls: {
70
+ default: function _default() {
71
+ return new _map.default();
72
+ },
73
+ type: 'object'
74
+ },
55
75
  localClusterServiceUrls: 'object',
56
76
  mercuryTimeOffset: {
57
77
  default: undefined,
@@ -87,41 +107,159 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
87
107
  getLastError: function getLastError() {
88
108
  return this.lastError;
89
109
  },
110
+ /**
111
+ * Get all active socket connections
112
+ * @returns {Map} Map of sessionId to socket instances
113
+ */
114
+ getSockets: function getSockets() {
115
+ return this.sockets;
116
+ },
117
+ /**
118
+ * Get a specific socket by connection ID
119
+ * @param {string} sessionId - The connection identifier
120
+ * @returns {Socket|undefined} The socket instance or undefined if not found
121
+ */
122
+ getSocket: function getSocket() {
123
+ var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
124
+ return this.sockets.get(sessionId);
125
+ },
126
+ /**
127
+ * Check if any sockets are connected
128
+ * @returns {boolean} True if at least one socket is connected
129
+ */
130
+ hasConnectedSockets: function hasConnectedSockets() {
131
+ var _iterator = _createForOfIteratorHelper(this.sockets.values()),
132
+ _step;
133
+ try {
134
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
135
+ var socket = _step.value;
136
+ if (socket && socket.connected) {
137
+ return true;
138
+ }
139
+ }
140
+ } catch (err) {
141
+ _iterator.e(err);
142
+ } finally {
143
+ _iterator.f();
144
+ }
145
+ return false;
146
+ },
147
+ /**
148
+ * Check if any sockets are connecting
149
+ * @returns {boolean} True if at least one socket is connected
150
+ */
151
+ hasConnectingSockets: function hasConnectingSockets() {
152
+ var _iterator2 = _createForOfIteratorHelper(this.sockets.values()),
153
+ _step2;
154
+ try {
155
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
156
+ var socket = _step2.value;
157
+ if (socket && socket.connecting) {
158
+ return true;
159
+ }
160
+ }
161
+ } catch (err) {
162
+ _iterator2.e(err);
163
+ } finally {
164
+ _iterator2.f();
165
+ }
166
+ return false;
167
+ },
168
+ // @oneFlight
90
169
  connect: function connect(webSocketUrl) {
91
170
  var _this2 = this;
92
- if (this.connected) {
93
- this.logger.info("".concat(this.namespace, ": already connected, will not connect again"));
171
+ var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
172
+ if (!this._connectPromises) this._connectPromises = new _map.default();
173
+
174
+ // First check if there's already a connection promise for this session
175
+ if (this._connectPromises.has(sessionId)) {
176
+ this.logger.info("".concat(this.namespace, ": connection ").concat(sessionId, " already in progress, returning existing promise"));
177
+ return this._connectPromises.get(sessionId);
178
+ }
179
+ var sessionSocket = this.sockets.get(sessionId);
180
+ if (sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connected || sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connecting) {
181
+ this.logger.info("".concat(this.namespace, ": connection ").concat(sessionId, " already connected, will not connect again"));
94
182
  return _promise.default.resolve();
95
183
  }
96
184
  this.connecting = true;
97
- this.logger.info("".concat(this.namespace, ": starting connection attempt"));
185
+ this.logger.info("".concat(this.namespace, ": starting connection attempt for ").concat(sessionId));
98
186
  this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
99
- return _promise.default.resolve(this.webex.internal.device.registered || this.webex.internal.device.register()).then(function () {
100
- _this2.logger.info("".concat(_this2.namespace, ": connecting"));
101
- return _this2._connectWithBackoff(webSocketUrl);
187
+ var connectPromise = _promise.default.resolve(this.webex.internal.device.registered || this.webex.internal.device.register()).then(function () {
188
+ _this2.logger.info("".concat(_this2.namespace, ": connecting ").concat(sessionId));
189
+ return _this2._connectWithBackoff(webSocketUrl, sessionId);
190
+ }).finally(function () {
191
+ _this2._connectPromises.delete(sessionId);
102
192
  });
193
+ this._connectPromises.set(sessionId, connectPromise);
194
+ return connectPromise;
103
195
  },
104
196
  logout: function logout() {
105
197
  this.logger.info("".concat(this.namespace, ": logout() called"));
106
198
  this.logger.info("".concat(this.namespace, ": debug_mercury_logging stack: "), new Error('debug_mercury_logging').stack);
107
- return this.disconnect(this.config.beforeLogoutOptionsCloseReason && !normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason) ? {
199
+ return this.disconnectAll(this.config.beforeLogoutOptionsCloseReason && !normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason) ? {
108
200
  code: 3050,
109
201
  reason: this.config.beforeLogoutOptionsCloseReason
110
202
  } : undefined);
111
203
  },
204
+ // @oneFlight
112
205
  disconnect: function disconnect(options) {
113
206
  var _this3 = this;
207
+ var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
114
208
  return new _promise.default(function (resolve) {
115
- if (_this3.backoffCall) {
116
- _this3.logger.info("".concat(_this3.namespace, ": aborting connection"));
117
- _this3.backoffCall.abort();
209
+ var backoffCall = _this3.backoffCalls.get(sessionId);
210
+ if (backoffCall) {
211
+ _this3.logger.info("".concat(_this3.namespace, ": aborting connection ").concat(sessionId));
212
+ backoffCall.abort();
213
+ _this3.backoffCalls.delete(sessionId);
118
214
  }
119
- if (_this3.socket) {
120
- _this3.socket.removeAllListeners('message');
121
- _this3.once('offline', resolve);
122
- resolve(_this3.socket.close(options || undefined));
215
+
216
+ // Clean up any pending connection promises
217
+ if (_this3._connectPromises) {
218
+ _this3._connectPromises.delete(sessionId);
219
+ }
220
+ var sessionSocket = _this3.sockets.get(sessionId);
221
+ var suffix = sessionId === _this3.defaultSessionId ? '' : ":".concat(sessionId);
222
+ if (sessionSocket) {
223
+ sessionSocket.removeAllListeners('message');
224
+ sessionSocket.connecting = false;
225
+ sessionSocket.connected = false;
226
+ _this3.once(sessionId === _this3.defaultSessionId ? 'offline' : "offline".concat(suffix), resolve);
227
+ resolve(sessionSocket.close(options || undefined));
123
228
  }
124
229
  resolve();
230
+
231
+ // Update overall connected status
232
+ _this3.connected = _this3.hasConnectedSockets();
233
+ });
234
+ },
235
+ /**
236
+ * Disconnect all socket connections
237
+ * @param {object} options - Close options
238
+ * @returns {Promise} Promise that resolves when all connections are closed
239
+ */
240
+ disconnectAll: function disconnectAll(options) {
241
+ var _this4 = this;
242
+ var disconnectPromises = [];
243
+ var _iterator3 = _createForOfIteratorHelper(this.sockets.keys()),
244
+ _step3;
245
+ try {
246
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
247
+ var sessionId = _step3.value;
248
+ disconnectPromises.push(this.disconnect(options, sessionId));
249
+ }
250
+ } catch (err) {
251
+ _iterator3.e(err);
252
+ } finally {
253
+ _iterator3.f();
254
+ }
255
+ return _promise.default.all(disconnectPromises).then(function () {
256
+ _this4.connected = false;
257
+ _this4.sockets.clear();
258
+ _this4.backoffCalls.clear();
259
+ // Clear connection promises to prevent stale promises
260
+ if (_this4._connectPromises) {
261
+ _this4._connectPromises.clear();
262
+ }
125
263
  });
126
264
  },
127
265
  listen: function listen() {
@@ -145,19 +283,19 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
145
283
  });
146
284
  },
147
285
  _prepareUrl: function _prepareUrl(webSocketUrl) {
148
- var _this4 = this;
286
+ var _this5 = this;
149
287
  if (!webSocketUrl) {
150
288
  webSocketUrl = this.webex.internal.device.webSocketUrl;
151
289
  }
152
290
  return this.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
153
291
  if (haMessagingEnabled) {
154
- return _this4.webex.internal.services.convertUrlToPriorityHostUrl(webSocketUrl);
292
+ return _this5.webex.internal.services.convertUrlToPriorityHostUrl(webSocketUrl);
155
293
  }
156
294
  return webSocketUrl;
157
295
  }).then(function (wsUrl) {
158
296
  webSocketUrl = wsUrl;
159
297
  }).then(function () {
160
- return _this4.webex.internal.feature.getFeature('developer', 'web-shared-mercury');
298
+ return _this5.webex.internal.feature.getFeature('developer', 'web-shared-mercury');
161
299
  }).then(function (webSharedMercury) {
162
300
  webSocketUrl = _url.default.parse(webSocketUrl, true);
163
301
  (0, _assign.default)(webSocketUrl.query, {
@@ -172,104 +310,117 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
172
310
  });
173
311
  (0, _deleteProperty.default)(webSocketUrl.query, 'bufferStates');
174
312
  }
175
- if ((0, _lodash.get)(_this4, 'webex.config.device.ephemeral', false)) {
313
+ if ((0, _lodash.get)(_this5, 'webex.config.device.ephemeral', false)) {
176
314
  webSocketUrl.query.multipleConnections = true;
177
315
  }
178
316
  webSocketUrl.query.clientTimestamp = (0, _now.default)();
179
317
  return _url.default.format(webSocketUrl);
180
318
  });
181
319
  },
182
- _attemptConnection: function _attemptConnection(socketUrl, callback) {
183
- var _this5 = this;
320
+ _attemptConnection: function _attemptConnection(socketUrl, sessionId, callback) {
321
+ var _this6 = this;
184
322
  var socket = new _socket.default();
323
+ socket.connecting = true;
185
324
  var attemptWSUrl;
325
+ var suffix = sessionId === this.defaultSessionId ? '' : ":".concat(sessionId);
186
326
  socket.on('close', function () {
187
- return _this5._onclose.apply(_this5, arguments);
327
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
328
+ args[_key] = arguments[_key];
329
+ }
330
+ return _this6._onclose.apply(_this6, [sessionId].concat(args));
188
331
  });
189
332
  socket.on('message', function () {
190
- return _this5._onmessage.apply(_this5, arguments);
333
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
334
+ args[_key2] = arguments[_key2];
335
+ }
336
+ return _this6._onmessage.apply(_this6, [sessionId].concat(args));
191
337
  });
192
338
  socket.on('pong', function () {
193
- return _this5._setTimeOffset.apply(_this5, arguments);
339
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
340
+ args[_key3] = arguments[_key3];
341
+ }
342
+ return _this6._setTimeOffset.apply(_this6, [sessionId].concat(args));
194
343
  });
195
344
  socket.on('sequence-mismatch', function () {
196
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
197
- args[_key] = arguments[_key];
345
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
346
+ args[_key4] = arguments[_key4];
198
347
  }
199
- return _this5._emit.apply(_this5, ['sequence-mismatch'].concat(args));
348
+ return _this6._emit.apply(_this6, ["sequence-mismatch".concat(suffix)].concat(args));
200
349
  });
201
350
  socket.on('ping-pong-latency', function () {
202
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
203
- args[_key2] = arguments[_key2];
351
+ for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
352
+ args[_key5] = arguments[_key5];
204
353
  }
205
- return _this5._emit.apply(_this5, ['ping-pong-latency'].concat(args));
354
+ return _this6._emit.apply(_this6, ["ping-pong-latency".concat(suffix)].concat(args));
206
355
  });
207
356
  _promise.default.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(function (_ref) {
208
357
  var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
209
358
  webSocketUrl = _ref2[0],
210
359
  token = _ref2[1];
211
- if (!_this5.backoffCall) {
212
- var msg = "".concat(_this5.namespace, ": prevent socket open when backoffCall no longer defined");
213
- _this5.logger.info(msg);
360
+ var backoffCall = _this6.backoffCalls.get(sessionId);
361
+ if (!backoffCall) {
362
+ var msg = "".concat(_this6.namespace, ": prevent socket open when backoffCall no longer defined for ").concat(sessionId);
363
+ _this6.logger.info(msg);
214
364
  return _promise.default.reject(new Error(msg));
215
365
  }
216
366
  attemptWSUrl = webSocketUrl;
217
367
  var options = {
218
- forceCloseDelay: _this5.config.forceCloseDelay,
219
- pingInterval: _this5.config.pingInterval,
220
- pongTimeout: _this5.config.pongTimeout,
368
+ forceCloseDelay: _this6.config.forceCloseDelay,
369
+ pingInterval: _this6.config.pingInterval,
370
+ pongTimeout: _this6.config.pongTimeout,
221
371
  token: token.toString(),
222
- trackingId: "".concat(_this5.webex.sessionId, "_").concat((0, _now.default)()),
223
- logger: _this5.logger
372
+ trackingId: "".concat(_this6.webex.sessionId, "_").concat(sessionId, "_").concat((0, _now.default)()),
373
+ logger: _this6.logger
224
374
  };
225
375
 
226
376
  // if the consumer has supplied request options use them
227
- if (_this5.webex.config.defaultMercuryOptions) {
228
- _this5.logger.info("".concat(_this5.namespace, ": setting custom options"));
229
- options = _objectSpread(_objectSpread({}, options), _this5.webex.config.defaultMercuryOptions);
377
+ if (_this6.webex.config.defaultMercuryOptions) {
378
+ _this6.logger.info("".concat(_this6.namespace, ": setting custom options for ").concat(sessionId));
379
+ options = _objectSpread(_objectSpread({}, options), _this6.webex.config.defaultMercuryOptions);
230
380
  }
231
381
 
232
382
  // Set the socket before opening it. This allows a disconnect() to close
233
383
  // the socket if it is in the process of being opened.
234
- _this5.socket = socket;
235
- _this5.logger.info("".concat(_this5.namespace, " connection url: ").concat(webSocketUrl));
384
+ _this6.sockets.set(sessionId, socket);
385
+ _this6.socket = _this6.sockets.get(_this6.defaultSessionId) || socket;
386
+ _this6.logger.info("".concat(_this6.namespace, " connection url for ").concat(sessionId, ": ").concat(webSocketUrl));
236
387
  return socket.open(webSocketUrl, options);
237
388
  }).then(function () {
238
- _this5.logger.info("".concat(_this5.namespace, ": connected to mercury, success, action: connected, url: ").concat(attemptWSUrl));
389
+ _this6.logger.info("".concat(_this6.namespace, ": connected to mercury, success, action: connected, sessionId: ").concat(sessionId, ", url: ").concat(attemptWSUrl));
239
390
  callback();
240
- return _this5.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
391
+ return _this6.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
241
392
  if (haMessagingEnabled) {
242
- return _this5.webex.internal.device.refresh();
393
+ return _this6.webex.internal.device.refresh();
243
394
  }
244
395
  return _promise.default.resolve();
245
396
  });
246
397
  }).catch(function (reason) {
247
- var _this5$backoffCall, _this5$backoffCall3;
248
- _this5.lastError = reason; // remember the last error
398
+ _this6.lastError = reason; // remember the last error
249
399
 
400
+ var backoffCall = _this6.backoffCalls.get(sessionId);
250
401
  // Suppress connection errors that appear to be network related. This
251
402
  // may end up suppressing metrics during outages, but we might not care
252
403
  // (especially since many of our outages happen in a way that client
253
404
  // metrics can't be trusted).
254
- if (reason.code !== 1006 && _this5.backoffCall && ((_this5$backoffCall = _this5.backoffCall) === null || _this5$backoffCall === void 0 ? void 0 : _this5$backoffCall.getNumRetries()) > 0) {
255
- var _this5$backoffCall2;
256
- _this5._emit('connection_failed', reason, {
257
- retries: (_this5$backoffCall2 = _this5.backoffCall) === null || _this5$backoffCall2 === void 0 ? void 0 : _this5$backoffCall2.getNumRetries()
405
+ if (reason.code !== 1006 && backoffCall && (backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.getNumRetries()) > 0) {
406
+ _this6._emit("connection_failed".concat(suffix), reason, {
407
+ sessionId: sessionId,
408
+ retries: backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.getNumRetries()
258
409
  });
259
410
  }
260
- _this5.logger.info("".concat(_this5.namespace, ": connection attempt failed"), reason, ((_this5$backoffCall3 = _this5.backoffCall) === null || _this5$backoffCall3 === void 0 ? void 0 : _this5$backoffCall3.getNumRetries()) === 0 ? reason.stack : '');
411
+ _this6.logger.info("".concat(_this6.namespace, ": connection attempt failed for ").concat(sessionId), reason, (backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.getNumRetries()) === 0 ? reason.stack : '');
261
412
  // UnknownResponse is produced by IE for any 4XXX; treated it like a bad
262
413
  // web socket url and let WDM handle the token checking
263
414
  if (reason instanceof _errors.UnknownResponse) {
264
- _this5.logger.info("".concat(_this5.namespace, ": received unknown response code, refreshing device registration"));
265
- return _this5.webex.internal.device.refresh().then(function () {
415
+ _this6.logger.info("".concat(_this6.namespace, ": received unknown response code for ").concat(sessionId, ", refreshing device registration"));
416
+ return _this6.webex.internal.device.refresh().then(function () {
266
417
  return callback(reason);
267
418
  });
268
419
  }
269
420
  // NotAuthorized implies expired token
270
421
  if (reason instanceof _errors.NotAuthorized) {
271
- _this5.logger.info("".concat(_this5.namespace, ": received authorization error, reauthorizing"));
272
- return _this5.webex.credentials.refresh({
422
+ _this6.logger.info("".concat(_this6.namespace, ": received authorization error for ").concat(sessionId, ", reauthorizing"));
423
+ return _this6.webex.credentials.refresh({
273
424
  force: true
274
425
  }).then(function () {
275
426
  return callback(reason);
@@ -284,15 +435,15 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
284
435
  // BadRequest implies current credentials are for a Service Account
285
436
  // Forbidden implies current user is not entitle for Webex
286
437
  if (reason instanceof _errors.BadRequest || reason instanceof _errors.Forbidden) {
287
- _this5.logger.warn("".concat(_this5.namespace, ": received unrecoverable response from mercury"));
288
- _this5.backoffCall.abort();
438
+ _this6.logger.warn("".concat(_this6.namespace, ": received unrecoverable response from mercury for ").concat(sessionId));
439
+ backoffCall === null || backoffCall === void 0 ? void 0 : backoffCall.abort();
289
440
  return callback(reason);
290
441
  }
291
442
  if (reason instanceof _errors.ConnectionError) {
292
- return _this5.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
443
+ return _this6.webex.internal.feature.getFeature('developer', 'web-high-availability').then(function (haMessagingEnabled) {
293
444
  if (haMessagingEnabled) {
294
- _this5.logger.info("".concat(_this5.namespace, ": received a generic connection error, will try to connect to another datacenter. failed, action: 'failed', url: ").concat(attemptWSUrl, " error: ").concat(reason.message));
295
- return _this5.webex.internal.services.markFailedUrl(attemptWSUrl);
445
+ _this6.logger.info("".concat(_this6.namespace, ": received a generic connection error for ").concat(sessionId, ", will try to connect to another datacenter. failed, action: 'failed', url: ").concat(attemptWSUrl, " error: ").concat(reason.message));
446
+ return _this6.webex.internal.services.markFailedUrl(attemptWSUrl);
296
447
  }
297
448
  return null;
298
449
  }).then(function () {
@@ -301,72 +452,96 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
301
452
  }
302
453
  return callback(reason);
303
454
  }).catch(function (reason) {
304
- _this5.logger.error("".concat(_this5.namespace, ": failed to handle connection failure"), reason);
455
+ _this6.logger.error("".concat(_this6.namespace, ": failed to handle connection failure for ").concat(sessionId), reason);
305
456
  callback(reason);
306
457
  });
307
458
  },
308
- _connectWithBackoff: function _connectWithBackoff(webSocketUrl) {
309
- var _this6 = this;
459
+ _connectWithBackoff: function _connectWithBackoff(webSocketUrl, sessionId) {
460
+ var _this7 = this;
310
461
  return new _promise.default(function (resolve, reject) {
311
462
  // eslint gets confused about whether or not call is actually used
312
463
  // eslint-disable-next-line prefer-const
313
464
  var call;
314
465
  var onComplete = function onComplete(err) {
315
- _this6.connecting = false;
316
- _this6.backoffCall = undefined;
466
+ var sid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : sessionId;
467
+ _this7.backoffCalls.delete(sid);
317
468
  if (err) {
318
- _this6.logger.info("".concat(_this6.namespace, ": failed to connect after ").concat(call.getNumRetries(), " retries; log statement about next retry was inaccurate; ").concat(err));
469
+ _this7.logger.info("".concat(_this7.namespace, ": failed to connect ").concat(sid, " after ").concat(call.getNumRetries(), " retries; log statement about next retry was inaccurate; ").concat(err));
319
470
  return reject(err);
320
471
  }
321
- _this6.connected = true;
322
- _this6.hasEverConnected = true;
323
- _this6._emit('online');
472
+ // Update overall connected status
473
+ var sessionSocket = _this7.sockets.get(sid);
474
+ if (sessionSocket) {
475
+ sessionSocket.connecting = false;
476
+ sessionSocket.connected = true;
477
+ }
478
+ // @ts-ignore
479
+ _this7.connecting = _this7.hasConnectingSockets();
480
+ _this7.connected = _this7.hasConnectedSockets();
481
+ _this7.hasEverConnected = true;
482
+ var suffix = sid === _this7.defaultSessionId ? '' : ":".concat(sid);
483
+ _this7._emit("online".concat(suffix), {
484
+ sessionId: sid
485
+ });
486
+ _this7.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
324
487
  return resolve();
325
488
  };
326
-
327
489
  // eslint-disable-next-line prefer-reflect
328
490
  call = _backoff.default.call(function (callback) {
329
- _this6.logger.info("".concat(_this6.namespace, ": executing connection attempt ").concat(call.getNumRetries()));
330
- _this6._attemptConnection(webSocketUrl, callback);
331
- }, onComplete);
491
+ _this7.logger.info("".concat(_this7.namespace, ": executing connection attempt ").concat(call.getNumRetries(), " for ").concat(sessionId));
492
+ _this7._attemptConnection(webSocketUrl, sessionId, callback);
493
+ }, function (err) {
494
+ return onComplete(err, sessionId);
495
+ });
332
496
  call.setStrategy(new _backoff.default.ExponentialStrategy({
333
- initialDelay: _this6.config.backoffTimeReset,
334
- maxDelay: _this6.config.backoffTimeMax
497
+ initialDelay: _this7.config.backoffTimeReset,
498
+ maxDelay: _this7.config.backoffTimeMax
335
499
  }));
336
- if (_this6.config.initialConnectionMaxRetries && !_this6.hasEverConnected) {
337
- call.failAfter(_this6.config.initialConnectionMaxRetries);
338
- } else if (_this6.config.maxRetries) {
339
- call.failAfter(_this6.config.maxRetries);
500
+ if (_this7.config.initialConnectionMaxRetries && !_this7.hasEverConnected) {
501
+ call.failAfter(_this7.config.initialConnectionMaxRetries);
502
+ } else if (_this7.config.maxRetries) {
503
+ call.failAfter(_this7.config.maxRetries);
340
504
  }
505
+
506
+ // Store the call BEFORE setting up event handlers to prevent race conditions
507
+ _this7.backoffCalls.set(sessionId, call);
341
508
  call.on('abort', function () {
342
- _this6.logger.info("".concat(_this6.namespace, ": connection aborted"));
343
- reject(new Error('Mercury Connection Aborted'));
509
+ _this7.logger.info("".concat(_this7.namespace, ": connection aborted for ").concat(sessionId));
510
+ reject(new Error("Mercury Connection Aborted for ".concat(sessionId)));
344
511
  });
345
512
  call.on('callback', function (err) {
346
513
  if (err) {
347
514
  var number = call.getNumRetries();
348
- var delay = Math.min(call.strategy_.nextBackoffDelay_, _this6.config.backoffTimeMax);
349
- _this6.logger.info("".concat(_this6.namespace, ": failed to connect; attempting retry ").concat(number + 1, " in ").concat(delay, " ms"));
515
+ var delay = Math.min(call.strategy_.nextBackoffDelay_, _this7.config.backoffTimeMax);
516
+ _this7.logger.info("".concat(_this7.namespace, ": failed to connect ").concat(sessionId, "; attempting retry ").concat(number + 1, " in ").concat(delay, " ms"));
350
517
  /* istanbul ignore if */
351
518
  if (process.env.NODE_ENV === 'development') {
352
- _this6.logger.debug("".concat(_this6.namespace, ": "), err, err.stack);
519
+ _this7.logger.debug("".concat(_this7.namespace, ": "), err, err.stack);
353
520
  }
354
521
  return;
355
522
  }
356
- _this6.logger.info("".concat(_this6.namespace, ": connected"));
523
+ _this7.logger.info("".concat(_this7.namespace, ": connected ").concat(sessionId));
357
524
  });
358
525
  call.start();
359
- _this6.backoffCall = call;
360
526
  });
361
527
  },
362
528
  _emit: function _emit() {
363
- for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
364
- args[_key3] = arguments[_key3];
529
+ for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
530
+ args[_key6] = arguments[_key6];
365
531
  }
366
532
  try {
367
- this.trigger.apply(this, args);
533
+ // Validate args before processing
534
+ if (args && args.length > 0) {
535
+ this.trigger.apply(this, args);
536
+ }
368
537
  } catch (error) {
369
- this.logger.error("".concat(this.namespace, ": error occurred in event handler:"), error, ' with args: ', args);
538
+ // Safely handle errors without causing additional issues during cleanup
539
+ try {
540
+ this.logger.error("".concat(this.namespace, ": error occurred in event handler:"), error, ' with args: ', args);
541
+ } catch (logError) {
542
+ // If even logging fails, just ignore to prevent cascading errors during cleanup
543
+ this.logger.error('Mercury _emit error handling failed:', logError);
544
+ }
370
545
  }
371
546
  },
372
547
  _getEventHandlers: function _getEventHandlers(eventType) {
@@ -387,35 +562,48 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
387
562
  }
388
563
  return handlers;
389
564
  },
390
- _onclose: function _onclose(event) {
565
+ _onclose: function _onclose(sessionId, event) {
391
566
  // I don't see any way to avoid the complexity or statement count in here.
392
567
  /* eslint complexity: [0] */
393
568
 
394
569
  try {
570
+ var _sessionSocket;
395
571
  var reason = event.reason && event.reason.toLowerCase();
396
- var socketUrl = this.socket.url;
397
- this.socket.removeAllListeners();
398
- this.unset('socket');
399
- this.connected = false;
400
- this._emit('offline', event);
572
+ var sessionSocket = this.sockets.get(sessionId);
573
+ var socketUrl = (_sessionSocket = sessionSocket) === null || _sessionSocket === void 0 ? void 0 : _sessionSocket.url;
574
+ var suffix = sessionId === this.defaultSessionId ? '' : ":".concat(sessionId);
575
+ event.sessionId = sessionId;
576
+ this.sockets.delete(sessionId);
577
+ if (sessionSocket) {
578
+ sessionSocket.removeAllListeners();
579
+ sessionSocket = null;
580
+ this._emit("offline".concat(suffix), event);
581
+ }
582
+
583
+ // Update overall connected status
584
+ this.connecting = this.hasConnectingSockets();
585
+ this.connected = this.hasConnectedSockets();
586
+ if (!this.connected) {
587
+ this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
588
+ }
401
589
  switch (event.code) {
402
590
  case 1003:
403
591
  // metric: disconnect
404
- this.logger.info("".concat(this.namespace, ": Mercury service rejected last message; will not reconnect: ").concat(event.reason));
405
- this._emit('offline.permanent', event);
592
+ this.logger.info("".concat(this.namespace, ": Mercury service rejected last message for ").concat(sessionId, "; will not reconnect: ").concat(event.reason));
593
+ this._emit("offline.permanent".concat(suffix), event);
406
594
  break;
407
595
  case 4000:
408
596
  // metric: disconnect
409
- this.logger.info("".concat(this.namespace, ": socket replaced; will not reconnect"));
410
- this._emit('offline.replaced', event);
597
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " replaced; will not reconnect"));
598
+ this._emit("offline.replaced".concat(suffix), event);
411
599
  break;
412
600
  case 1001:
413
601
  case 1005:
414
602
  case 1006:
415
603
  case 1011:
416
- this.logger.info("".concat(this.namespace, ": socket disconnected; reconnecting"));
417
- this._emit('offline.transient', event);
418
- this._reconnect(socketUrl);
604
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; reconnecting"));
605
+ this._emit("offline.transient".concat(suffix), event);
606
+ this._reconnect(socketUrl, sessionId);
419
607
  // metric: disconnect
420
608
  // if (code == 1011 && reason !== ping error) metric: unexpected disconnect
421
609
  break;
@@ -423,32 +611,33 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
423
611
  case 3050:
424
612
  // 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
425
613
  if (normalReconnectReasons.includes(reason)) {
426
- this.logger.info("".concat(this.namespace, ": socket disconnected; reconnecting"));
427
- this._emit('offline.transient', event);
428
- this._reconnect(socketUrl);
614
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; reconnecting"));
615
+ this._emit("offline.transient".concat(suffix), event);
616
+ this._reconnect(socketUrl, sessionId);
429
617
  // metric: disconnect
430
618
  // if (reason === done forced) metric: force closure
431
619
  } else {
432
- this.logger.info("".concat(this.namespace, ": socket disconnected; will not reconnect: ").concat(event.reason));
433
- this._emit('offline.permanent', event);
620
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected; will not reconnect: ").concat(event.reason));
621
+ this._emit("offline.permanent".concat(suffix), event);
434
622
  }
435
623
  break;
436
624
  default:
437
- this.logger.info("".concat(this.namespace, ": socket disconnected unexpectedly; will not reconnect"));
625
+ this.logger.info("".concat(this.namespace, ": socket ").concat(sessionId, " disconnected unexpectedly; will not reconnect"));
438
626
  // unexpected disconnect
439
- this._emit('offline.permanent', event);
627
+ this._emit("offline.permanent".concat(suffix), event);
440
628
  }
441
629
  } catch (error) {
442
- this.logger.error("".concat(this.namespace, ": error occurred in close handler"), error);
630
+ this.logger.error("".concat(this.namespace, ": error occurred in close handler for ").concat(sessionId), error);
443
631
  }
444
632
  },
445
- _onmessage: function _onmessage(event) {
446
- var _this7 = this;
447
- this._setTimeOffset(event);
633
+ _onmessage: function _onmessage(sessionId, event) {
634
+ var _this8 = this;
635
+ this._setTimeOffset(sessionId, event);
448
636
  var envelope = event.data;
449
637
  if (process.env.ENABLE_MERCURY_LOGGING) {
450
- this.logger.debug("".concat(this.namespace, ": message envelope: "), envelope);
638
+ this.logger.debug("".concat(this.namespace, ": message envelope from ").concat(sessionId, ": "), envelope);
451
639
  }
640
+ envelope.sessionId = sessionId;
452
641
  var data = envelope.data;
453
642
  this._applyOverrides(data);
454
643
  return this._getEventHandlers(data.eventType).reduce(function (promise, handler) {
@@ -456,37 +645,39 @@ var Mercury = _webexCore.WebexPlugin.extend((_dec = (0, _common.deprecated)('Mer
456
645
  var namespace = handler.namespace,
457
646
  name = handler.name;
458
647
  return new _promise.default(function (resolve) {
459
- return resolve((_this7.webex[namespace] || _this7.webex.internal[namespace])[name](data));
648
+ return resolve((_this8.webex[namespace] || _this8.webex.internal[namespace])[name](data));
460
649
  }).catch(function (reason) {
461
- return _this7.logger.error("".concat(_this7.namespace, ": error occurred in autowired event handler for ").concat(data.eventType), reason);
650
+ return _this8.logger.error("".concat(_this8.namespace, ": error occurred in autowired event handler for ").concat(data.eventType, " from ").concat(sessionId), reason);
462
651
  });
463
652
  });
464
653
  }, _promise.default.resolve()).then(function () {
465
- _this7._emit('event', event.data);
654
+ var suffix = sessionId === _this8.defaultSessionId ? '' : ":".concat(sessionId);
655
+ _this8._emit("event".concat(suffix), envelope);
466
656
  var _data$eventType$split = data.eventType.split('.'),
467
657
  _data$eventType$split2 = (0, _slicedToArray2.default)(_data$eventType$split, 1),
468
658
  namespace = _data$eventType$split2[0];
469
659
  if (namespace === data.eventType) {
470
- _this7._emit("event:".concat(namespace), envelope);
660
+ _this8._emit("event:".concat(namespace).concat(suffix), envelope);
471
661
  } else {
472
- _this7._emit("event:".concat(namespace), envelope);
473
- _this7._emit("event:".concat(data.eventType), envelope);
662
+ _this8._emit("event:".concat(namespace).concat(suffix), envelope);
663
+ _this8._emit("event:".concat(data.eventType).concat(suffix), envelope);
474
664
  }
475
665
  }).catch(function (reason) {
476
- _this7.logger.error("".concat(_this7.namespace, ": error occurred processing socket message"), reason);
666
+ _this8.logger.error("".concat(_this8.namespace, ": error occurred processing socket message from ").concat(sessionId), reason);
477
667
  });
478
668
  },
479
- _setTimeOffset: function _setTimeOffset(event) {
669
+ _setTimeOffset: function _setTimeOffset(sessionId, event) {
480
670
  var wsWriteTimestamp = event.data.wsWriteTimestamp;
481
671
  if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) {
482
672
  this.mercuryTimeOffset = (0, _now.default)() - wsWriteTimestamp;
483
673
  }
484
674
  },
485
675
  _reconnect: function _reconnect(webSocketUrl) {
486
- this.logger.info("".concat(this.namespace, ": reconnecting"));
487
- return this.connect(webSocketUrl);
676
+ var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
677
+ this.logger.info("".concat(this.namespace, ": reconnecting ").concat(sessionId));
678
+ return this.connect(webSocketUrl, sessionId);
488
679
  },
489
- version: "3.8.1"
490
- }, ((0, _applyDecoratedDescriptor2.default)(_obj, "connect", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "connect"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "disconnect", [_common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "disconnect"), _obj), (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)));
491
- var _default = exports.default = Mercury;
680
+ version: "3.9.0-multiple-llm.1"
681
+ }, ((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)));
682
+ var _default2 = exports.default = Mercury;
492
683
  //# sourceMappingURL=mercury.js.map