@webex/plugin-meetings 3.10.0-next.9 → 3.10.0-webex-services-ready.2

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 (73) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.js +11 -3
  4. package/dist/constants.js.map +1 -1
  5. package/dist/hashTree/constants.js +20 -0
  6. package/dist/hashTree/constants.js.map +1 -0
  7. package/dist/hashTree/hashTree.js +515 -0
  8. package/dist/hashTree/hashTree.js.map +1 -0
  9. package/dist/hashTree/hashTreeParser.js +1266 -0
  10. package/dist/hashTree/hashTreeParser.js.map +1 -0
  11. package/dist/hashTree/types.js +22 -0
  12. package/dist/hashTree/types.js.map +1 -0
  13. package/dist/hashTree/utils.js +48 -0
  14. package/dist/hashTree/utils.js.map +1 -0
  15. package/dist/interpretation/index.js +1 -1
  16. package/dist/interpretation/siLanguage.js +1 -1
  17. package/dist/locus-info/index.js +529 -75
  18. package/dist/locus-info/index.js.map +1 -1
  19. package/dist/locus-info/types.js +7 -0
  20. package/dist/locus-info/types.js.map +1 -0
  21. package/dist/meeting/index.js +63 -22
  22. package/dist/meeting/index.js.map +1 -1
  23. package/dist/meeting/util.js +1 -0
  24. package/dist/meeting/util.js.map +1 -1
  25. package/dist/meetings/index.js +112 -70
  26. package/dist/meetings/index.js.map +1 -1
  27. package/dist/metrics/constants.js +3 -1
  28. package/dist/metrics/constants.js.map +1 -1
  29. package/dist/reachability/clusterReachability.js +44 -358
  30. package/dist/reachability/clusterReachability.js.map +1 -1
  31. package/dist/reachability/reachability.types.js +14 -1
  32. package/dist/reachability/reachability.types.js.map +1 -1
  33. package/dist/reachability/reachabilityPeerConnection.js +445 -0
  34. package/dist/reachability/reachabilityPeerConnection.js.map +1 -0
  35. package/dist/types/constants.d.ts +26 -21
  36. package/dist/types/hashTree/constants.d.ts +8 -0
  37. package/dist/types/hashTree/hashTree.d.ts +129 -0
  38. package/dist/types/hashTree/hashTreeParser.d.ts +260 -0
  39. package/dist/types/hashTree/types.d.ts +27 -0
  40. package/dist/types/hashTree/utils.d.ts +9 -0
  41. package/dist/types/locus-info/index.d.ts +95 -56
  42. package/dist/types/locus-info/types.d.ts +54 -0
  43. package/dist/types/meeting/index.d.ts +22 -9
  44. package/dist/types/meetings/index.d.ts +9 -2
  45. package/dist/types/metrics/constants.d.ts +2 -0
  46. package/dist/types/reachability/clusterReachability.d.ts +10 -88
  47. package/dist/types/reachability/reachability.types.d.ts +12 -1
  48. package/dist/types/reachability/reachabilityPeerConnection.d.ts +111 -0
  49. package/dist/webinar/index.js +1 -1
  50. package/package.json +22 -21
  51. package/src/constants.ts +13 -1
  52. package/src/hashTree/constants.ts +9 -0
  53. package/src/hashTree/hashTree.ts +463 -0
  54. package/src/hashTree/hashTreeParser.ts +1161 -0
  55. package/src/hashTree/types.ts +32 -0
  56. package/src/hashTree/utils.ts +42 -0
  57. package/src/locus-info/index.ts +571 -106
  58. package/src/locus-info/types.ts +53 -0
  59. package/src/meeting/index.ts +78 -27
  60. package/src/meeting/util.ts +1 -0
  61. package/src/meetings/index.ts +104 -51
  62. package/src/metrics/constants.ts +2 -0
  63. package/src/reachability/clusterReachability.ts +50 -347
  64. package/src/reachability/reachability.types.ts +15 -1
  65. package/src/reachability/reachabilityPeerConnection.ts +416 -0
  66. package/test/unit/spec/hashTree/hashTree.ts +655 -0
  67. package/test/unit/spec/hashTree/hashTreeParser.ts +1532 -0
  68. package/test/unit/spec/hashTree/utils.ts +103 -0
  69. package/test/unit/spec/locus-info/index.js +722 -4
  70. package/test/unit/spec/meeting/index.js +120 -20
  71. package/test/unit/spec/meeting/utils.js +77 -0
  72. package/test/unit/spec/meetings/index.js +71 -26
  73. package/test/unit/spec/reachability/clusterReachability.ts +281 -138
@@ -1,17 +1,30 @@
1
1
  "use strict";
2
2
 
3
+ var _typeof = require("@babel/runtime-corejs2/helpers/typeof");
3
4
  var _Reflect$construct = require("@babel/runtime-corejs2/core-js/reflect/construct");
5
+ var _Object$keys = require("@babel/runtime-corejs2/core-js/object/keys");
6
+ var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
7
+ var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
8
+ var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
9
+ var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
10
+ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
4
11
  var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");
5
12
  var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");
6
13
  var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");
7
14
  var _Array$isArray2 = require("@babel/runtime-corejs2/core-js/array/is-array");
8
- var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
15
+ var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");
9
16
  var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
10
17
  _Object$defineProperty(exports, "__esModule", {
11
18
  value: true
12
19
  });
13
20
  exports.default = void 0;
21
+ var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
22
+ var _map = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/map"));
23
+ var _values = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/values"));
24
+ var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));
25
+ var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
14
26
  var _isArray = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/is-array"));
27
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
15
28
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
16
29
  var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
17
30
  var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/possibleConstructorReturn"));
@@ -32,11 +45,25 @@ var _mediaSharesUtils = _interopRequireDefault(require("./mediaSharesUtils"));
32
45
  var _parser = _interopRequireDefault(require("./parser"));
33
46
  var _metrics = _interopRequireDefault(require("../metrics"));
34
47
  var _constants2 = _interopRequireDefault(require("../metrics/constants"));
48
+ var _hashTreeParser = _interopRequireWildcard(require("../hashTree/hashTreeParser"));
49
+ var _types = require("../hashTree/types");
50
+ function _interopRequireWildcard(e, t) { if ("function" == typeof _WeakMap) var r = new _WeakMap(), n = new _WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t2 in e) "default" !== _t2 && {}.hasOwnProperty.call(e, _t2) && ((i = (o = _Object$defineProperty) && _Object$getOwnPropertyDescriptor(e, _t2)) && (i.get || i.set) ? o(f, _t2, i) : f[_t2] = e[_t2]); return f; })(e, t); }
35
51
  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; } } }; }
36
52
  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; } }
37
53
  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; }
54
+ 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; }
55
+ 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; }
38
56
  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)); }
39
57
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
58
+ // list of top level keys in Locus DTO relevant for Hash Tree DTOs processing
59
+ // it does not contain fields specific to classic Locus DTOs like sequence or baseSequence
60
+ var LocusDtoTopLevelKeys = ['controls', 'fullState', 'host', 'info', 'links', 'mediaShares', 'meetings', 'participants', 'replaces', 'self', 'sequence', 'syncUrl', 'url', 'htMeta' // only exists when hash trees are used
61
+ ];
62
+ var LocusObjectStateAfterUpdates = {
63
+ unchanged: 'unchanged',
64
+ removed: 'removed',
65
+ updated: 'updated'
66
+ };
40
67
  /**
41
68
  * @description LocusInfo extends ChildEmitter to convert locusInfo info a private emitter to parent object
42
69
  * @export
@@ -82,10 +109,13 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
82
109
  (0, _defineProperty2.default)(_this, "mediaShares", void 0);
83
110
  (0, _defineProperty2.default)(_this, "replace", void 0);
84
111
  (0, _defineProperty2.default)(_this, "url", void 0);
85
- (0, _defineProperty2.default)(_this, "services", void 0);
86
- (0, _defineProperty2.default)(_this, "resources", void 0);
112
+ (0, _defineProperty2.default)(_this, "links", void 0);
87
113
  (0, _defineProperty2.default)(_this, "mainSessionLocusCache", void 0);
88
114
  (0, _defineProperty2.default)(_this, "self", void 0);
115
+ (0, _defineProperty2.default)(_this, "hashTreeParser", void 0);
116
+ (0, _defineProperty2.default)(_this, "hashTreeObjectId2ParticipantId", void 0);
117
+ // mapping of hash tree object ids to participant ids
118
+ (0, _defineProperty2.default)(_this, "classicVsHashTreeMismatchMetricCounter", 0);
89
119
  _this.parsedLocus = {
90
120
  states: []
91
121
  };
@@ -95,11 +125,13 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
95
125
  _this.meetingId = meetingId;
96
126
  _this.updateMeeting = updateMeeting;
97
127
  _this.locusParser = new _parser.default();
128
+ _this.hashTreeObjectId2ParticipantId = new _map.default();
98
129
  return _this;
99
130
  }
100
131
 
101
132
  /**
102
133
  * Does a Locus sync. It tries to get the latest delta DTO or if it can't, it falls back to getting the full Locus DTO.
134
+ * WARNING: This function must not be used for hash tree based Locus meetings.
103
135
  *
104
136
  * @param {Meeting} meeting
105
137
  * @param {boolean} isLocusUrlChanged
@@ -266,7 +298,6 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
266
298
  }, {
267
299
  key: "init",
268
300
  value: function init() {
269
- var _locus$links, _locus$links2;
270
301
  var locus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
271
302
  this.created = locus.created || null;
272
303
  this.scheduledMeeting = locus.meeting || null;
@@ -302,35 +333,385 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
302
333
  this.updateSelf(locus.self);
303
334
  this.updateHostInfo(locus.host);
304
335
  this.updateMediaShares(locus.mediaShares);
305
- this.updateServices((_locus$links = locus.links) === null || _locus$links === void 0 ? void 0 : _locus$links.services);
306
- this.updateResources((_locus$links2 = locus.links) === null || _locus$links2 === void 0 ? void 0 : _locus$links2.resources);
336
+ this.updateLinks(locus.links);
307
337
  }
308
338
 
309
339
  /**
310
- * @param {Object} locus
340
+ * Creates the HashTreeParser instance.
341
+ * @param {Object} initial locus data
342
+ * @returns {void}
343
+ */
344
+ }, {
345
+ key: "createHashTreeParser",
346
+ value: function createHashTreeParser(_ref) {
347
+ var initialLocus = _ref.initialLocus;
348
+ return new _hashTreeParser.default({
349
+ initialLocus: initialLocus,
350
+ webexRequest: this.webex.request.bind(this.webex),
351
+ locusInfoUpdateCallback: this.updateFromHashTree.bind(this),
352
+ debugId: "HT-".concat(this.meetingId.substring(0, 4))
353
+ });
354
+ }
355
+
356
+ /**
357
+ * @param {Object} data - data to initialize locus info with. It may be from a join or GET /loci response or from a Mercury event that triggers a creation of meeting object
311
358
  * @returns {undefined}
312
359
  * @memberof LocusInfo
313
360
  */
314
361
  }, {
315
362
  key: "initialSetup",
316
- value: function initialSetup(locus) {
317
- this.updateLocusCache(locus);
318
- this.onFullLocus(locus);
363
+ value: (function () {
364
+ var _initialSetup = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee(data) {
365
+ var _data$locus, _data$locus$links, _data$locus$links$res, _data$locus$links$res2;
366
+ var _data$hashTreeMessage, _selfObject$data, selfObject, _data$locus2, _data$locus2$self, _t;
367
+ return _regenerator.default.wrap(function (_context) {
368
+ while (1) switch (_context.prev = _context.next) {
369
+ case 0:
370
+ _t = data.trigger;
371
+ _context.next = _t === 'locus-message' ? 1 : _t === 'join-response' ? 6 : _t === 'get-loci-response' ? 7 : 10;
372
+ break;
373
+ case 1:
374
+ if (!data.hashTreeMessage) {
375
+ _context.next = 4;
376
+ break;
377
+ }
378
+ // we need the SELF object to be in the received message, because it contains visibleDataSets
379
+ // and these are needed to initialize all the hash trees
380
+ selfObject = (_data$hashTreeMessage = data.hashTreeMessage.locusStateElements) === null || _data$hashTreeMessage === void 0 ? void 0 : _data$hashTreeMessage.find(function (el) {
381
+ return (0, _hashTreeParser.isSelf)(el);
382
+ });
383
+ if (selfObject !== null && selfObject !== void 0 && (_selfObject$data = selfObject.data) !== null && _selfObject$data !== void 0 && _selfObject$data.visibleDataSets) {
384
+ _context.next = 2;
385
+ break;
386
+ }
387
+ _loggerProxy.default.logger.warn("Locus-info:index#initialSetup --> cannot initialize HashTreeParser, SELF object with visibleDataSets is missing in the message");
388
+ throw new Error('SELF object with visibleDataSets is missing in the message');
389
+ case 2:
390
+ _loggerProxy.default.logger.info('Locus-info:index#initialSetup --> creating HashTreeParser from message');
391
+ // first create the HashTreeParser, but don't initialize it with any data yet
392
+ // pass just a fake locus that contains only the visibleDataSets
393
+ this.hashTreeParser = this.createHashTreeParser({
394
+ initialLocus: {
395
+ locus: {
396
+ self: {
397
+ visibleDataSets: selfObject.data.visibleDataSets
398
+ }
399
+ },
400
+ dataSets: [] // empty, because they will be populated in initializeFromMessage() call // dataSets: data.hashTreeMessage.dataSets,
401
+ }
402
+ });
319
403
 
320
- // Change it to true after it receives it first locus object
321
- this.emitChange = true;
322
- }
404
+ // now handle the message - that should populate all the visible datasets
405
+ _context.next = 3;
406
+ return this.hashTreeParser.initializeFromMessage(data.hashTreeMessage);
407
+ case 3:
408
+ _context.next = 5;
409
+ break;
410
+ case 4:
411
+ // "classic" Locus case, no hash trees involved
412
+ this.updateLocusCache(data.locus);
413
+ this.onFullLocus(data.locus, undefined);
414
+ case 5:
415
+ return _context.abrupt("continue", 10);
416
+ case 6:
417
+ this.updateLocusCache(data.locus);
418
+ this.onFullLocus(data.locus, undefined, data.dataSets);
419
+ return _context.abrupt("continue", 10);
420
+ case 7:
421
+ if (!((_data$locus = data.locus) !== null && _data$locus !== void 0 && (_data$locus$links = _data$locus.links) !== null && _data$locus$links !== void 0 && (_data$locus$links$res = _data$locus$links.resources) !== null && _data$locus$links$res !== void 0 && (_data$locus$links$res2 = _data$locus$links$res.visibleDataSets) !== null && _data$locus$links$res2 !== void 0 && _data$locus$links$res2.url)) {
422
+ _context.next = 9;
423
+ break;
424
+ }
425
+ _loggerProxy.default.logger.info('Locus-info:index#initialSetup --> creating HashTreeParser from get-loci-response');
426
+ // first create the HashTreeParser, but don't initialize it with any data yet
427
+ // pass just a fake locus that contains only the visibleDataSets
428
+ this.hashTreeParser = this.createHashTreeParser({
429
+ initialLocus: {
430
+ locus: {
431
+ self: {
432
+ visibleDataSets: (_data$locus2 = data.locus) === null || _data$locus2 === void 0 ? void 0 : (_data$locus2$self = _data$locus2.self) === null || _data$locus2$self === void 0 ? void 0 : _data$locus2$self.visibleDataSets
433
+ }
434
+ },
435
+ dataSets: [] // empty, because we don't have them yet
436
+ }
437
+ });
323
438
 
439
+ // now initialize all the data
440
+ _context.next = 8;
441
+ return this.hashTreeParser.initializeFromGetLociResponse(data.locus);
442
+ case 8:
443
+ _context.next = 10;
444
+ break;
445
+ case 9:
446
+ // "classic" Locus case, no hash trees involved
447
+ this.updateLocusCache(data.locus);
448
+ this.onFullLocus(data.locus, undefined);
449
+ case 10:
450
+ // Change it to true after it receives it first locus object
451
+ this.emitChange = true;
452
+ case 11:
453
+ case "end":
454
+ return _context.stop();
455
+ }
456
+ }, _callee, this);
457
+ }));
458
+ function initialSetup(_x) {
459
+ return _initialSetup.apply(this, arguments);
460
+ }
461
+ return initialSetup;
462
+ }()
324
463
  /**
325
464
  * Handles HTTP response from Locus API call.
326
465
  * @param {Meeting} meeting meeting object
327
466
  * @param {LocusApiResponseBody} responseBody body of the http response from Locus API call
328
467
  * @returns {void}
329
468
  */
469
+ )
330
470
  }, {
331
471
  key: "handleLocusAPIResponse",
332
472
  value: function handleLocusAPIResponse(meeting, responseBody) {
333
- this.handleLocusDelta(responseBody.locus, meeting);
473
+ if (this.hashTreeParser) {
474
+ if (!responseBody.dataSets) {
475
+ this.sendClassicVsHashTreeMismatchMetric(meeting, "expected hash tree dataSets in API response but they are missing");
476
+ // continuing as we can still manage without responseBody.dataSets, but this is very suspicious
477
+ }
478
+ _loggerProxy.default.logger.info('Locus-info:index#handleLocusAPIResponse --> passing Locus API response to HashTreeParser: ', responseBody);
479
+ // update the data in our hash trees
480
+ this.hashTreeParser.handleLocusUpdate(responseBody);
481
+ } else {
482
+ if (responseBody.dataSets) {
483
+ this.sendClassicVsHashTreeMismatchMetric(meeting, "unexpected hash tree dataSets in API response");
484
+ }
485
+ // classic Locus delta
486
+ this.handleLocusDelta(responseBody.locus, meeting);
487
+ }
488
+ }
489
+
490
+ /**
491
+ *
492
+ * @param {HashTreeObject} object data set object
493
+ * @param {any} locus
494
+ * @returns {void}
495
+ */
496
+ }, {
497
+ key: "updateLocusFromHashTreeObject",
498
+ value: function updateLocusFromHashTreeObject(object, locus) {
499
+ var type = object.htMeta.elementId.type.toLowerCase();
500
+ switch (type) {
501
+ case _types.ObjectType.locus:
502
+ {
503
+ if (!object.data) {
504
+ // not doing anything here, as we need Locus to always be there (at least some fields)
505
+ // and that's already taken care of in updateFromHashTree()
506
+ _loggerProxy.default.logger.info("Locus-info:index#updateLocusFromHashTreeObject --> LOCUS object removed, version=".concat(object.htMeta.elementId.version));
507
+ return locus;
508
+ }
509
+ // replace the main locus
510
+
511
+ // The Locus object we receive from backend has empty participants array,
512
+ // and may have (although it shouldn't) other fields that are managed by other ObjectTypes
513
+ // like "fullState" or "info", so we're making sure to delete them here
514
+ var locusObjectFromData = object.data;
515
+ (0, _values.default)(_types.ObjectTypeToLocusKeyMap).forEach(function (locusDtoKey) {
516
+ delete locusObjectFromData[locusDtoKey];
517
+ });
518
+ locus = _objectSpread(_objectSpread({}, locus), locusObjectFromData);
519
+ _loggerProxy.default.logger.info("Locus-info:index#updateLocusFromHashTreeObject --> LOCUS object updated to version=".concat(object.htMeta.elementId.version));
520
+ break;
521
+ }
522
+ case _types.ObjectType.mediaShare:
523
+ if (object.data) {
524
+ var _object$data$floor, _object$data$floor2, _object$data$floor2$b, _locus$mediaShares;
525
+ _loggerProxy.default.logger.info("Locus-info:index#updateLocusFromHashTreeObject --> mediaShare id=".concat(object.htMeta.elementId.id, " name='").concat(object.data.name, "' updated ").concat(object.data.name === 'content' ? "floor=".concat((_object$data$floor = object.data.floor) === null || _object$data$floor === void 0 ? void 0 : _object$data$floor.disposition, ", ").concat((_object$data$floor2 = object.data.floor) === null || _object$data$floor2 === void 0 ? void 0 : (_object$data$floor2$b = _object$data$floor2.beneficiary) === null || _object$data$floor2$b === void 0 ? void 0 : _object$data$floor2$b.id) : '', " version=").concat(object.htMeta.elementId.version));
526
+ var existingMediaShare = (_locus$mediaShares = locus.mediaShares) === null || _locus$mediaShares === void 0 ? void 0 : _locus$mediaShares.find(function (ms) {
527
+ return ms.htMeta.elementId.id === object.htMeta.elementId.id;
528
+ });
529
+ if (existingMediaShare) {
530
+ (0, _assign.default)(existingMediaShare, object.data);
531
+ } else {
532
+ locus.mediaShares = locus.mediaShares || [];
533
+ locus.mediaShares.push(object.data);
534
+ }
535
+ } else {
536
+ var _locus$mediaShares2;
537
+ _loggerProxy.default.logger.info("Locus-info:index#updateLocusFromHashTreeObject --> mediaShare id=".concat(object.htMeta.elementId.id, " removed, version=").concat(object.htMeta.elementId.version));
538
+ locus.mediaShares = (_locus$mediaShares2 = locus.mediaShares) === null || _locus$mediaShares2 === void 0 ? void 0 : _locus$mediaShares2.filter(function (ms) {
539
+ return ms.htMeta.elementId.id !== object.htMeta.elementId.id;
540
+ });
541
+ }
542
+ break;
543
+ case _types.ObjectType.participant:
544
+ _loggerProxy.default.logger.info("Locus-info:index#updateLocusFromHashTreeObject --> participant id=".concat(object.htMeta.elementId.id, " ").concat(object.data ? 'updated' : 'removed', " version=").concat(object.htMeta.elementId.version));
545
+ if (object.data) {
546
+ if (!locus.participants) {
547
+ locus.participants = [];
548
+ }
549
+ var participantObject = object.data;
550
+ participantObject.htMeta = object.htMeta;
551
+ locus.participants.push(participantObject);
552
+ this.hashTreeObjectId2ParticipantId.set(object.htMeta.elementId.id, participantObject.id);
553
+ } else {
554
+ var participantId = this.hashTreeObjectId2ParticipantId.get(object.htMeta.elementId.id);
555
+ if (!locus.jsSdkMeta) {
556
+ locus.jsSdkMeta = {
557
+ removedParticipantIds: []
558
+ };
559
+ }
560
+ locus.jsSdkMeta.removedParticipantIds.push(participantId);
561
+ this.hashTreeObjectId2ParticipantId.delete(object.htMeta.elementId.id);
562
+ }
563
+ break;
564
+ case _types.ObjectType.links:
565
+ case _types.ObjectType.info:
566
+ case _types.ObjectType.fullState:
567
+ case _types.ObjectType.self:
568
+ if (!object.data) {
569
+ // self without data is handled inside HashTreeParser and results in LocusInfoUpdateType.MEETING_ENDED, so we should never get here
570
+ // all other types info, fullstate, etc - Locus should never send them without data
571
+ _loggerProxy.default.logger.warn("Locus-info:index#updateLocusFromHashTreeObject --> received ".concat(type, " object without data, this is not expected! version=").concat(object.htMeta.elementId.version));
572
+ } else {
573
+ _loggerProxy.default.logger.info("Locus-info:index#updateLocusFromHashTreeObject --> ".concat(type, " object updated to version ").concat(object.htMeta.elementId.version));
574
+ var locusDtoKey = _types.ObjectTypeToLocusKeyMap[type];
575
+ locus[locusDtoKey] = object.data;
576
+ }
577
+ break;
578
+ default:
579
+ _loggerProxy.default.logger.warn("Locus-info:index#updateLocusFromHashTreeObject --> received unsupported object type ".concat(type));
580
+ break;
581
+ }
582
+ return locus;
583
+ }
584
+
585
+ /**
586
+ * Sends a metric when we receive something from Locus that uses hash trees while we
587
+ * expect classic deltas or the other way around.
588
+ * @param {Meeting} meeting
589
+ * @param {string} message
590
+ * @returns {void}
591
+ */
592
+ }, {
593
+ key: "sendClassicVsHashTreeMismatchMetric",
594
+ value: function sendClassicVsHashTreeMismatchMetric(meeting, message) {
595
+ _loggerProxy.default.logger.warn("Locus-info:index#sendClassicVsHashTreeMismatchMetric --> classic vs hash tree mismatch! ".concat(message));
596
+
597
+ // we don't want to flood the metrics system
598
+ if (this.classicVsHashTreeMismatchMetricCounter < 5) {
599
+ _metrics.default.sendBehavioralMetric(_constants2.default.LOCUS_CLASSIC_VS_HASH_TREE_MISMATCH, {
600
+ correlationId: meeting.correlationId,
601
+ message: message
602
+ });
603
+ this.classicVsHashTreeMismatchMetricCounter += 1;
604
+ }
605
+ }
606
+
607
+ /**
608
+ * Handles a hash tree message received from Locus.
609
+ *
610
+ * @param {Meeting} meeting - The meeting object
611
+ * @param {eventType} eventType - The event type
612
+ * @param {HashTreeMessage} message incoming hash tree message
613
+ * @returns {void}
614
+ */
615
+ }, {
616
+ key: "handleHashTreeMessage",
617
+ value: function handleHashTreeMessage(meeting, eventType, message) {
618
+ if (eventType !== _constants.LOCUSEVENT.HASH_TREE_DATA_UPDATED) {
619
+ this.sendClassicVsHashTreeMismatchMetric(meeting, "got ".concat(eventType, ", expected ").concat(_constants.LOCUSEVENT.HASH_TREE_DATA_UPDATED));
620
+ return;
621
+ }
622
+ this.hashTreeParser.handleMessage(message);
623
+ }
624
+
625
+ /**
626
+ * Callback registered with HashTreeParser to receive locus info updates.
627
+ * Updates our locus info based on the data parsed by the hash tree parser.
628
+ *
629
+ * @param {LocusInfoUpdateType} updateType - The type of update received.
630
+ * @param {Object} [data] - Additional data for the update, if applicable.
631
+ * @returns {void}
632
+ */
633
+ }, {
634
+ key: "updateFromHashTree",
635
+ value: function updateFromHashTree(updateType, data) {
636
+ var _this4 = this;
637
+ switch (updateType) {
638
+ case _hashTreeParser.LocusInfoUpdateType.OBJECTS_UPDATED:
639
+ {
640
+ // initialize our new locus
641
+ var locus = {
642
+ participants: [],
643
+ jsSdkMeta: {
644
+ removedParticipantIds: []
645
+ }
646
+ };
647
+
648
+ // first go over all the updates and check what happens with the main locus object
649
+ var locusObjectStateAfterUpdates = LocusObjectStateAfterUpdates.unchanged;
650
+ data.updatedObjects.forEach(function (object) {
651
+ if (object.htMeta.elementId.type.toLowerCase() === _types.ObjectType.locus) {
652
+ if (locusObjectStateAfterUpdates === LocusObjectStateAfterUpdates.updated) {
653
+ var _object$data;
654
+ // this code doesn't supported it right now,
655
+ // cases for "updated" followed by "removed", or multiple "updated" would need more handling
656
+ // but these should never happen
657
+ _loggerProxy.default.logger.warn("Locus-info:index#updateFromHashTree --> received multiple LOCUS objects in one update, this is unexpected!");
658
+ _metrics.default.sendBehavioralMetric(_constants2.default.LOCUS_HASH_TREE_UNSUPPORTED_OPERATION, {
659
+ locusUrl: ((_object$data = object.data) === null || _object$data === void 0 ? void 0 : _object$data.url) || _this4.url,
660
+ message: object.data ? 'multiple LOCUS object updates' : 'LOCUS object update followed by removal'
661
+ });
662
+ }
663
+ if (object.data) {
664
+ locusObjectStateAfterUpdates = LocusObjectStateAfterUpdates.updated;
665
+ } else {
666
+ locusObjectStateAfterUpdates = LocusObjectStateAfterUpdates.removed;
667
+ }
668
+ }
669
+ });
670
+
671
+ // if Locus object is unchanged or removed, we need to keep using the existing locus
672
+ // because the rest of the locusInfo code expects locus to always be present (with at least some of the fields)
673
+ // if it gets updated, we only need to have the fields that are not part of "locus" object (like "info" or "mediaShares")
674
+ // so that when Locus object gets updated, if the new one is missing some field, that field will
675
+ // be removed from our locusInfo
676
+ if (locusObjectStateAfterUpdates === LocusObjectStateAfterUpdates.unchanged || locusObjectStateAfterUpdates === LocusObjectStateAfterUpdates.removed) {
677
+ // copy over all of existing locus except participants
678
+ LocusDtoTopLevelKeys.forEach(function (key) {
679
+ if (key !== 'participants') {
680
+ locus[key] = (0, _lodash.cloneDeep)(_this4[key]);
681
+ }
682
+ });
683
+ } else {
684
+ // initialize only the fields that are not part of main "Locus" object
685
+ // (except participants, which need to stay empty - that means "no participant changes")
686
+ (0, _values.default)(_types.ObjectTypeToLocusKeyMap).forEach(function (locusDtoKey) {
687
+ if (locusDtoKey !== 'participants') {
688
+ locus[locusDtoKey] = (0, _lodash.cloneDeep)(_this4[locusDtoKey]);
689
+ }
690
+ });
691
+ }
692
+ _loggerProxy.default.logger.info("Locus-info:index#updateFromHashTree --> LOCUS object is ".concat(locusObjectStateAfterUpdates, ", all updates: ").concat((0, _stringify.default)(data.updatedObjects.map(function (o) {
693
+ return {
694
+ type: o.htMeta.elementId.type,
695
+ id: o.htMeta.elementId.id,
696
+ hasData: !!o.data
697
+ };
698
+ }))));
699
+ // now apply all the updates from the hash tree onto the locus
700
+ data.updatedObjects.forEach(function (object) {
701
+ locus = _this4.updateLocusFromHashTreeObject(object, locus);
702
+ });
703
+
704
+ // update our locus info with the new locus
705
+ this.onDeltaLocus(locus);
706
+ break;
707
+ }
708
+ case _hashTreeParser.LocusInfoUpdateType.MEETING_ENDED:
709
+ {
710
+ _loggerProxy.default.logger.info("Locus-info:index#updateFromHashTree --> received signal that meeting ended, destroying meeting ".concat(this.meetingId));
711
+ var meeting = this.webex.meetings.meetingCollection.get(this.meetingId);
712
+ this.webex.meetings.destroy(meeting, _constants.MEETING_REMOVED_REASON.SELF_REMOVED);
713
+ }
714
+ }
334
715
  }
335
716
 
336
717
  /**
@@ -342,37 +723,44 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
342
723
  }, {
343
724
  key: "parse",
344
725
  value: function parse(meeting, data) {
345
- // eslint-disable-next-line @typescript-eslint/no-shadow
346
- var eventType = data.eventType;
347
- var locus = this.getTheLocusToUpdate(data.locus);
348
- _loggerProxy.default.logger.info("Locus-info:index#parse --> received locus data: ".concat(eventType));
349
- locus.jsSdkMeta = {
350
- removedParticipantIds: []
351
- };
352
- switch (eventType) {
353
- case _constants.LOCUSEVENT.PARTICIPANT_JOIN:
354
- case _constants.LOCUSEVENT.PARTICIPANT_LEFT:
355
- case _constants.LOCUSEVENT.CONTROLS_UPDATED:
356
- case _constants.LOCUSEVENT.PARTICIPANT_AUDIO_MUTED:
357
- case _constants.LOCUSEVENT.PARTICIPANT_AUDIO_UNMUTED:
358
- case _constants.LOCUSEVENT.PARTICIPANT_VIDEO_MUTED:
359
- case _constants.LOCUSEVENT.PARTICIPANT_VIDEO_UNMUTED:
360
- case _constants.LOCUSEVENT.SELF_CHANGED:
361
- case _constants.LOCUSEVENT.PARTICIPANT_UPDATED:
362
- case _constants.LOCUSEVENT.PARTICIPANT_CONTROLS_UPDATED:
363
- case _constants.LOCUSEVENT.PARTICIPANT_ROLES_UPDATED:
364
- case _constants.LOCUSEVENT.PARTICIPANT_DECLINED:
365
- case _constants.LOCUSEVENT.FLOOR_GRANTED:
366
- case _constants.LOCUSEVENT.FLOOR_RELEASED:
367
- this.onFullLocus(locus, eventType);
368
- break;
369
- case _constants.LOCUSEVENT.DIFFERENCE:
370
- this.handleLocusDelta(locus, meeting);
371
- break;
372
- default:
373
- // Why will there be a event with no eventType ????
374
- // we may not need this, we can get full locus
375
- this.handleLocusDelta(locus, meeting);
726
+ if (this.hashTreeParser) {
727
+ this.handleHashTreeMessage(meeting, data.eventType, data.stateElementsMessage);
728
+ } else {
729
+ // eslint-disable-next-line @typescript-eslint/no-shadow
730
+ var eventType = data.eventType;
731
+ var locus = this.getTheLocusToUpdate(data.locus);
732
+ _loggerProxy.default.logger.info("Locus-info:index#parse --> received locus data: ".concat(eventType));
733
+ locus.jsSdkMeta = {
734
+ removedParticipantIds: []
735
+ };
736
+ switch (eventType) {
737
+ case _constants.LOCUSEVENT.PARTICIPANT_JOIN:
738
+ case _constants.LOCUSEVENT.PARTICIPANT_LEFT:
739
+ case _constants.LOCUSEVENT.CONTROLS_UPDATED:
740
+ case _constants.LOCUSEVENT.PARTICIPANT_AUDIO_MUTED:
741
+ case _constants.LOCUSEVENT.PARTICIPANT_AUDIO_UNMUTED:
742
+ case _constants.LOCUSEVENT.PARTICIPANT_VIDEO_MUTED:
743
+ case _constants.LOCUSEVENT.PARTICIPANT_VIDEO_UNMUTED:
744
+ case _constants.LOCUSEVENT.SELF_CHANGED:
745
+ case _constants.LOCUSEVENT.PARTICIPANT_UPDATED:
746
+ case _constants.LOCUSEVENT.PARTICIPANT_CONTROLS_UPDATED:
747
+ case _constants.LOCUSEVENT.PARTICIPANT_ROLES_UPDATED:
748
+ case _constants.LOCUSEVENT.PARTICIPANT_DECLINED:
749
+ case _constants.LOCUSEVENT.FLOOR_GRANTED:
750
+ case _constants.LOCUSEVENT.FLOOR_RELEASED:
751
+ this.onFullLocus(locus, eventType);
752
+ break;
753
+ case _constants.LOCUSEVENT.DIFFERENCE:
754
+ this.handleLocusDelta(locus, meeting);
755
+ break;
756
+ case _constants.LOCUSEVENT.HASH_TREE_DATA_UPDATED:
757
+ this.sendClassicVsHashTreeMismatchMetric(meeting, "got ".concat(eventType, ", expected classic events"));
758
+ break;
759
+ default:
760
+ // Why will there be a event with no eventType ????
761
+ // we may not need this, we can get full locus
762
+ this.handleLocusDelta(locus, meeting);
763
+ }
376
764
  }
377
765
  }
378
766
 
@@ -389,26 +777,99 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
389
777
  return this.emit(scope, eventName, args);
390
778
  }
391
779
 
780
+ /**
781
+ * Function for handling full locus when it's using hash trees (so not the "classic" one).
782
+ *
783
+ * @param {object} locus locus object
784
+ * @param {string} eventType locus event
785
+ * @param {DataSet[]} dataSets
786
+ * @returns {void}
787
+ */
788
+ }, {
789
+ key: "onFullLocusWithHashTrees",
790
+ value: function onFullLocusWithHashTrees(locus, eventType, dataSets) {
791
+ if (!this.hashTreeParser) {
792
+ _loggerProxy.default.logger.info("Locus-info:index#onFullLocus --> creating hash tree parser");
793
+ _loggerProxy.default.logger.info('Locus-info:index#onFullLocus --> dataSets:', dataSets, ' and locus:', locus);
794
+ this.hashTreeParser = this.createHashTreeParser({
795
+ initialLocus: {
796
+ locus: locus,
797
+ dataSets: dataSets
798
+ }
799
+ });
800
+ this.onFullLocusCommon(locus, eventType);
801
+ } else {
802
+ // in this case the Locus we're getting is not necessarily the full one
803
+ // so treat it like if we just got it in any api response
804
+
805
+ _loggerProxy.default.logger.info('Locus-info:index#onFullLocus --> hash tree parser already exists, handling it like a normal API response');
806
+ this.handleLocusAPIResponse(undefined, {
807
+ dataSets: dataSets,
808
+ locus: locus
809
+ });
810
+ }
811
+ }
812
+
813
+ /**
814
+ * Function for handling full locus when it's the "classic" one (not hash trees)
815
+ *
816
+ * @param {object} locus locus object
817
+ * @param {string} eventType locus event
818
+ * @returns {void}
819
+ */
820
+ }, {
821
+ key: "onFullLocusClassic",
822
+ value: function onFullLocusClassic(locus, eventType) {
823
+ if (!this.locusParser.isNewFullLocus(locus)) {
824
+ _loggerProxy.default.logger.info("Locus-info:index#onFullLocus --> ignoring old full locus DTO, eventType=".concat(eventType));
825
+ return;
826
+ }
827
+ this.onFullLocusCommon(locus, eventType);
828
+ }
829
+
392
830
  /**
393
831
  * updates the locus with full locus object
394
832
  * @param {object} locus locus object
395
- * @param {string} eventType particulat locus event
833
+ * @param {string} eventType locus event
834
+ * @param {DataSet[]} dataSets
396
835
  * @returns {object} null
397
836
  * @memberof LocusInfo
398
837
  */
399
838
  }, {
400
839
  key: "onFullLocus",
401
- value: function onFullLocus(locus, eventType) {
402
- var _locus$jsSdkMeta;
840
+ value: function onFullLocus(locus, eventType, dataSets) {
403
841
  if (!locus) {
404
842
  _loggerProxy.default.logger.error('Locus-info:index#onFullLocus --> object passed as argument was invalid, continuing.');
405
843
  }
406
- if (!this.locusParser.isNewFullLocus(locus)) {
407
- _loggerProxy.default.logger.info("Locus-info:index#onFullLocus --> ignoring old full locus DTO, eventType=".concat(eventType));
408
- return;
844
+ if (dataSets) {
845
+ // this is the new hashmap Locus DTO format (only applicable to webinars for now)
846
+ this.onFullLocusWithHashTrees(locus, eventType, dataSets);
847
+ } else {
848
+ this.onFullLocusClassic(locus, eventType);
409
849
  }
850
+ }
851
+
852
+ /**
853
+ * Common part of handling full locus, used by both classic and hash tree based locus handling
854
+ * @param {object} locus locus object
855
+ * @param {string} eventType locus event
856
+ * @returns {void}
857
+ */
858
+ }, {
859
+ key: "onFullLocusCommon",
860
+ value: function onFullLocusCommon(locus, eventType) {
861
+ var _this$participants,
862
+ _this5 = this,
863
+ _locus$jsSdkMeta;
410
864
  this.scheduledMeeting = locus.meeting || null;
411
865
  this.participants = locus.participants;
866
+ (_this$participants = this.participants) === null || _this$participants === void 0 ? void 0 : _this$participants.forEach(function (participant) {
867
+ var _participant$htMeta;
868
+ // participant.htMeta is set only for hash tree based locus
869
+ if ((_participant$htMeta = participant.htMeta) !== null && _participant$htMeta !== void 0 && _participant$htMeta.elementId.id) {
870
+ _this5.hashTreeObjectId2ParticipantId.set(participant.htMeta.elementId.id, participant.id);
871
+ }
872
+ });
412
873
  var isReplaceMembers = _controlsUtils.default.isNeedReplaceMembers(this.controls, locus.controls);
413
874
  this.updateLocusInfo(locus);
414
875
  this.updateParticipants(locus.participants, (_locus$jsSdkMeta = locus.jsSdkMeta) === null || _locus$jsSdkMeta === void 0 ? void 0 : _locus$jsSdkMeta.removedParticipantIds, isReplaceMembers);
@@ -479,7 +940,7 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
479
940
  }, {
480
941
  key: "updateLocusInfo",
481
942
  value: function updateLocusInfo(locus) {
482
- var _locus$self, _locus$self2, _locus$links3, _locus$links4;
943
+ var _locus$self, _locus$self2;
483
944
  if (((_locus$self = locus.self) === null || _locus$self === void 0 ? void 0 : _locus$self.reason) === 'MOVED' && ((_locus$self2 = locus.self) === null || _locus$self2 === void 0 ? void 0 : _locus$self2.state) === 'LEFT') {
484
945
  // When moved to a breakout session locus sends a message for the previous locus
485
946
  // indicating that we have been moved. It isn't helpful to continue parsing this
@@ -503,8 +964,7 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
503
964
  this.updateMemberShip(locus.membership);
504
965
  this.updateIdentifiers(locus.identities);
505
966
  this.updateEmbeddedApps(locus.embeddedApps);
506
- this.updateServices((_locus$links3 = locus.links) === null || _locus$links3 === void 0 ? void 0 : _locus$links3.services);
507
- this.updateResources((_locus$links4 = locus.links) === null || _locus$links4 === void 0 ? void 0 : _locus$links4.resources);
967
+ this.updateLinks(locus.links);
508
968
  this.compareAndUpdate();
509
969
  // update which required to compare different objects from locus
510
970
  }
@@ -1053,41 +1513,35 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
1053
1513
  }
1054
1514
 
1055
1515
  /**
1056
- * @param {Object} services
1516
+ * Updates links and emits appropriate events if services or resources have changed
1517
+ * @param {Object} links
1057
1518
  * @returns {undefined}
1058
1519
  * @memberof LocusInfo
1059
1520
  */
1060
1521
  }, {
1061
- key: "updateServices",
1062
- value: function updateServices(services) {
1063
- if (services && !(0, _lodash.isEqual)(this.services, services)) {
1064
- this.services = services;
1522
+ key: "updateLinks",
1523
+ value: function updateLinks(links) {
1524
+ var _this$links, _this$links2;
1525
+ var _ref2 = links || {},
1526
+ services = _ref2.services,
1527
+ resources = _ref2.resources;
1528
+ if (services && !(0, _lodash.isEqual)((_this$links = this.links) === null || _this$links === void 0 ? void 0 : _this$links.services, services)) {
1065
1529
  this.emitScoped({
1066
1530
  file: 'locus-info',
1067
- function: 'updateServices'
1531
+ function: 'updateLinks'
1068
1532
  }, _constants.LOCUSINFO.EVENTS.LINKS_SERVICES, {
1069
1533
  services: services
1070
1534
  });
1071
1535
  }
1072
- }
1073
-
1074
- /**
1075
- * @param {Object} resources
1076
- * @returns {undefined}
1077
- * @memberof LocusInfo
1078
- */
1079
- }, {
1080
- key: "updateResources",
1081
- value: function updateResources(resources) {
1082
- if (resources && !(0, _lodash.isEqual)(this.resources, resources)) {
1083
- this.resources = resources;
1536
+ if (resources && !(0, _lodash.isEqual)((_this$links2 = this.links) === null || _this$links2 === void 0 ? void 0 : _this$links2.resources, resources)) {
1084
1537
  this.emitScoped({
1085
1538
  file: 'locus-info',
1086
- function: 'updateResources'
1539
+ function: 'updateLinks'
1087
1540
  }, _constants.LOCUSINFO.EVENTS.LINKS_RESOURCES, {
1088
1541
  resources: resources
1089
1542
  });
1090
1543
  }
1544
+ this.links = links;
1091
1545
  }
1092
1546
 
1093
1547
  /**
@@ -1628,7 +2082,7 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
1628
2082
  }, {
1629
2083
  key: "updateMainSessionLocusCache",
1630
2084
  value: function updateMainSessionLocusCache(mainLocus) {
1631
- var _this4 = this;
2085
+ var _this6 = this;
1632
2086
  if (!mainLocus) {
1633
2087
  return;
1634
2088
  }
@@ -1637,7 +2091,7 @@ var LocusInfo = exports.default = /*#__PURE__*/function (_EventsScope) {
1637
2091
  // shallow merge and do special merge for participants
1638
2092
  (0, _lodash.assignWith)(this.mainSessionLocusCache, locusClone, function (objValue, srcValue, key) {
1639
2093
  if (key === 'participants') {
1640
- return _this4.mergeParticipants(objValue, srcValue);
2094
+ return _this6.mergeParticipants(objValue, srcValue);
1641
2095
  }
1642
2096
  return srcValue || objValue;
1643
2097
  });