@webex/calling 3.12.0-mobius-socket.18 → 3.12.0-mobius-socket.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/CallingClient/utils/request.js +6 -3
  2. package/dist/CallingClient/utils/request.js.map +1 -1
  3. package/dist/CallingClient/utils/request.test.js +2 -2
  4. package/dist/CallingClient/utils/request.test.js.map +1 -1
  5. package/dist/CallingClient/utils/types.js.map +1 -1
  6. package/dist/mobius-socket/config.js +7 -44
  7. package/dist/mobius-socket/config.js.map +1 -1
  8. package/dist/mobius-socket/errors.js +71 -26
  9. package/dist/mobius-socket/errors.js.map +1 -1
  10. package/dist/mobius-socket/index.js +4 -54
  11. package/dist/mobius-socket/index.js.map +1 -1
  12. package/dist/mobius-socket/mobius-socket-events.test.js +20 -48
  13. package/dist/mobius-socket/mobius-socket-events.test.js.map +1 -1
  14. package/dist/mobius-socket/mobius-socket.js +359 -748
  15. package/dist/mobius-socket/mobius-socket.js.map +1 -1
  16. package/dist/mobius-socket/mobius-socket.test.js +452 -728
  17. package/dist/mobius-socket/mobius-socket.test.js.map +1 -1
  18. package/dist/mobius-socket/socket/constants.js +14 -0
  19. package/dist/mobius-socket/socket/constants.js.map +1 -1
  20. package/dist/mobius-socket/socket/socket-base.js +152 -205
  21. package/dist/mobius-socket/socket/socket-base.js.map +1 -1
  22. package/dist/mobius-socket/socket/types.js.map +1 -1
  23. package/dist/mobius-socket/socket.test.js +38 -63
  24. package/dist/mobius-socket/socket.test.js.map +1 -1
  25. package/dist/mobius-socket/types.js.map +1 -1
  26. package/dist/module/CallingClient/utils/request.js +3 -2
  27. package/dist/module/mobius-socket/config.js +7 -10
  28. package/dist/module/mobius-socket/errors.js +34 -0
  29. package/dist/module/mobius-socket/index.js +0 -3
  30. package/dist/module/mobius-socket/mobius-socket.js +237 -426
  31. package/dist/module/mobius-socket/socket/socket-base.js +79 -116
  32. package/dist/types/CallingClient/utils/request.d.ts.map +1 -1
  33. package/dist/types/CallingClient/utils/types.d.ts +1 -1
  34. package/dist/types/CallingClient/utils/types.d.ts.map +1 -1
  35. package/dist/types/mobius-socket/config.d.ts +7 -8
  36. package/dist/types/mobius-socket/config.d.ts.map +1 -1
  37. package/dist/types/mobius-socket/errors.d.ts +11 -1
  38. package/dist/types/mobius-socket/errors.d.ts.map +1 -1
  39. package/dist/types/mobius-socket/index.d.ts +1 -5
  40. package/dist/types/mobius-socket/index.d.ts.map +1 -1
  41. package/dist/types/mobius-socket/mobius-socket.d.ts +33 -35
  42. package/dist/types/mobius-socket/mobius-socket.d.ts.map +1 -1
  43. package/dist/types/mobius-socket/socket/constants.d.ts.map +1 -1
  44. package/dist/types/mobius-socket/socket/socket-base.d.ts +9 -10
  45. package/dist/types/mobius-socket/socket/socket-base.d.ts.map +1 -1
  46. package/dist/types/mobius-socket/socket/types.d.ts +0 -8
  47. package/dist/types/mobius-socket/socket/types.d.ts.map +1 -1
  48. package/dist/types/mobius-socket/types.d.ts.map +1 -1
  49. package/package.json +1 -1
@@ -1,11 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
4
- var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");
5
- var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");
6
- var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");
7
- var _Array$isArray2 = require("@babel/runtime-corejs2/core-js/array/is-array");
8
- var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
4
+ var _Object$keys = require("@babel/runtime-corejs2/core-js/object/keys");
9
5
  var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
10
6
  var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
11
7
  var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
@@ -17,12 +13,10 @@ _Object$defineProperty(exports, "__esModule", {
17
13
  });
18
14
  exports.default = void 0;
19
15
  var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
20
- var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
21
- var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
22
16
  var _isArray = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/is-array"));
17
+ var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
23
18
  var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
24
- var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
25
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
19
+ var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
26
20
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
27
21
  var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/typeof"));
28
22
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
@@ -31,28 +25,24 @@ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime
31
25
  var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
32
26
  var _get2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/get"));
33
27
  var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
34
- var _set2 = _interopRequireDefault(require("lodash/set"));
35
- var _camelCase2 = _interopRequireDefault(require("lodash/camelCase"));
28
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
36
29
  var _events = require("events");
37
30
  var _backoff = _interopRequireDefault(require("backoff"));
38
31
  var _socket = _interopRequireDefault(require("./socket"));
39
32
  var _errors = require("./errors");
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$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
33
+ function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
41
34
  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$getOwnPropertyDescriptor(t, r)); }); } return e; }
42
- function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof _Symbol && r[_Symbol$iterator] || r["@@iterator"]; if (!t) { if (_Array$isArray2(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; } } }; }
43
- 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; } }
44
- 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; }
45
35
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? _Reflect$construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
46
36
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
47
- function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; } // @ts-nocheck
48
- /* eslint-disable require-jsdoc */ /*!
37
+ function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; } /*!
49
38
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file
50
- */
39
+ */ // @ts-ignore - backoff library does not have type definitions
51
40
  var normalReconnectReasons = ['idle', 'done (forced)'];
52
- var DEFAULT_MOBIUS_WEBSOCKET_SESSION = 'mobius-websocket-session';
53
41
  var MOBIUS_SOCKET_NAMESPACE = 'MobiusSocket';
54
42
  var TOKEN_REFRESH_INTERVAL_MS = 1 * 60 * 60 * 1000; // 1 hour
55
43
 
44
+ // Extended Socket type with dynamic properties
45
+
56
46
  function normalizeMobiusAuthToken(token) {
57
47
  return token.replace(/^Bearer\s+/i, '');
58
48
  }
@@ -62,26 +52,38 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
62
52
  var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
63
53
  (0, _classCallCheck2.default)(this, MobiusSocket);
64
54
  _this = _callSuper(this, MobiusSocket);
55
+ (0, _defineProperty2.default)(_this, "webex", void 0);
56
+ (0, _defineProperty2.default)(_this, "config", void 0);
57
+ (0, _defineProperty2.default)(_this, "logger", void 0);
58
+ (0, _defineProperty2.default)(_this, "connected", void 0);
59
+ (0, _defineProperty2.default)(_this, "connecting", void 0);
60
+ (0, _defineProperty2.default)(_this, "hasEverConnected", void 0);
61
+ (0, _defineProperty2.default)(_this, "socket", void 0);
62
+ (0, _defineProperty2.default)(_this, "backoffCall", void 0);
63
+ // backoff library has no types
64
+ (0, _defineProperty2.default)(_this, "shutdownSwitchoverBackoffCall", void 0);
65
+ // backoff library has no types
66
+ (0, _defineProperty2.default)(_this, "seenAsyncEventIds", void 0);
67
+ (0, _defineProperty2.default)(_this, "connectPromise", void 0);
68
+ (0, _defineProperty2.default)(_this, "socketUrl", void 0);
69
+ (0, _defineProperty2.default)(_this, "tokenRefreshTimer", void 0);
70
+ (0, _defineProperty2.default)(_this, "tokenRefreshInFlight", void 0);
65
71
  if (!webex) {
66
72
  throw new Error('A Webex instance is required when initializing MobiusSocket');
67
73
  }
68
74
  _this.webex = webex;
69
75
  _this.config = config;
70
76
  _this.logger = webex.logger || console;
71
- _this.defaultSessionId = DEFAULT_MOBIUS_WEBSOCKET_SESSION;
72
77
  _this.connected = false;
73
78
  _this.connecting = false;
74
79
  _this.hasEverConnected = false;
75
80
  _this.socket = undefined;
76
- _this.sockets = new _map.default();
77
- _this.backoffCalls = new _map.default();
78
- _this._shutdownSwitchoverBackoffCalls = new _map.default();
79
- _this._seenAsyncEventIdsBySession = new _map.default();
80
- _this._connectPromises = new _map.default();
81
- _this.mercuryTimeOffset = undefined;
82
- _this._tokenRefreshTimer = undefined;
83
- _this._tokenRefreshInFlight = undefined;
84
- _this._bindInternalEvents();
81
+ _this.backoffCall = undefined;
82
+ _this.shutdownSwitchoverBackoffCall = undefined;
83
+ _this.seenAsyncEventIds = new _map.default();
84
+ _this.connectPromise = undefined;
85
+ _this.tokenRefreshTimer = undefined;
86
+ _this.tokenRefreshInFlight = undefined;
85
87
  return _this;
86
88
  }
87
89
  (0, _inherits2.default)(MobiusSocket, _EventEmitter);
@@ -94,143 +96,49 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
94
96
  this.removeAllListeners(eventName);
95
97
  return this;
96
98
  }
97
- }, {
98
- key: "_bindInternalEvents",
99
- value: function _bindInternalEvents() {
100
- var _this2 = this;
101
- /*
102
- When one of these legacy feature gets updated, this event would be triggered
103
- * group-message-notifications
104
- * mention-notifications
105
- * thread-notifications
106
- */
107
- this.on('event:featureToggle_update', function (envelope) {
108
- if (envelope && envelope.data) {
109
- _this2.webex.internal.feature.updateFeature(envelope.data.featureToggle);
110
- }
111
- });
112
- /*
113
- * When Cluster Migrations, notify clients using ActiveClusterStatusEvent via mercury
114
- * https://wwwin-github.cisco.com/pages/Webex/crr-docs/techdocs/rr-002.html#wip-notifying-clients-of-cluster-migrations
115
- * */
116
- this.on('event:ActiveClusterStatusEvent', function (envelope) {
117
- var _this2$webex$internal;
118
- if (typeof ((_this2$webex$internal = _this2.webex.internal.services) === null || _this2$webex$internal === void 0 ? void 0 : _this2$webex$internal.switchActiveClusterIds) === 'function' && envelope && envelope.data) {
119
- var _envelope$data;
120
- _this2.webex.internal.services.switchActiveClusterIds((_envelope$data = envelope.data) === null || _envelope$data === void 0 ? void 0 : _envelope$data.activeClusters);
121
- }
122
- });
123
- /*
124
- * Using cache-invalidation via mercury to instead the method of polling via the new /timestamp endpoint from u2c
125
- * https://wwwin-github.cisco.com/pages/Webex/crr-docs/techdocs/rr-005.html#websocket-notifications
126
- * */
127
- this.on('event:u2c.cache-invalidation', function (envelope) {
128
- var _this2$webex$internal2;
129
- if (typeof ((_this2$webex$internal2 = _this2.webex.internal.services) === null || _this2$webex$internal2 === void 0 ? void 0 : _this2$webex$internal2.invalidateCache) === 'function' && envelope && envelope.data) {
130
- var _envelope$data2;
131
- _this2.webex.internal.services.invalidateCache((_envelope$data2 = envelope.data) === null || _envelope$data2 === void 0 ? void 0 : _envelope$data2.timestamp);
132
- }
133
- });
134
- }
135
99
 
136
100
  /**
137
101
  * Attach event listeners to a socket.
138
- * @param {Socket} socket - The socket to attach listeners to
139
- * @param {sessionId} sessionId - The socket related session ID
140
- * @returns {void}
102
+ * @param socket - The socket to attach listeners to
141
103
  */
142
104
  }, {
143
- key: "_attachSocketEventListeners",
144
- value: function _attachSocketEventListeners(socket, sessionId) {
145
- var _this3 = this;
105
+ key: "attachSocketEventListeners",
106
+ value: function attachSocketEventListeners(socket) {
107
+ var _this2 = this;
146
108
  socket.on('close', function (event) {
147
- return _this3._onclose(sessionId, event, socket);
109
+ return _this2.onclose(event, socket);
148
110
  });
149
- socket.on('message', function () {
150
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
151
- args[_key] = arguments[_key];
152
- }
153
- return _this3._onmessage.apply(_this3, [sessionId].concat(args));
154
- });
155
- socket.on('pong', function () {
156
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
157
- args[_key2] = arguments[_key2];
158
- }
159
- return _this3._setTimeOffset.apply(_this3, [sessionId].concat(args));
111
+ socket.on('message', function (event) {
112
+ return _this2.onmessage(event);
160
113
  });
161
- socket.on('sequence-mismatch', function () {
162
- for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
163
- args[_key3] = arguments[_key3];
164
- }
165
- return _this3._emit.apply(_this3, [sessionId, 'sequence-mismatch'].concat(args));
166
- });
167
- socket.on('ping-pong-latency', function () {
168
- for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
169
- args[_key4] = arguments[_key4];
170
- }
171
- return _this3._emit.apply(_this3, [sessionId, 'ping-pong-latency'].concat(args));
172
- });
173
- }
174
-
175
- /**
176
- * Returns the per-session cache of seen async_event IDs, creating it on first access.
177
- * @param {string} sessionId - The session identifier.
178
- * @returns {Map<string, boolean>} Ordered cache of seen event IDs for the session.
179
- */
180
- }, {
181
- key: "_getSeenAsyncEventIds",
182
- value: function _getSeenAsyncEventIds(sessionId) {
183
- var seenAsyncEventIds = this._seenAsyncEventIdsBySession.get(sessionId);
184
- if (!seenAsyncEventIds) {
185
- seenAsyncEventIds = new _map.default();
186
- this._seenAsyncEventIdsBySession.set(sessionId, seenAsyncEventIds);
187
- }
188
- return seenAsyncEventIds;
189
- }
190
-
191
- /**
192
- * Clears the dedup cache for one session or for all sessions when omitted.
193
- * @param {string} [sessionId] - Optional session identifier.
194
- * @returns {void}
195
- */
196
- }, {
197
- key: "_clearSeenAsyncEventIds",
198
- value: function _clearSeenAsyncEventIds(sessionId) {
199
- if (sessionId) {
200
- this._seenAsyncEventIdsBySession.delete(sessionId);
201
- return;
202
- }
203
- this._seenAsyncEventIdsBySession.clear();
204
114
  }
205
115
 
206
116
  /**
207
117
  * Tracks a newly seen async_event ID and reports whether a duplicate should be suppressed.
208
- * @param {string} sessionId - The session identifier.
209
- * @param {object} envelope - Parsed websocket message envelope.
210
- * @returns {boolean} True when the event has already been seen for this session.
118
+ * @param envelope - Parsed websocket message envelope
119
+ * @returns True when the event has already been seen
211
120
  */
212
121
  }, {
213
- key: "_trackAsyncEventAndShouldSuppressDuplicate",
214
- value: function _trackAsyncEventAndShouldSuppressDuplicate(sessionId, envelope) {
122
+ key: "trackAsyncEventAndShouldSuppressDuplicate",
123
+ value: function trackAsyncEventAndShouldSuppressDuplicate(envelope) {
215
124
  if ((envelope === null || envelope === void 0 ? void 0 : envelope.type) !== 'async_event' || !envelope.eventId) {
216
125
  return false;
217
126
  }
218
- var seenAsyncEventIds = this._getSeenAsyncEventIds(sessionId);
219
- if (seenAsyncEventIds.has(envelope.eventId)) {
220
- var previousValue = seenAsyncEventIds.get(envelope.eventId);
221
-
127
+ if (this.seenAsyncEventIds.has(envelope.eventId)) {
222
128
  // Refresh recency so frequently retransmitted eventIds stay protected longer.
223
- seenAsyncEventIds.delete(envelope.eventId);
224
- seenAsyncEventIds.set(envelope.eventId, previousValue);
225
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": duplicate async_event suppressed for ").concat(sessionId, ", eventId=").concat(envelope.eventId));
129
+ // This deletion and setting again makes the data recent since javascript map maintains order as well
130
+ var previousValue = this.seenAsyncEventIds.get(envelope.eventId) || true;
131
+ this.seenAsyncEventIds.delete(envelope.eventId);
132
+ this.seenAsyncEventIds.set(envelope.eventId, previousValue);
133
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": duplicate async_event suppressed, eventId=").concat(envelope.eventId));
226
134
  return true;
227
135
  }
228
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": tracking async_event for ").concat(sessionId, ", eventId=").concat(envelope.eventId));
229
- seenAsyncEventIds.set(envelope.eventId, true);
230
- if (seenAsyncEventIds.size > this.config.dedupCacheMaxSize) {
231
- var oldestEventId = seenAsyncEventIds.keys().next().value;
232
- seenAsyncEventIds.delete(oldestEventId);
233
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": evicted oldest async_event from dedup cache for ").concat(sessionId, ", eventId=").concat(oldestEventId));
136
+ this.logger.log("".concat(MOBIUS_SOCKET_NAMESPACE, ": tracking async_event, eventId=").concat(envelope.eventId));
137
+ this.seenAsyncEventIds.set(envelope.eventId, true);
138
+ if (this.config.dedupCacheMaxSize && this.seenAsyncEventIds.size > this.config.dedupCacheMaxSize) {
139
+ var oldestEventId = this.seenAsyncEventIds.keys().next().value || '';
140
+ this.seenAsyncEventIds.delete(oldestEventId);
141
+ this.logger.log("".concat(MOBIUS_SOCKET_NAMESPACE, ": evicted oldest async_event from dedup cache, eventId=").concat(oldestEventId));
234
142
  }
235
143
  return false;
236
144
  }
@@ -239,179 +147,93 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
239
147
  * Handle imminent shutdown by establishing a new connection while keeping
240
148
  * the current one alive (make-before-break).
241
149
  * Idempotent: will no-op if already in progress.
242
- * @param {string} sessionId - The session ID for which the shutdown is imminent
243
- * @returns {void}
244
150
  */
245
151
  }, {
246
- key: "_handleImminentShutdown",
247
- value: function _handleImminentShutdown(sessionId) {
248
- var _this4 = this;
249
- var oldSocket = this.sockets.get(sessionId);
152
+ key: "handleImminentShutdown",
153
+ value: function handleImminentShutdown() {
154
+ var _this3 = this;
155
+ var oldSocket = this.socket;
250
156
  try {
251
- // Idempotent: if we already have a switchover backoff call for this session,
252
- // a switchover is in progress – do nothing.
253
- if (this._shutdownSwitchoverBackoffCalls.get(sessionId)) {
254
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover already in progress for ").concat(sessionId));
157
+ if (this.shutdownSwitchoverBackoffCall) {
158
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover already in progress"));
255
159
  return;
256
160
  }
257
- var switchoverId = "".concat((0, _now.default)());
258
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover start, id=").concat(switchoverId, " for ").concat(sessionId));
259
- this._connectWithBackoff(undefined, sessionId, {
161
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover start"));
162
+ this.connectWithBackoff(undefined, {
260
163
  isShutdownSwitchover: true,
261
164
  attemptOptions: {
262
165
  isShutdownSwitchover: true,
263
166
  onSuccess: function onSuccess(newSocket, webSocketUrl) {
264
- _this4.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover connected, url: ").concat(webSocketUrl, " for ").concat(sessionId));
265
-
266
- // Atomically switch active socket reference
267
- _this4.socket = _this4.sockets.get(_this4.defaultSessionId);
268
- _this4.connected = _this4.hasConnectedSockets(); // remain connected throughout
269
-
270
- _this4._emit(sessionId, 'event:mercury_shutdown_switchover_complete', {
167
+ _this3.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover connected, url: ").concat(webSocketUrl));
168
+
169
+ // Promote the new socket now that the switchover succeeded
170
+ newSocket.connecting = false;
171
+ newSocket.connected = true;
172
+ _this3.socket = newSocket;
173
+ _this3.connected = true;
174
+ _this3.emitEvent('event:mobius_shutdown_switchover_complete', {
271
175
  url: webSocketUrl
272
176
  });
273
177
  if (oldSocket) {
274
- _this4.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] old socket retained; server will close with 4001"));
178
+ _this3.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] old socket retained; server will close with 4001"));
275
179
  }
276
180
  }
277
181
  }
278
182
  }).then(function () {
279
- _this4.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover completed successfully for ").concat(sessionId));
183
+ _this3.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover completed successfully"));
280
184
  }).catch(function (err) {
281
- _this4.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover exhausted retries; will fall back to normal reconnection for ").concat(sessionId, ": "), err);
282
- _this4._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {
185
+ _this3.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover exhausted retries; will fall back to normal reconnection: "), err);
186
+ _this3.emitEvent('event:mobius_shutdown_switchover_failed', {
283
187
  reason: err
284
188
  });
285
- // Old socket will eventually close with 4001, triggering normal reconnection
286
189
  });
287
190
  } catch (e) {
288
- this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] error during switchover for ").concat(sessionId), e);
289
- this._shutdownSwitchoverBackoffCalls.delete(sessionId);
290
- this._emit(sessionId, 'event:mercury_shutdown_switchover_failed', {
191
+ this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] error during switchover"), e);
192
+ this.shutdownSwitchoverBackoffCall = undefined;
193
+ this.emitEvent('event:mobius_shutdown_switchover_failed', {
291
194
  reason: e
292
195
  });
293
196
  }
294
197
  }
295
198
 
296
199
  /**
297
- * Get the last error.
298
- * @returns {unknown} The last error.
299
- */
300
- }, {
301
- key: "getLastError",
302
- value: function getLastError() {
303
- return this.lastError;
304
- }
305
-
306
- /**
307
- * Get all active socket connections
308
- * @returns {Map} Map of sessionId to socket instances
309
- */
310
- }, {
311
- key: "getSockets",
312
- value: function getSockets() {
313
- return this.sockets;
314
- }
315
-
316
- /**
317
- * Get a specific socket by connection ID
318
- * @param {string} sessionId - The connection identifier
319
- * @returns {Socket|undefined} The socket instance or undefined if not found
320
- */
321
- }, {
322
- key: "getSocket",
323
- value: function getSocket() {
324
- var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
325
- return this.sockets.get(sessionId);
326
- }
327
-
328
- /**
329
- * Get the websocket URL for a currently connected session.
330
- * @param {string} [sessionId=this.defaultSessionId] - The session identifier.
331
- * @returns {string|undefined} The connected websocket URL, or undefined when not connected.
200
+ * Get the websocket URL for the currently connected socket.
201
+ * @returns The connected websocket URL, or undefined when not connected
332
202
  */
333
203
  }, {
334
204
  key: "getConnectedWebSocketUrl",
335
205
  value: function getConnectedWebSocketUrl() {
336
- var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
337
- var socket = this.getSocket(sessionId);
338
- if (!(socket !== null && socket !== void 0 && socket.connected)) {
206
+ var _this$socket;
207
+ if (!((_this$socket = this.socket) !== null && _this$socket !== void 0 && _this$socket.connected)) {
339
208
  return undefined;
340
209
  }
341
- return socket.url;
342
- }
343
-
344
- /**
345
- * Sends a payload on the active connected socket
346
- * @param {Object} payload - The data to send
347
- * @param {string} [sessionId=this.defaultSessionId] - The session identifier
348
- * @returns {Promise}
349
- */
350
- }, {
351
- key: "send",
352
- value: function send(payload) {
353
- var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
354
- var socket = this.getSocket(sessionId);
355
- if (!socket || !socket.connected) {
356
- return _promise.default.reject(new Error("Mobius socket is not connected for session ".concat(sessionId)));
357
- }
358
- return socket.send(payload);
210
+ return this.socket.url;
359
211
  }
360
212
 
361
213
  /**
362
214
  * Sends a websocket request and resolves when the matching response arrives.
363
- * @param {Object} payload - The websocket request payload.
364
- * @param {string|Object} [sessionIdOrRequestOptions=this.defaultSessionId] - Session ID or request options.
365
- * @param {Object} [options={}] - Additional request options.
366
- * @returns {Promise<Object>}
215
+ * @param payload - The websocket request payload
216
+ * @param options - Additional request options
217
+ * @returns Promise that resolves with the socket response
367
218
  */
368
219
  }, {
369
220
  key: "sendWssRequest",
370
221
  value: function sendWssRequest(payload) {
371
- var _this5 = this;
372
- var sessionIdOrRequestOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
373
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
222
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
374
223
  if (!payload || (0, _typeof2.default)(payload) !== 'object' || (0, _isArray.default)(payload)) {
375
224
  return _promise.default.reject(new Error('`payload` is required'));
376
225
  }
377
- var sessionId = this.defaultSessionId;
378
- var requestOptions = options;
379
- if (typeof sessionIdOrRequestOptions === 'string') {
380
- sessionId = sessionIdOrRequestOptions;
381
- } else if (sessionIdOrRequestOptions && (0, _typeof2.default)(sessionIdOrRequestOptions) === 'object') {
382
- requestOptions = sessionIdOrRequestOptions;
383
- }
384
- var socket = this.getSocket(sessionId);
385
- if (!socket || !socket.connected) {
386
- return _promise.default.reject(new Error("Mobius socket is not connected for session ".concat(sessionId)));
226
+ if (!this.socket || !this.socket.connected) {
227
+ return _promise.default.reject(new Error('Mobius socket is not connected'));
387
228
  }
388
- return socket.sendRequest(payload, {
389
- timeout: requestOptions.timeout,
390
- matchesResponse: function matchesResponse(response, request) {
391
- return (response === null || response === void 0 ? void 0 : response.type) === 'response_event' && (response === null || response === void 0 ? void 0 : response.subtype) === request.type && (response === null || response === void 0 ? void 0 : response.trackingId) === request.trackingId;
392
- },
393
- getStatusCode: function getStatusCode(response) {
394
- return response === null || response === void 0 ? void 0 : response.statusCode;
395
- },
396
- getStatusMessage: function getStatusMessage(response) {
397
- return response === null || response === void 0 ? void 0 : response.statusMessage;
398
- },
399
- createError: function createError(response, statusCode, statusMessage) {
400
- return _this5._createWssResponseError(response, statusCode, statusMessage);
401
- },
402
- createTimeoutError: function createTimeoutError(request) {
403
- return _this5._createWssResponseError({
404
- type: 'response_event',
405
- subtype: request.type,
406
- trackingId: request.trackingId
407
- }, 408, 'Mobius websocket response timed out');
408
- }
229
+ return this.socket.sendRequest(payload, {
230
+ timeout: options.timeout
409
231
  });
410
232
  }
411
233
 
412
234
  /**
413
- * Check if the plugin is connected
414
- * @returns {boolean} True if connected
235
+ * Check if the socket is connected.
236
+ * @returns True if connected
415
237
  */
416
238
  }, {
417
239
  key: "isConnected",
@@ -420,66 +242,24 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
420
242
  }
421
243
 
422
244
  /**
423
- * Check if a socket is connected
424
- * @param {string} [sessionId] - Optional session identifier
425
- * @returns {boolean|undefined} True if the socket is connected
426
- */
427
- }, {
428
- key: "hasConnectedSockets",
429
- value: function hasConnectedSockets(sessionId) {
430
- if (sessionId) {
431
- var _this$sockets$get;
432
- return Boolean((_this$sockets$get = this.sockets.get(sessionId)) === null || _this$sockets$get === void 0 ? void 0 : _this$sockets$get.connected);
433
- }
434
- var _iterator = _createForOfIteratorHelper(this.sockets.values()),
435
- _step;
436
- try {
437
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
438
- var socket = _step.value;
439
- if (socket !== null && socket !== void 0 && socket.connected) {
440
- return true;
441
- }
442
- }
443
- } catch (err) {
444
- _iterator.e(err);
445
- } finally {
446
- _iterator.f();
447
- }
448
- return false;
449
- }
450
-
451
- /**
452
- * Check if any sockets are connecting
453
- * @param {string} [sessionId=this.defaultSessionId] - The session identifier
454
- * @returns {boolean|undefined} True if the socket is connecting
455
- */
456
- }, {
457
- key: "hasConnectingSockets",
458
- value: function hasConnectingSockets() {
459
- var sessionId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.defaultSessionId;
460
- var socket = this.sockets.get(sessionId || this.defaultSessionId);
461
- return Boolean(socket === null || socket === void 0 ? void 0 : socket.connecting);
462
- }
463
-
464
- /**
465
- * Connect to Mobius for a specific session.
466
- * @param {string} [webSocketUrl] - Optional websocket URL override. Falls back to the device websocket URL.
467
- * @param {string} [sessionId=this.defaultSessionId] - The session identifier for this connection.
468
- * @returns {Promise<void>} Resolves when connection flow completes for the session.
245
+ * Connect to Mobius.
246
+ * @param webSocketUrl - Optional websocket URL override. Falls back to the device websocket URL
247
+ * @returns Promise that resolves when connection flow completes
469
248
  */
470
249
  }, {
471
250
  key: "connect",
472
251
  value: function connect(webSocketUrl) {
473
- var _this6 = this;
474
- var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
475
- // First check if there's already a connection promise for this session
476
- if (this._connectPromises.has(sessionId)) {
477
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connection ").concat(sessionId, " already in progress, returning existing promise"));
478
- return this._connectPromises.get(sessionId);
479
- }
480
- var sessionSocket = this.sockets.get(sessionId);
481
- if (sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connected || sessionSocket !== null && sessionSocket !== void 0 && sessionSocket.connecting) {
482
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connection ").concat(sessionId, " already connected, will not connect again"));
252
+ var _this$socket2,
253
+ _this$socket3,
254
+ _this$webex$internal$,
255
+ _this$webex$internal$2,
256
+ _this4 = this;
257
+ if (this.connectPromise) {
258
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connection already in progress, returning existing promise"));
259
+ return this.connectPromise;
260
+ }
261
+ if ((_this$socket2 = this.socket) !== null && _this$socket2 !== void 0 && _this$socket2.connected || (_this$socket3 = this.socket) !== null && _this$socket3 !== void 0 && _this$socket3.connecting) {
262
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": already connected, will not connect again"));
483
263
  return _promise.default.resolve();
484
264
  }
485
265
 
@@ -490,182 +270,88 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
490
270
  }
491
271
 
492
272
  // Cache the caller-provided URL for reconnect
493
- var resolvedUrl = webSocketUrl || this.socketUrl;
494
273
  if (webSocketUrl) {
495
274
  this.socketUrl = webSocketUrl;
496
275
  }
497
276
  this.connecting = true;
498
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": starting connection attempt for ").concat(sessionId).concat(Number(this.config.initialConnectionMaxRetries) === 0 && !this.hasEverConnected ? ' (initial retries disabled)' : ''));
499
- var connectPromise = _promise.default.resolve(this.webex.internal.device.registered || this.webex.internal.device.register()).then(function () {
500
- _this6.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connecting ").concat(sessionId));
501
- return _this6._connectWithBackoff(resolvedUrl, sessionId);
277
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": starting connection attempt").concat(Number(this.config.initialConnectionMaxRetries) === 0 && !this.hasEverConnected ? ' (initial retries disabled)' : ''));
278
+ var connectPromise = _promise.default.resolve(this.webex.internal.device.registered || ((_this$webex$internal$ = (_this$webex$internal$2 = this.webex.internal.device).register) === null || _this$webex$internal$ === void 0 ? void 0 : _this$webex$internal$.call(_this$webex$internal$2))).then(function () {
279
+ _this4.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connecting"));
280
+ return _this4.connectWithBackoff(_this4.socketUrl);
502
281
  }).finally(function () {
503
- _this6._connectPromises.delete(sessionId);
282
+ _this4.connectPromise = undefined;
504
283
  });
505
- this._connectPromises.set(sessionId, connectPromise);
284
+ this.connectPromise = connectPromise;
506
285
  return connectPromise;
507
286
  }
508
- }, {
509
- key: "logout",
510
- value: function logout() {
511
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": logout() called"));
512
- return this.disconnectAll(this.config.beforeLogoutOptionsCloseReason && !normalReconnectReasons.includes(this.config.beforeLogoutOptionsCloseReason) ? {
513
- code: 3050,
514
- reason: this.config.beforeLogoutOptionsCloseReason
515
- } : undefined);
516
- }
517
287
 
518
288
  /**
519
- * Disconnect a Mobius socket for a specific session.
520
- * @param {object} [options] - Optional websocket close options (for example: `{code, reason}`).
521
- * @param {string} [sessionId=this.defaultSessionId] - The session identifier to disconnect.
522
- * @returns {Promise<void>} Resolves after disconnect cleanup and close handling are initiated/completed.
289
+ * Disconnect the Mobius socket.
290
+ * @param options - Optional websocket close options (code, reason)
291
+ * @returns Promise that resolves after disconnect cleanup and close handling complete
523
292
  */
524
293
  }, {
525
294
  key: "disconnect",
526
295
  value: function disconnect(options) {
527
- var _this7 = this;
528
- var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
529
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, "#disconnect: connecting state: ").concat(this.connecting, ", connected state: ").concat(this.connected, ", socket exists: ").concat(!!this.socket, ", options: ").concat((0, _stringify.default)(options)));
530
- var backoffCall = this.backoffCalls.get(sessionId);
531
- if (backoffCall) {
532
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": aborting connection ").concat(sessionId));
533
- backoffCall.abort();
534
- this.backoffCalls.delete(sessionId);
535
- }
536
- var shutdownSwitchoverBackoffCall = this._shutdownSwitchoverBackoffCalls.get(sessionId);
537
- if (shutdownSwitchoverBackoffCall) {
538
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": aborting shutdown switchover connection ").concat(sessionId));
539
- shutdownSwitchoverBackoffCall.abort();
540
- this._shutdownSwitchoverBackoffCalls.delete(sessionId);
541
- }
542
- // Clean up any pending connection promises
543
- this._connectPromises.delete(sessionId);
544
- var sessionSocket = this.sockets.get(sessionId);
545
- this._clearSeenAsyncEventIds(sessionId);
546
- if (!sessionSocket) {
547
- this.connected = this.hasConnectedSockets();
548
- if (!this.hasConnectedSockets()) {
549
- this._stopTokenRefreshTimer();
550
- }
296
+ var _this5 = this;
297
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, "#disconnect: connecting state: ").concat(this.connecting, ",\n connected state: ").concat(this.connected, ", socket exists: ").concat(!!this.socket, ",\n options: ").concat((0, _stringify.default)(options)));
298
+ if (this.backoffCall) {
299
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": aborting connection"));
300
+ this.backoffCall.abort();
301
+ this.backoffCall = undefined;
302
+ }
303
+ if (this.shutdownSwitchoverBackoffCall) {
304
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": aborting shutdown switchover connection"));
305
+ this.shutdownSwitchoverBackoffCall.abort();
306
+ this.shutdownSwitchoverBackoffCall = undefined;
307
+ }
308
+ this.connectPromise = undefined;
309
+ this.seenAsyncEventIds.clear();
310
+ if (!this.socket) {
311
+ this.connected = false;
312
+ this.stopTokenRefreshTimer();
551
313
  return _promise.default.resolve();
552
314
  }
553
- sessionSocket.removeAllListeners('message');
554
- sessionSocket.connecting = false;
555
- sessionSocket.connected = false;
556
- return _promise.default.resolve(sessionSocket.close(options || undefined)).finally(function () {
557
- _this7.connected = _this7.hasConnectedSockets();
558
- if (!_this7.hasConnectedSockets()) {
559
- _this7._stopTokenRefreshTimer();
560
- }
315
+ this.socket.removeAllListeners('message');
316
+ this.socket.connecting = false;
317
+ this.socket.connected = false;
318
+ return _promise.default.resolve(this.socket.close(options || undefined)).finally(function () {
319
+ _this5.connected = false;
320
+ _this5.stopTokenRefreshTimer();
561
321
  });
562
322
  }
563
-
564
- /**
565
- * Disconnect all socket connections
566
- * @param {object} options - Close options
567
- * @returns {Promise} Promise that resolves when all connections are closed
568
- */
569
323
  }, {
570
- key: "disconnectAll",
571
- value: function disconnectAll(options) {
572
- var _this8 = this;
573
- var disconnectPromises = [];
574
- var _iterator2 = _createForOfIteratorHelper(this.sockets.keys()),
575
- _step2;
576
- try {
577
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
578
- var sessionId = _step2.value;
579
- disconnectPromises.push(this.disconnect(options, sessionId));
580
- }
581
- } catch (err) {
582
- _iterator2.e(err);
583
- } finally {
584
- _iterator2.f();
585
- }
586
- return _promise.default.all(disconnectPromises).then(function () {
587
- _this8.connected = false;
588
- _this8.socket = undefined;
589
- _this8.sockets.clear();
590
- _this8.backoffCalls.clear();
591
- _this8._shutdownSwitchoverBackoffCalls.clear();
592
- _this8._clearSeenAsyncEventIds();
593
- _this8._stopTokenRefreshTimer();
594
- _this8._connectPromises.clear();
595
- });
596
- }
597
- }, {
598
- key: "processRegistrationStatusEvent",
599
- value: function processRegistrationStatusEvent(message) {
600
- this.localClusterServiceUrls = message.localClusterServiceUrls;
601
- }
602
-
603
- // eslint-disable-next-line class-methods-use-this
604
- }, {
605
- key: "_createWssResponseError",
606
- value: function _createWssResponseError(response, statusCode, statusMessage) {
607
- var error = new Error(statusMessage || "Mobius websocket request failed with status ".concat(statusCode || 'unknown'));
608
- error.name = 'MobiusSocketResponseError';
609
- error.statusCode = statusCode;
610
- error.statusMessage = statusMessage;
611
- error.response = response;
612
- error.trackingId = response === null || response === void 0 ? void 0 : response.trackingId;
613
- return error;
614
- }
615
-
616
- // eslint-disable-next-line class-methods-use-this
617
- }, {
618
- key: "_applyOverrides",
619
- value: function _applyOverrides(event) {
620
- if (!event || !event.headers) {
621
- return;
622
- }
623
- var headerKeys = (0, _keys.default)(event.headers);
624
- headerKeys.forEach(function (keyPath) {
625
- (0, _set2.default)(event, keyPath, event.headers[keyPath]);
626
- });
627
- }
628
- }, {
629
- key: "_prepareUrl",
630
- value: function _prepareUrl(webSocketUrl) {
324
+ key: "prepareUrl",
325
+ value: function prepareUrl(webSocketUrl) {
631
326
  if (!webSocketUrl) {
632
- webSocketUrl = this.webex.internal.device.webSocketUrl;
327
+ // TODO: Circle back to this logic when mobius implements the shutdown switchover
328
+ webSocketUrl = this.webex.internal.device.webSocketUrl || '';
633
329
  }
634
-
635
- // TODO: Validate the host against the service catalog
636
- // const hostFromUrl = url.parse(webSocketUrl, true)?.host;
637
- // const isValidHost = this.webex.internal.services.isValidHost(hostFromUrl);
638
- // if (!isValidHost) {
639
- // this.logger.error(
640
- // `${MOBIUS_SOCKET_NAMESPACE}: host ${hostFromUrl} is not a valid host from host catalog`
641
- // );
642
- // return Promise.resolve('');
643
- // }
644
-
645
330
  return _promise.default.resolve(webSocketUrl);
646
331
  }
647
332
  }, {
648
- key: "_attemptConnection",
649
- value: function _attemptConnection(socketUrl, sessionId, callback) {
650
- var _this9 = this;
651
- var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
333
+ key: "attemptConnection",
334
+ value: function attemptConnection(socketUrl, callback) {
335
+ var _this6 = this;
336
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
652
337
  var _options$isShutdownSw = options.isShutdownSwitchover,
653
338
  isShutdownSwitchover = _options$isShutdownSw === void 0 ? false : _options$isShutdownSw,
654
- _options$onSuccess = options.onSuccess,
655
- onSuccess = _options$onSuccess === void 0 ? null : _options$onSuccess;
339
+ _options$attemptOptio = options.attemptOptions,
340
+ attemptOptions = _options$attemptOptio === void 0 ? {} : _options$attemptOptio;
341
+ var _attemptOptions$onSuc = attemptOptions.onSuccess,
342
+ onSuccess = _attemptOptions$onSuc === void 0 ? null : _attemptOptions$onSuc;
656
343
  var socket = new _socket.default();
657
344
  socket.connecting = true;
658
345
  var newWSUrl;
659
- this._attachSocketEventListeners(socket, sessionId);
660
- var backoffCall = isShutdownSwitchover ? this._shutdownSwitchoverBackoffCalls.get(sessionId) : this.backoffCalls.get(sessionId);
346
+ this.attachSocketEventListeners(socket);
347
+ var backoffCall = isShutdownSwitchover ? this.shutdownSwitchoverBackoffCall : this.backoffCall;
661
348
 
662
349
  // Check appropriate backoff call based on connection type
663
350
  if (!backoffCall) {
664
351
  var mode = isShutdownSwitchover ? 'switchover backoff call' : 'backoffCall';
665
- var msg = "".concat(MOBIUS_SOCKET_NAMESPACE, ": prevent socket open when ").concat(mode, " no longer defined for ").concat(sessionId);
352
+ var msg = "".concat(MOBIUS_SOCKET_NAMESPACE, ": prevent socket open when ").concat(mode, " no longer defined");
666
353
  var err = new Error(msg);
667
354
  this.logger.info(msg);
668
-
669
355
  // Call the callback with the error before rejecting
670
356
  callback(err);
671
357
  return _promise.default.reject(err);
@@ -674,11 +360,11 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
674
360
  // For shutdown switchover, don't set socket yet (make-before-break)
675
361
  // For normal connection, set socket before opening to allow disconnect() to close it
676
362
  if (!isShutdownSwitchover) {
677
- this.sockets.set(sessionId, socket);
363
+ this.socket = socket;
678
364
  }
679
- return this._prepareAndOpenSocket(socket, socketUrl, sessionId, isShutdownSwitchover).then(function (webSocketUrl) {
365
+ return this.prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover).then(function (webSocketUrl) {
680
366
  newWSUrl = webSocketUrl;
681
- _this9.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(isShutdownSwitchover ? '[shutdown] switchover' : '', " connected to mobius socket, success, action: connected for ").concat(sessionId, ", url: ").concat(newWSUrl));
367
+ _this6.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(isShutdownSwitchover ? '[shutdown] switchover' : '', " connected to mobius socket, success, url: ").concat(newWSUrl));
682
368
 
683
369
  // Custom success handler for shutdown switchover
684
370
  if (onSuccess) {
@@ -693,145 +379,131 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
693
379
  }).catch(function (reason) {
694
380
  // For shutdown, simpler error handling - just callback for retry
695
381
  if (isShutdownSwitchover) {
696
- _this9.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover attempt failed for ").concat(sessionId), reason);
382
+ _this6.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] switchover attempt failed"), reason);
697
383
  return callback(reason);
698
384
  }
699
385
 
700
- // Normal connection error handling (existing complex logic)
701
- _this9.lastError = reason; // remember the last error
702
-
703
- var backoffCallNormal = _this9.backoffCalls.get(sessionId);
704
- // Suppress connection errors that appear to be network related. This
705
- // may end up suppressing metrics during outages, but we might not care
706
- // (especially since many of our outages happen in a way that client
707
- // metrics can't be trusted).
386
+ // Normal connection error handling
387
+ var backoffCallNormal = _this6.backoffCall;
388
+ // Suppress connection errors that appear to be network related (code 1006).
708
389
  if (reason.code !== 1006 && backoffCallNormal && (backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()) > 0) {
709
- _this9._emit(sessionId, 'connection_failed', reason, {
710
- sessionId: sessionId,
390
+ _this6.emitEvent('connection_failed', reason, {
711
391
  retries: backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()
712
392
  });
713
393
  }
714
- _this9.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connection attempt failed for ").concat(sessionId), reason, (backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()) === 0 ? reason.stack : '');
715
- // UnknownResponse is produced by IE for any 4XXX; treated it like a bad
394
+ _this6.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connection attempt failed"), reason, (backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.getNumRetries()) === 0 ? reason.stack : '');
395
+
396
+ // UnknownResponse is produced by IE for any 4XXX; treat it like a bad
716
397
  // web socket url and let WDM handle the token checking
717
398
  if (reason instanceof _errors.UnknownResponse) {
718
- _this9.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": received unknown response code for ").concat(sessionId, ", refreshing device registration"));
719
- return _this9.webex.internal.device.refresh().then(function () {
399
+ var _this6$webex$internal, _this6$webex$internal2;
400
+ _this6.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": received unknown response code, refreshing device registration"));
401
+ return (_this6$webex$internal = (_this6$webex$internal2 = _this6.webex.internal.device).refresh) === null || _this6$webex$internal === void 0 ? void 0 : _this6$webex$internal.call(_this6$webex$internal2).then(function () {
720
402
  return callback(reason);
721
403
  });
722
404
  }
723
405
  // NotAuthorized implies expired token
724
406
  if (reason instanceof _errors.NotAuthorized) {
725
- _this9.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": received authorization error for ").concat(sessionId, ", reauthorizing"));
726
- return _this9.webex.credentials.refresh({
407
+ var _this6$webex$credenti, _this6$webex$credenti2;
408
+ _this6.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": received authorization error, reauthorizing"));
409
+ return (_this6$webex$credenti = (_this6$webex$credenti2 = _this6.webex.credentials).refresh) === null || _this6$webex$credenti === void 0 ? void 0 : _this6$webex$credenti.call(_this6$webex$credenti2, {
727
410
  force: true
728
411
  }).then(function () {
729
412
  return callback(reason);
730
413
  });
731
414
  }
732
- // // NotFound implies expired web socket url
733
- // else if (reason instanceof NotFound) {
734
- // this.logger.info(`mercury: received not found error, refreshing device registration`);
735
- // return this.webex.internal.device.refresh()
736
- // .then(() => callback(reason));
737
- // }
738
- // BadRequest implies current credentials are for a Service Account
739
- // Forbidden implies current user is not entitled for Webex
740
415
  if (reason instanceof _errors.BadRequest || reason instanceof _errors.Forbidden) {
741
- _this9.logger.warn("".concat(MOBIUS_SOCKET_NAMESPACE, ": received unrecoverable response from ").concat(MOBIUS_SOCKET_NAMESPACE, " for ").concat(sessionId));
416
+ _this6.logger.warn("".concat(MOBIUS_SOCKET_NAMESPACE, ": received unrecoverable response from ").concat(MOBIUS_SOCKET_NAMESPACE));
742
417
  backoffCallNormal === null || backoffCallNormal === void 0 ? void 0 : backoffCallNormal.abort();
743
418
  return callback(reason);
744
419
  }
745
420
  return callback(reason);
746
421
  }).catch(function (reason) {
747
- _this9.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": failed to handle connection failure for ").concat(sessionId), reason);
422
+ _this6.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": failed to handle connection failure"), reason);
748
423
  callback(reason);
749
424
  });
750
425
  }
751
426
  }, {
752
- key: "_prepareAndOpenSocket",
753
- value: function _prepareAndOpenSocket(socket, socketUrl, sessionId) {
754
- var _this0 = this;
755
- var isShutdownSwitchover = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
427
+ key: "prepareAndOpenSocket",
428
+ value: function prepareAndOpenSocket(socket, socketUrl) {
429
+ var _this7 = this;
430
+ var isShutdownSwitchover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
756
431
  var logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
757
- return _promise.default.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(function (_ref) {
432
+ return _promise.default.all([this.prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(function (_ref) {
758
433
  var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
759
434
  webSocketUrl = _ref2[0],
760
435
  token = _ref2[1];
761
436
  var options = {
762
- forceCloseDelay: _this0.config.forceCloseDelay,
763
- wssResponseTimeout: _this0.config.wssResponseTimeout,
764
- skipAckEventId: _this0.config.skipAckEventId,
765
- skipAckEventType: _this0.config.skipAckEventType,
437
+ forceCloseDelay: _this7.config.forceCloseDelay,
438
+ wssResponseTimeout: _this7.config.wssResponseTimeout,
766
439
  token: normalizeMobiusAuthToken(token.toString()),
767
440
  refreshToken: function refreshToken() {
768
- return _this0._refreshToken();
441
+ return _this7.refreshToken();
769
442
  },
770
- trackingId: "".concat(_this0.webex.sessionId, "_").concat((0, _now.default)()),
771
- logger: _this0.logger
443
+ trackingId: "".concat(_this7.webex.sessionId, "_").concat((0, _now.default)()),
444
+ logger: _this7.logger
772
445
  };
773
- if (_this0.webex.config.defaultMobiusSocketOptions) {
446
+ if (_this7.webex.config.defaultMobiusSocketOptions) {
774
447
  var customOptionsMsg = isShutdownSwitchover ? 'setting custom options for switchover' : 'setting custom options';
775
- _this0.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(customOptionsMsg));
776
- options = _objectSpread(_objectSpread({}, options), _this0.webex.config.defaultMobiusSocketOptions);
448
+ _this7.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(customOptionsMsg));
449
+ options = _objectSpread(_objectSpread({}, options), _this7.webex.config.defaultMobiusSocketOptions);
777
450
  }
778
451
 
779
- // Set the socket before opening it. This allows a disconnect() to close
780
- // the socket if it is in the process of being opened.
781
- _this0.sockets.set(sessionId, socket);
782
- _this0.socket = _this0.sockets.get(_this0.defaultSessionId);
783
- _this0.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, " ").concat(logPrefix, " url for ").concat(sessionId, ": ").concat(webSocketUrl));
452
+ // Only promote the socket reference for normal connections.
453
+ // Shutdown switchover keeps the old socket active until the new one succeeds.
454
+ if (!isShutdownSwitchover) {
455
+ _this7.socket = socket;
456
+ }
457
+ _this7.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, " ").concat(logPrefix, " url: ").concat(webSocketUrl));
784
458
  return socket.open(webSocketUrl, options).then(function () {
785
459
  return webSocketUrl;
786
460
  });
787
461
  });
788
462
  }
789
463
  }, {
790
- key: "_connectWithBackoff",
791
- value: function _connectWithBackoff(webSocketUrl, sessionId) {
792
- var _this1 = this;
793
- var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
464
+ key: "connectWithBackoff",
465
+ value: function connectWithBackoff(webSocketUrl) {
466
+ var _this8 = this;
467
+ var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
794
468
  var _context$isShutdownSw = context.isShutdownSwitchover,
795
469
  isShutdownSwitchover = _context$isShutdownSw === void 0 ? false : _context$isShutdownSw,
796
470
  _context$attemptOptio = context.attemptOptions,
797
471
  attemptOptions = _context$attemptOptio === void 0 ? {} : _context$attemptOptio;
798
472
  return new _promise.default(function (resolve, reject) {
799
- // eslint gets confused about whether call is actually used
800
- // eslint-disable-next-line prefer-const
801
473
  var call;
802
- var isInitialConnect = !isShutdownSwitchover && !_this1.hasEverConnected;
803
- var initialRetryLimit = _this1.config.initialConnectionMaxRetries == null ? null : Number(_this1.config.initialConnectionMaxRetries);
474
+ var isInitialConnect = !isShutdownSwitchover && !_this8.hasEverConnected;
475
+ var initialRetryLimit = _this8.config.initialConnectionMaxRetries == null ? null : Number(_this8.config.initialConnectionMaxRetries);
804
476
  var isInitialConnectWithoutRetries = isInitialConnect && initialRetryLimit === 0;
805
477
  var onComplete = function onComplete(err) {
806
- var sid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : sessionId;
807
478
  if (isShutdownSwitchover) {
808
- _this1._shutdownSwitchoverBackoffCalls.delete(sid);
479
+ _this8.shutdownSwitchoverBackoffCall = undefined;
809
480
  } else {
810
- _this1.backoffCalls.delete(sid);
481
+ _this8.backoffCall = undefined;
811
482
  }
812
- var sessionSocket = _this1.sockets.get(sid);
813
483
  if (err) {
814
484
  var msg = isShutdownSwitchover ? "[shutdown] switchover failed after ".concat(call.getNumRetries(), " retries") : "failed to connect after ".concat(call.getNumRetries(), " retries");
815
- _this1.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(msg, "; log statement about next retry was inaccurate; ").concat(err));
816
- if (sessionSocket) {
817
- sessionSocket.connecting = false;
818
- sessionSocket.connected = false;
485
+ _this8.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(msg, "; ").concat(err));
486
+ // Only mutate socket flags for normal connections.
487
+ // During shutdown switchover, this.socket is the old live socket — don't touch it.
488
+ if (!isShutdownSwitchover && _this8.socket) {
489
+ _this8.socket.connecting = false;
490
+ _this8.socket.connected = false;
819
491
  }
820
492
  return reject(err);
821
493
  }
822
494
 
823
- // Update overall connected status
824
- if (sessionSocket) {
825
- sessionSocket.connecting = false;
826
- sessionSocket.connected = true;
495
+ // For normal connections, mark the socket as connected.
496
+ // Shutdown switchover promotion is handled by the onSuccess callback.
497
+ if (!isShutdownSwitchover && _this8.socket) {
498
+ _this8.socket.connecting = false;
499
+ _this8.socket.connected = true;
827
500
  }
828
- // Default success handling for normal connections
829
501
  if (!isShutdownSwitchover) {
830
- _this1.connecting = _this1.hasConnectingSockets();
831
- _this1.connected = _this1.hasConnectedSockets();
832
- _this1.hasEverConnected = true;
833
- _this1._startTokenRefreshTimer();
834
- _this1._emit(sid, 'online');
502
+ _this8.connecting = false;
503
+ _this8.connected = true;
504
+ _this8.hasEverConnected = true;
505
+ _this8.startTokenRefreshTimer();
506
+ _this8.emitEvent('online');
835
507
  }
836
508
  return resolve();
837
509
  };
@@ -839,207 +511,180 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
839
511
  call = _backoff.default.call(function (callback) {
840
512
  var attemptNum = call.getNumRetries();
841
513
  var attemptLogPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
842
- _this1.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": executing ").concat(attemptLogPrefix, " attempt ").concat(attemptNum, " for ").concat(sessionId));
843
- _this1._attemptConnection(webSocketUrl, sessionId, callback, attemptOptions);
514
+ _this8.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": executing ").concat(attemptLogPrefix, " attempt ").concat(attemptNum));
515
+ _this8.attemptConnection(webSocketUrl, callback, attemptOptions);
844
516
  }, function (err) {
845
- return onComplete(err, sessionId);
517
+ return onComplete(err);
846
518
  });
847
519
  call.setStrategy(new _backoff.default.ExponentialStrategy({
848
- initialDelay: _this1.config.backoffTimeReset,
849
- maxDelay: _this1.config.backoffTimeMax
520
+ initialDelay: _this8.config.backoffTimeReset,
521
+ maxDelay: _this8.config.backoffTimeMax
850
522
  }));
851
523
  if (isInitialConnectWithoutRetries) {
852
524
  call.retryIf(function () {
853
525
  return false;
854
526
  });
855
- } else if (isInitialConnect && initialRetryLimit > 0) {
527
+ } else if (isInitialConnect && initialRetryLimit !== null && initialRetryLimit > 0) {
856
528
  call.failAfter(initialRetryLimit);
857
- } else if (_this1.config.maxRetries) {
858
- call.failAfter(_this1.config.maxRetries);
529
+ } else if (_this8.config.maxRetries) {
530
+ call.failAfter(_this8.config.maxRetries);
859
531
  }
860
532
 
861
- // Store the call BEFORE setting up event handlers to prevent race conditions
862
- // Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
533
+ // Store backoff call reference BEFORE starting (so it's available in attemptConnection)
863
534
  if (isShutdownSwitchover) {
864
- _this1._shutdownSwitchoverBackoffCalls.set(sessionId, call);
535
+ _this8.shutdownSwitchoverBackoffCall = call;
865
536
  } else {
866
- _this1.backoffCalls.set(sessionId, call);
537
+ _this8.backoffCall = call;
867
538
  }
868
539
  call.on('abort', function () {
869
540
  var msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
870
- _this1.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(msg, " aborted for ").concat(sessionId));
871
- reject(new Error("MobiusSocket ".concat(msg, " Aborted for ").concat(sessionId)));
541
+ _this8.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(msg, " aborted"));
542
+ reject(new Error("MobiusSocket ".concat(msg, " Aborted")));
872
543
  });
873
544
  call.on('callback', function (err) {
874
545
  if (err) {
875
546
  if (isInitialConnectWithoutRetries) {
876
- // retryIf(() => false) already disabled retries for this initial connect;
877
- // this branch only avoids logging the generic "attempting retry" message.
878
- _this1.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": initial connect failed for ").concat(sessionId, "; retries already disabled"));
547
+ _this8.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": initial connect failed; retries already disabled"));
879
548
  return;
880
549
  }
881
550
  var number = call.getNumRetries();
882
- var delay = Math.min(call.strategy_.nextBackoffDelay_, _this1.config.backoffTimeMax);
551
+ var delay = Math.min(call.strategy_.nextBackoffDelay_, _this8.config.backoffTimeMax || Infinity);
883
552
  var callbackLogPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
884
- _this1.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(callbackLogPrefix, " failed to connect; attempting retry ").concat(number + 1, " in ").concat(delay, " ms for ").concat(sessionId));
553
+ _this8.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": ").concat(callbackLogPrefix, " failed to connect; attempting retry ").concat(number + 1, " in ").concat(delay, " ms"));
885
554
  /* istanbul ignore if */
886
555
  if (process.env.NODE_ENV === 'development') {
887
- _this1.logger.debug("".concat(MOBIUS_SOCKET_NAMESPACE, ": "), err, err.stack);
556
+ _this8.logger.debug("".concat(MOBIUS_SOCKET_NAMESPACE, ": "), err, err.stack);
888
557
  }
889
558
  return;
890
559
  }
891
- _this1.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connected ").concat(sessionId));
560
+ _this8.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": connected"));
892
561
  });
893
562
  call.start();
894
563
  });
895
564
  }
565
+
566
+ /**
567
+ * Safely emits an event, catching and logging any errors from event handlers.
568
+ * @param eventName - The name of the event to emit
569
+ * @param args - Arguments to pass to event handlers
570
+ */
896
571
  }, {
897
- key: "_emit",
898
- value: function _emit(sessionId, eventName) {
899
- for (var _len5 = arguments.length, args = new Array(_len5 > 2 ? _len5 - 2 : 0), _key5 = 2; _key5 < _len5; _key5++) {
900
- args[_key5 - 2] = arguments[_key5];
572
+ key: "emitEvent",
573
+ value: function emitEvent(eventName) {
574
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
575
+ args[_key - 1] = arguments[_key];
901
576
  }
902
577
  try {
903
- if (!sessionId || !eventName) {
578
+ if (!eventName) {
904
579
  return;
905
580
  }
906
- var suffix = sessionId === this.defaultSessionId ? '' : ":".concat(sessionId);
907
- this.emit.apply(this, ["".concat(eventName).concat(suffix)].concat(args));
581
+ this.emit.apply(this, [eventName].concat(args));
908
582
  } catch (error) {
909
583
  // Safely handle errors without causing additional issues during cleanup
910
- try {
911
- this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred in event handler:"), error, ' with args: ', [sessionId, eventName].concat(args));
912
- } catch (logError) {
913
- // If even logging fails, just ignore to prevent cascading errors during cleanup
914
- // eslint-disable-next-line no-console
915
- console.error('MobiusSocket _emit error handling failed:', logError);
916
- }
917
- }
918
- }
919
- }, {
920
- key: "_getEventHandlers",
921
- value: function _getEventHandlers(eventType) {
922
- if (!eventType) {
923
- return [];
924
- }
925
- var _eventType$split = eventType.split('.'),
926
- _eventType$split2 = (0, _slicedToArray2.default)(_eventType$split, 2),
927
- namespace = _eventType$split2[0],
928
- name = _eventType$split2[1];
929
- var handlers = [];
930
- if (!this.webex[namespace] && !this.webex.internal[namespace]) {
931
- return handlers;
584
+ this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred in event handler:"), error, ' with args: ', [eventName].concat(args));
932
585
  }
933
- var handlerName = (0, _camelCase2.default)("process_".concat(name, "_event"));
934
- if ((this.webex[namespace] || this.webex.internal[namespace])[handlerName]) {
935
- handlers.push({
936
- name: handlerName,
937
- namespace: namespace
938
- });
939
- }
940
- return handlers;
941
586
  }
587
+
588
+ /**
589
+ * Starts a periodic timer to refresh the authentication token.
590
+ * Token refresh occurs every hour while connected.
591
+ */
942
592
  }, {
943
- key: "_startTokenRefreshTimer",
944
- value: function _startTokenRefreshTimer() {
945
- var _this10 = this;
946
- if (this._tokenRefreshTimer || !this.hasConnectedSockets()) {
593
+ key: "startTokenRefreshTimer",
594
+ value: function startTokenRefreshTimer() {
595
+ var _this9 = this;
596
+ if (this.tokenRefreshTimer || !this.connected) {
947
597
  return;
948
598
  }
949
- this._tokenRefreshTimer = setInterval(function () {
950
- _this10._refreshToken().catch(function (error) {
951
- _this10.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": periodic token refresh failed"), error);
599
+ this.tokenRefreshTimer = setInterval(function () {
600
+ _this9.refreshToken().catch(function (error) {
601
+ _this9.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": periodic token refresh failed"), error);
952
602
  });
953
603
  }, TOKEN_REFRESH_INTERVAL_MS);
954
604
  }
605
+
606
+ /**
607
+ * Stops the periodic token refresh timer.
608
+ */
955
609
  }, {
956
- key: "_stopTokenRefreshTimer",
957
- value: function _stopTokenRefreshTimer() {
958
- if (!this._tokenRefreshTimer) {
610
+ key: "stopTokenRefreshTimer",
611
+ value: function stopTokenRefreshTimer() {
612
+ if (!this.tokenRefreshTimer) {
959
613
  return;
960
614
  }
961
- clearInterval(this._tokenRefreshTimer);
962
- this._tokenRefreshTimer = undefined;
615
+ clearInterval(this.tokenRefreshTimer);
616
+ this.tokenRefreshTimer = undefined;
963
617
  }
618
+
619
+ /**
620
+ * Refreshes the authentication token and re-authenticates the socket connection.
621
+ * @returns Promise that resolves when token refresh and re-authentication complete
622
+ */
964
623
  }, {
965
- key: "_refreshToken",
966
- value: function _refreshToken() {
967
- var _this11 = this;
968
- if (this._tokenRefreshInFlight) {
969
- return this._tokenRefreshInFlight;
970
- }
971
- if (!this.hasConnectedSockets()) {
972
- this._stopTokenRefreshTimer();
624
+ key: "refreshToken",
625
+ value: function refreshToken() {
626
+ var _this$webex$credentia,
627
+ _this$webex$credentia2,
628
+ _this$webex$credentia3,
629
+ _this0 = this;
630
+ if (this.tokenRefreshInFlight) {
631
+ return this.tokenRefreshInFlight;
632
+ }
633
+ if (!this.connected) {
634
+ this.stopTokenRefreshTimer();
973
635
  return _promise.default.resolve();
974
636
  }
975
- var tokenPromise = this.webex.credentials.canRefresh ? this.webex.credentials.refresh({
637
+ var tokenPromise = this.webex.credentials.canRefresh ? (_this$webex$credentia = (_this$webex$credentia2 = this.webex.credentials).refresh) === null || _this$webex$credentia === void 0 ? void 0 : (_this$webex$credentia3 = _this$webex$credentia.call(_this$webex$credentia2, {
976
638
  force: true
977
- }).then(function () {
978
- return _this11.webex.credentials.getUserToken();
639
+ })) === null || _this$webex$credentia3 === void 0 ? void 0 : _this$webex$credentia3.then(function () {
640
+ return _this0.webex.credentials.getUserToken();
979
641
  }) : this.webex.credentials.getUserToken();
980
- this._tokenRefreshInFlight = tokenPromise.then(function (token) {
642
+ this.tokenRefreshInFlight = tokenPromise.then(function (token) {
643
+ var _this0$socket;
981
644
  if (!token) {
982
645
  throw new Error('Mobius token refresh did not return a token');
983
646
  }
984
647
  var refreshedToken = normalizeMobiusAuthToken(token.toString());
985
- var authPayloadPromises = [];
986
- var _iterator3 = _createForOfIteratorHelper(_this11.sockets.values()),
987
- _step3;
988
- try {
989
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
990
- var socket = _step3.value;
991
- if (socket !== null && socket !== void 0 && socket.connected) {
992
- authPayloadPromises.push(socket.refresh(refreshedToken));
993
- }
994
- }
995
- } catch (err) {
996
- _iterator3.e(err);
997
- } finally {
998
- _iterator3.f();
648
+ if (!((_this0$socket = _this0.socket) !== null && _this0$socket !== void 0 && _this0$socket.connected)) {
649
+ _this0.logger.warn("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket is not connected, skipping token refresh"));
650
+ return undefined;
999
651
  }
1000
- return _promise.default.all(authPayloadPromises);
652
+ return _this0.socket.refresh(refreshedToken);
1001
653
  }).catch(function (error) {
1002
- _this11.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": failed to refresh/re-auth Mobius sockets"), error);
654
+ _this0.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": failed to refresh/re-auth Mobius socket"), error);
1003
655
  throw error;
1004
656
  }).finally(function () {
1005
- _this11._tokenRefreshInFlight = undefined;
657
+ _this0.tokenRefreshInFlight = undefined;
1006
658
  });
1007
- return this._tokenRefreshInFlight;
659
+ return this.tokenRefreshInFlight;
1008
660
  }
1009
661
  }, {
1010
- key: "_onclose",
1011
- value: function _onclose(sessionId, event, sourceSocket) {
662
+ key: "onclose",
663
+ value: function onclose(event, sourceSocket) {
1012
664
  // I don't see any way to avoid the complexity or statement count in here.
1013
665
  /* eslint complexity: [0] */
1014
666
 
1015
667
  try {
1016
668
  var reason = event.reason && event.reason.toLowerCase();
1017
- var sessionSocket = this.sockets.get(sessionId);
1018
669
  var socketUrl;
1019
- event.sessionId = sessionId;
1020
- var isActiveSocket = sourceSocket === sessionSocket;
670
+ var isActiveSocket = sourceSocket === this.socket;
1021
671
  if (sourceSocket) {
1022
672
  socketUrl = sourceSocket.url;
1023
673
  }
1024
- this.sockets.delete(sessionId);
674
+
675
+ // Only tear down state if the currently active socket closed
1025
676
  if (isActiveSocket) {
1026
- // Only tear down state if the currently active socket closed
1027
- if (sessionSocket) {
1028
- sessionSocket.removeAllListeners();
1029
- if (sessionId === this.defaultSessionId) {
1030
- this.socket = undefined;
1031
- }
1032
- this._emit(sessionId, 'offline', event);
1033
- }
1034
- // Update overall connected status
1035
- this.connecting = this.hasConnectingSockets();
1036
- this.connected = this.hasConnectedSockets();
1037
- if (!this.hasConnectedSockets()) {
1038
- this._stopTokenRefreshTimer();
677
+ if (this.socket) {
678
+ this.socket.removeAllListeners();
679
+ this.socket = undefined;
680
+ this.emitEvent('offline', event);
1039
681
  }
682
+ this.connecting = false;
683
+ this.connected = false;
684
+ this.stopTokenRefreshTimer();
1040
685
  } else {
1041
686
  // Old socket closed; do not flip connection state
1042
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] non-active socket closed, code=").concat(event.code, " for ").concat(sessionId));
687
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] non-active socket closed, code=").concat(event.code));
1043
688
  // Clean up listeners from old socket now that it's closed
1044
689
  if (sourceSocket) {
1045
690
  sourceSocket.removeAllListeners();
@@ -1047,145 +692,111 @@ var MobiusSocket = /*#__PURE__*/function (_EventEmitter) {
1047
692
  }
1048
693
  switch (event.code) {
1049
694
  case 1003:
1050
- // metric: disconnect
1051
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": service rejected last message for ").concat(sessionId, "; will not reconnect: ").concat(event.reason));
1052
- if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
695
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": service rejected last message; will not reconnect: ").concat(event.reason));
696
+ if (isActiveSocket) this.emitEvent('offline.permanent', event);
1053
697
  break;
1054
698
  case 4000:
1055
- // metric: disconnect
1056
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket ").concat(sessionId, " replaced; will not reconnect"));
1057
- if (isActiveSocket) this._emit(sessionId, 'offline.replaced', event);
1058
- // If not active, nothing to do
699
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket replaced; will not reconnect"));
700
+ if (isActiveSocket) this.emitEvent('offline.replaced', event);
1059
701
  break;
1060
702
  case 4001:
1061
703
  // replaced during shutdown
1062
704
  if (isActiveSocket) {
1063
705
  // Server closed active socket with 4001, meaning it expected this connection
1064
- // to be replaced, but the switchover in _handleImminentShutdown failed.
1065
- // This is a permanent failure - do not reconnect.
1066
- this.logger.warn("".concat(MOBIUS_SOCKET_NAMESPACE, ": active socket closed with 4001; shutdown switchover failed for ").concat(sessionId));
1067
- this._emit(sessionId, 'offline.permanent', event);
706
+ // to be replaced, but the switchover in handleImminentShutdown failed.
707
+ this.logger.warn("".concat(MOBIUS_SOCKET_NAMESPACE, ": active socket closed with 4001; shutdown switchover failed"));
708
+ this.emitEvent('offline.permanent', event);
1068
709
  } else {
1069
710
  // Expected: old socket closed after successful switchover
1070
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": old socket closed with 4001 (replaced during shutdown); no reconnect needed for ").concat(sessionId));
1071
- this._emit(sessionId, 'offline.replaced', event);
711
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": old socket closed with 4001 (replaced during shutdown); no reconnect needed"));
712
+ this.emitEvent('offline.replaced', event);
1072
713
  }
1073
714
  break;
1074
715
  case 1001:
1075
716
  case 1005:
1076
717
  case 1006:
1077
718
  case 1011:
1078
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket ").concat(sessionId, " disconnected; reconnecting"));
719
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket disconnected; reconnecting"));
1079
720
  if (isActiveSocket) {
1080
- this._emit(sessionId, 'offline.transient', event);
1081
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] reconnecting active socket to recover for ").concat(sessionId));
1082
- this._reconnect(socketUrl, sessionId);
721
+ this.emitEvent('offline.transient', event);
722
+ this.reconnect(socketUrl);
1083
723
  }
1084
- // metric: disconnect
1085
- // if (code == 1011 && reason !== ping error) metric: unexpected disconnect
1086
724
  break;
1087
725
  case 1000:
1088
726
  case 3050:
1089
- // 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
1090
- if (normalReconnectReasons.includes(reason)) {
1091
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket ").concat(sessionId, " disconnected; reconnecting"));
727
+ if (reason && normalReconnectReasons.includes(reason)) {
728
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket disconnected; reconnecting"));
1092
729
  if (isActiveSocket) {
1093
- this._emit(sessionId, 'offline.transient', event);
1094
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] reconnecting due to normal close for ").concat(sessionId));
1095
- this._reconnect(socketUrl, sessionId);
730
+ this.emitEvent('offline.transient', event);
731
+ this.reconnect(socketUrl);
1096
732
  }
1097
- // metric: disconnect
1098
- // if (reason === done forced) metric: force closure
1099
733
  } else {
1100
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket ").concat(sessionId, " disconnected; will not reconnect: ").concat(event.reason));
1101
- if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
734
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket disconnected; will not reconnect: ").concat(event.reason));
735
+ if (isActiveSocket) this.emitEvent('offline.permanent', event);
1102
736
  }
1103
737
  break;
1104
738
  default:
1105
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket ").concat(sessionId, " disconnected unexpectedly; will not reconnect"));
1106
- // unexpected disconnect
1107
- if (isActiveSocket) this._emit(sessionId, 'offline.permanent', event);
739
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": socket disconnected unexpectedly; will not reconnect"));
740
+ if (isActiveSocket) this.emitEvent('offline.permanent', event);
1108
741
  }
1109
742
  } catch (error) {
1110
- this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred in close handler for ").concat(sessionId), error);
743
+ this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred in close handler"), error);
1111
744
  }
1112
745
  }
1113
746
  }, {
1114
- key: "_onmessage",
1115
- value: function _onmessage(sessionId, event) {
1116
- var _this12 = this;
1117
- this._setTimeOffset(sessionId, event);
747
+ key: "onmessage",
748
+ value: function onmessage(event) {
1118
749
  var envelope = event.data;
1119
- if (process.env.ENABLE_MERCURY_LOGGING) {
1120
- this.logger.debug("".concat(MOBIUS_SOCKET_NAMESPACE, ": message envelope from ").concat(sessionId, ": "), envelope);
750
+ if (process.env.ENABLE_MOBIUS_LOGGING) {
751
+ this.logger.debug("".concat(MOBIUS_SOCKET_NAMESPACE, ": message envelope: "), envelope);
1121
752
  }
1122
- envelope.sessionId = sessionId;
1123
753
 
1124
754
  // Handle shutdown message shape: { type: 'shutdown' }
1125
755
  if (envelope && envelope.type === 'shutdown') {
1126
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] imminent shutdown message received for ").concat(sessionId));
1127
- this._emit(sessionId, 'event:mercury_shutdown_imminent', envelope);
1128
- this._handleImminentShutdown(sessionId);
756
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": [shutdown] imminent shutdown message received"));
757
+ this.emitEvent('event:mobius_shutdown_imminent', envelope); // This is not yet not implemented, keeping for future support
758
+
759
+ this.handleImminentShutdown();
1129
760
  return _promise.default.resolve();
1130
761
  }
1131
- if (this._trackAsyncEventAndShouldSuppressDuplicate(sessionId, envelope)) {
762
+ if (this.trackAsyncEventAndShouldSuppressDuplicate(envelope)) {
1132
763
  return _promise.default.resolve();
1133
764
  }
1134
765
 
1135
- // Mobius: emit event:<type> for typed messages (e.g., register.response)
766
+ // Emit event:<type> for typed messages (e.g., register.response)
1136
767
  if (envelope.type) {
1137
- this._emit(sessionId, "event:".concat(envelope.type), envelope);
768
+ this.emitEvent("event:".concat(envelope.type), envelope);
1138
769
  }
1139
- envelope.sessionId = sessionId;
770
+
1140
771
  // Use data/payload if present, otherwise treat the envelope itself as the data (flat format)
1141
772
  var data = envelope.data || envelope;
1142
- this._applyOverrides(data);
1143
773
 
1144
- // Support both Mercury-enveloped (data.eventType) and flat (eventType) formats
774
+ // Support both Mobius-enveloped (data.eventType) and flat (eventType) formats
1145
775
  var eventType = (data === null || data === void 0 ? void 0 : data.eventType) || envelope.eventType;
1146
776
  if (!eventType) {
1147
- this._emit(sessionId, 'event', envelope);
777
+ this.emitEvent('event', envelope);
1148
778
  return _promise.default.resolve();
1149
779
  }
1150
- return this._getEventHandlers(eventType).reduce(function (promise, handler) {
1151
- return promise.then(function () {
1152
- var namespace = handler.namespace,
1153
- name = handler.name;
1154
- return new _promise.default(function (resolve) {
1155
- resolve((_this12.webex[namespace] || _this12.webex.internal[namespace])[name](data));
1156
- }).catch(function (reason) {
1157
- return _this12.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred in autowired event handler for ").concat(eventType, " from ").concat(sessionId), reason);
1158
- });
1159
- });
1160
- }, _promise.default.resolve()).then(function () {
1161
- _this12._emit(sessionId, 'event', envelope);
1162
- var _eventType$split3 = eventType.split('.'),
1163
- _eventType$split4 = (0, _slicedToArray2.default)(_eventType$split3, 1),
1164
- namespace = _eventType$split4[0];
1165
- if (namespace === eventType) {
1166
- _this12._emit(sessionId, "event:".concat(namespace), envelope);
1167
- } else {
1168
- _this12._emit(sessionId, "event:".concat(namespace), envelope);
1169
- _this12._emit(sessionId, "event:".concat(eventType), envelope);
780
+ try {
781
+ // TODO: Remove if event:namespace is not required
782
+ this.emitEvent('event', envelope);
783
+ var _eventType$split = eventType.split('.'),
784
+ _eventType$split2 = (0, _slicedToArray2.default)(_eventType$split, 1),
785
+ namespace = _eventType$split2[0];
786
+ this.emitEvent("event:".concat(namespace), envelope);
787
+ if (namespace !== eventType) {
788
+ this.emitEvent("event:".concat(eventType), envelope);
1170
789
  }
1171
- }).catch(function (reason) {
1172
- _this12.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred processing socket message from ").concat(sessionId), reason);
1173
- });
1174
- }
1175
- }, {
1176
- key: "_setTimeOffset",
1177
- value: function _setTimeOffset(sessionId, event) {
1178
- var wsWriteTimestamp = event.data.wsWriteTimestamp;
1179
- if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) {
1180
- this.mercuryTimeOffset = (0, _now.default)() - wsWriteTimestamp;
790
+ } catch (reason) {
791
+ this.logger.error("".concat(MOBIUS_SOCKET_NAMESPACE, ": error occurred processing socket message"), reason);
1181
792
  }
793
+ return _promise.default.resolve();
1182
794
  }
1183
795
  }, {
1184
- key: "_reconnect",
1185
- value: function _reconnect(webSocketUrl) {
1186
- var sessionId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSessionId;
1187
- this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": reconnecting ").concat(sessionId));
1188
- return this.connect(webSocketUrl || this.socketUrl, sessionId);
796
+ key: "reconnect",
797
+ value: function reconnect(webSocketUrl) {
798
+ this.logger.info("".concat(MOBIUS_SOCKET_NAMESPACE, ": reconnecting"));
799
+ return this.connect(webSocketUrl || this.socketUrl);
1189
800
  }
1190
801
  }]);
1191
802
  }(_events.EventEmitter);