@webex/plugin-meetings 3.8.1 → 3.9.0-multiple-llm.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 (319) hide show
  1. package/README.md +26 -13
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.js +34 -3
  5. package/dist/constants.js.map +1 -1
  6. package/dist/controls-options-manager/enums.js +1 -0
  7. package/dist/controls-options-manager/enums.js.map +1 -1
  8. package/dist/controls-options-manager/types.js.map +1 -1
  9. package/dist/controls-options-manager/util.js +26 -0
  10. package/dist/controls-options-manager/util.js.map +1 -1
  11. package/dist/interpretation/index.js +1 -1
  12. package/dist/interpretation/siLanguage.js +1 -1
  13. package/dist/locus-info/controlsUtils.js +11 -3
  14. package/dist/locus-info/controlsUtils.js.map +1 -1
  15. package/dist/locus-info/index.js +107 -95
  16. package/dist/locus-info/index.js.map +1 -1
  17. package/dist/locus-info/parser.js +4 -1
  18. package/dist/locus-info/parser.js.map +1 -1
  19. package/dist/media/index.js +2 -2
  20. package/dist/media/index.js.map +1 -1
  21. package/dist/media/properties.js +53 -5
  22. package/dist/media/properties.js.map +1 -1
  23. package/dist/meeting/brbState.js +17 -14
  24. package/dist/meeting/brbState.js.map +1 -1
  25. package/dist/meeting/in-meeting-actions.js +13 -1
  26. package/dist/meeting/in-meeting-actions.js.map +1 -1
  27. package/dist/meeting/index.js +555 -296
  28. package/dist/meeting/index.js.map +1 -1
  29. package/dist/meeting/muteState.js +2 -5
  30. package/dist/meeting/muteState.js.map +1 -1
  31. package/dist/meeting/request.js +44 -0
  32. package/dist/meeting/request.js.map +1 -1
  33. package/dist/meeting/request.type.js.map +1 -1
  34. package/dist/{rtcMetrics/constants.js → meeting/type.js} +1 -5
  35. package/dist/meeting/type.js.map +1 -0
  36. package/dist/meeting/util.js +98 -13
  37. package/dist/meeting/util.js.map +1 -1
  38. package/dist/meeting-info/meeting-info-v2.js +29 -21
  39. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  40. package/dist/meetings/index.js +18 -10
  41. package/dist/meetings/index.js.map +1 -1
  42. package/dist/member/types.js.map +1 -1
  43. package/dist/members/collection.js +13 -0
  44. package/dist/members/collection.js.map +1 -1
  45. package/dist/members/index.js +53 -29
  46. package/dist/members/index.js.map +1 -1
  47. package/dist/members/request.js +3 -3
  48. package/dist/members/request.js.map +1 -1
  49. package/dist/members/util.js +25 -8
  50. package/dist/members/util.js.map +1 -1
  51. package/dist/metrics/constants.js +3 -1
  52. package/dist/metrics/constants.js.map +1 -1
  53. package/dist/multistream/mediaRequestManager.js +1 -1
  54. package/dist/multistream/mediaRequestManager.js.map +1 -1
  55. package/dist/multistream/remoteMedia.js +34 -5
  56. package/dist/multistream/remoteMedia.js.map +1 -1
  57. package/dist/multistream/remoteMediaGroup.js +42 -2
  58. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  59. package/dist/multistream/sendSlotManager.js +32 -2
  60. package/dist/multistream/sendSlotManager.js.map +1 -1
  61. package/dist/reachability/index.js +8 -13
  62. package/dist/reachability/index.js.map +1 -1
  63. package/dist/types/constants.d.ts +30 -0
  64. package/dist/types/controls-options-manager/enums.d.ts +2 -1
  65. package/dist/types/controls-options-manager/types.d.ts +4 -1
  66. package/dist/types/locus-info/index.d.ts +54 -10
  67. package/dist/types/media/properties.d.ts +21 -0
  68. package/dist/types/meeting/brbState.d.ts +0 -1
  69. package/dist/types/meeting/in-meeting-actions.d.ts +12 -0
  70. package/dist/types/meeting/index.d.ts +58 -20
  71. package/dist/types/meeting/request.d.ts +18 -1
  72. package/dist/types/meeting/request.type.d.ts +74 -0
  73. package/dist/types/meeting/type.d.ts +9 -0
  74. package/dist/types/meeting/util.d.ts +13 -3
  75. package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
  76. package/dist/types/meetings/index.d.ts +3 -1
  77. package/dist/types/member/types.d.ts +1 -0
  78. package/dist/types/members/collection.d.ts +6 -0
  79. package/dist/types/members/index.d.ts +22 -9
  80. package/dist/types/members/request.d.ts +1 -1
  81. package/dist/types/members/util.d.ts +13 -6
  82. package/dist/types/metrics/constants.d.ts +2 -0
  83. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  84. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  85. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  86. package/dist/types/reachability/index.d.ts +2 -2
  87. package/dist/webinar/index.js +1 -1
  88. package/package.json +25 -26
  89. package/src/constants.ts +34 -2
  90. package/src/controls-options-manager/enums.ts +1 -0
  91. package/src/controls-options-manager/types.ts +6 -1
  92. package/src/controls-options-manager/util.ts +31 -0
  93. package/src/locus-info/controlsUtils.ts +15 -0
  94. package/src/locus-info/index.ts +174 -96
  95. package/src/locus-info/parser.ts +5 -1
  96. package/src/media/index.ts +2 -2
  97. package/src/media/properties.ts +43 -0
  98. package/src/meeting/brbState.ts +13 -9
  99. package/src/meeting/in-meeting-actions.ts +25 -0
  100. package/src/meeting/index.ts +362 -75
  101. package/src/meeting/muteState.ts +2 -6
  102. package/src/meeting/request.ts +39 -0
  103. package/src/meeting/request.type.ts +64 -0
  104. package/src/meeting/type.ts +9 -0
  105. package/src/meeting/util.ts +114 -22
  106. package/src/meeting-info/meeting-info-v2.ts +24 -5
  107. package/src/meetings/index.ts +12 -5
  108. package/src/member/types.ts +1 -0
  109. package/src/members/collection.ts +11 -0
  110. package/src/members/index.ts +51 -15
  111. package/src/members/request.ts +2 -2
  112. package/src/members/util.ts +34 -6
  113. package/src/metrics/constants.ts +2 -0
  114. package/src/multistream/mediaRequestManager.ts +7 -7
  115. package/src/multistream/remoteMedia.ts +34 -4
  116. package/src/multistream/remoteMediaGroup.ts +37 -2
  117. package/src/multistream/sendSlotManager.ts +34 -2
  118. package/src/reachability/index.ts +8 -16
  119. package/test/unit/spec/common/browser-detection.js +0 -24
  120. package/test/unit/spec/controls-options-manager/util.js +58 -0
  121. package/test/unit/spec/locus-info/controlsUtils.js +52 -0
  122. package/test/unit/spec/locus-info/index.js +270 -97
  123. package/test/unit/spec/locus-info/parser.js +3 -2
  124. package/test/unit/spec/media/index.ts +107 -0
  125. package/test/unit/spec/media/properties.ts +137 -0
  126. package/test/unit/spec/meeting/brbState.ts +23 -4
  127. package/test/unit/spec/meeting/in-meeting-actions.ts +12 -0
  128. package/test/unit/spec/meeting/index.js +1194 -97
  129. package/test/unit/spec/meeting/muteState.js +32 -6
  130. package/test/unit/spec/meeting/request.js +92 -0
  131. package/test/unit/spec/meeting/utils.js +167 -17
  132. package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
  133. package/test/unit/spec/meetings/index.js +12 -5
  134. package/test/unit/spec/members/collection.js +120 -0
  135. package/test/unit/spec/members/index.js +140 -12
  136. package/test/unit/spec/members/request.js +57 -2
  137. package/test/unit/spec/members/utils.js +139 -17
  138. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  139. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  140. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  141. package/test/unit/spec/reachability/index.ts +160 -9
  142. package/test/unit/spec/roap/turnDiscovery.ts +3 -3
  143. package/dist/annotation/annotation.types.d.ts +0 -42
  144. package/dist/annotation/constants.d.ts +0 -31
  145. package/dist/annotation/index.d.ts +0 -117
  146. package/dist/breakouts/breakout.d.ts +0 -8
  147. package/dist/breakouts/collection.d.ts +0 -5
  148. package/dist/breakouts/edit-lock-error.d.ts +0 -15
  149. package/dist/breakouts/events.d.ts +0 -8
  150. package/dist/breakouts/index.d.ts +0 -5
  151. package/dist/breakouts/request.d.ts +0 -22
  152. package/dist/breakouts/utils.d.ts +0 -15
  153. package/dist/common/browser-detection.d.ts +0 -9
  154. package/dist/common/collection.d.ts +0 -48
  155. package/dist/common/config.d.ts +0 -2
  156. package/dist/common/errors/captcha-error.d.ts +0 -15
  157. package/dist/common/errors/intent-to-join.d.ts +0 -16
  158. package/dist/common/errors/join-meeting.d.ts +0 -17
  159. package/dist/common/errors/media.d.ts +0 -15
  160. package/dist/common/errors/no-meeting-info.d.ts +0 -14
  161. package/dist/common/errors/parameter.d.ts +0 -15
  162. package/dist/common/errors/password-error.d.ts +0 -15
  163. package/dist/common/errors/permission.d.ts +0 -14
  164. package/dist/common/errors/reclaim-host-role-error.d.ts +0 -60
  165. package/dist/common/errors/reclaim-host-role-error.js +0 -158
  166. package/dist/common/errors/reclaim-host-role-error.js.map +0 -1
  167. package/dist/common/errors/reclaim-host-role-errors.d.ts +0 -60
  168. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  169. package/dist/common/errors/reconnection-in-progress.js +0 -35
  170. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  171. package/dist/common/errors/reconnection.d.ts +0 -15
  172. package/dist/common/errors/stats.d.ts +0 -15
  173. package/dist/common/errors/webex-errors.d.ts +0 -81
  174. package/dist/common/errors/webex-meetings-error.d.ts +0 -20
  175. package/dist/common/events/events-scope.d.ts +0 -17
  176. package/dist/common/events/events.d.ts +0 -12
  177. package/dist/common/events/trigger-proxy.d.ts +0 -2
  178. package/dist/common/events/util.d.ts +0 -2
  179. package/dist/common/logs/logger-config.d.ts +0 -2
  180. package/dist/common/logs/logger-proxy.d.ts +0 -2
  181. package/dist/common/logs/request.d.ts +0 -34
  182. package/dist/common/queue.d.ts +0 -32
  183. package/dist/config.d.ts +0 -73
  184. package/dist/constants.d.ts +0 -952
  185. package/dist/controls-options-manager/constants.d.ts +0 -4
  186. package/dist/controls-options-manager/enums.d.ts +0 -5
  187. package/dist/controls-options-manager/index.d.ts +0 -120
  188. package/dist/controls-options-manager/types.d.ts +0 -43
  189. package/dist/controls-options-manager/util.d.ts +0 -7
  190. package/dist/index.d.ts +0 -4
  191. package/dist/interceptors/index.d.ts +0 -2
  192. package/dist/interceptors/locusRetry.d.ts +0 -27
  193. package/dist/interpretation/collection.d.ts +0 -5
  194. package/dist/interpretation/index.d.ts +0 -5
  195. package/dist/interpretation/siLanguage.d.ts +0 -5
  196. package/dist/locus-info/controlsUtils.d.ts +0 -2
  197. package/dist/locus-info/embeddedAppsUtils.d.ts +0 -2
  198. package/dist/locus-info/fullState.d.ts +0 -2
  199. package/dist/locus-info/hostUtils.d.ts +0 -2
  200. package/dist/locus-info/index.d.ts +0 -269
  201. package/dist/locus-info/infoUtils.d.ts +0 -2
  202. package/dist/locus-info/mediaSharesUtils.d.ts +0 -2
  203. package/dist/locus-info/parser.d.ts +0 -212
  204. package/dist/locus-info/selfUtils.d.ts +0 -2
  205. package/dist/media/index.d.ts +0 -32
  206. package/dist/media/properties.d.ts +0 -108
  207. package/dist/media/util.d.ts +0 -2
  208. package/dist/mediaQualityMetrics/config.d.ts +0 -233
  209. package/dist/mediaQualityMetrics/config.js +0 -513
  210. package/dist/mediaQualityMetrics/config.js.map +0 -1
  211. package/dist/meeting/effectsState.d.ts +0 -42
  212. package/dist/meeting/effectsState.js +0 -260
  213. package/dist/meeting/effectsState.js.map +0 -1
  214. package/dist/meeting/in-meeting-actions.d.ts +0 -79
  215. package/dist/meeting/index.d.ts +0 -1622
  216. package/dist/meeting/locusMediaRequest.d.ts +0 -74
  217. package/dist/meeting/muteState.d.ts +0 -116
  218. package/dist/meeting/request.d.ts +0 -257
  219. package/dist/meeting/request.type.d.ts +0 -11
  220. package/dist/meeting/state.d.ts +0 -9
  221. package/dist/meeting/util.d.ts +0 -2
  222. package/dist/meeting/voicea-meeting.d.ts +0 -16
  223. package/dist/meeting-info/collection.d.ts +0 -20
  224. package/dist/meeting-info/index.d.ts +0 -57
  225. package/dist/meeting-info/meeting-info-v2.d.ts +0 -93
  226. package/dist/meeting-info/request.d.ts +0 -22
  227. package/dist/meeting-info/util.d.ts +0 -2
  228. package/dist/meeting-info/utilv2.d.ts +0 -2
  229. package/dist/meetings/collection.d.ts +0 -23
  230. package/dist/meetings/index.d.ts +0 -296
  231. package/dist/meetings/meetings.types.d.ts +0 -4
  232. package/dist/meetings/request.d.ts +0 -27
  233. package/dist/meetings/util.d.ts +0 -18
  234. package/dist/member/index.d.ts +0 -148
  235. package/dist/member/member.types.d.ts +0 -11
  236. package/dist/member/member.types.js +0 -18
  237. package/dist/member/member.types.js.map +0 -1
  238. package/dist/member/types.d.ts +0 -32
  239. package/dist/member/util.d.ts +0 -2
  240. package/dist/members/collection.d.ts +0 -24
  241. package/dist/members/index.d.ts +0 -308
  242. package/dist/members/request.d.ts +0 -58
  243. package/dist/members/types.d.ts +0 -25
  244. package/dist/members/util.d.ts +0 -2
  245. package/dist/metrics/config.d.ts +0 -169
  246. package/dist/metrics/config.js +0 -289
  247. package/dist/metrics/config.js.map +0 -1
  248. package/dist/metrics/constants.d.ts +0 -59
  249. package/dist/metrics/index.d.ts +0 -152
  250. package/dist/multistream/mediaRequestManager.d.ts +0 -119
  251. package/dist/multistream/receiveSlot.d.ts +0 -68
  252. package/dist/multistream/receiveSlotManager.d.ts +0 -56
  253. package/dist/multistream/remoteMedia.d.ts +0 -72
  254. package/dist/multistream/remoteMediaGroup.d.ts +0 -49
  255. package/dist/multistream/remoteMediaManager.d.ts +0 -300
  256. package/dist/multistream/sendSlotManager.d.ts +0 -69
  257. package/dist/networkQualityMonitor/index.d.ts +0 -70
  258. package/dist/networkQualityMonitor/index.js +0 -226
  259. package/dist/networkQualityMonitor/index.js.map +0 -1
  260. package/dist/peer-connection-manager/index.d.ts +0 -6
  261. package/dist/peer-connection-manager/index.js +0 -671
  262. package/dist/peer-connection-manager/index.js.map +0 -1
  263. package/dist/peer-connection-manager/util.d.ts +0 -6
  264. package/dist/peer-connection-manager/util.js +0 -110
  265. package/dist/peer-connection-manager/util.js.map +0 -1
  266. package/dist/personal-meeting-room/index.d.ts +0 -47
  267. package/dist/personal-meeting-room/request.d.ts +0 -14
  268. package/dist/personal-meeting-room/util.d.ts +0 -2
  269. package/dist/reachability/clusterReachability.d.ts +0 -109
  270. package/dist/reachability/index.d.ts +0 -139
  271. package/dist/reachability/request.d.ts +0 -35
  272. package/dist/reachability/util.d.ts +0 -8
  273. package/dist/reactions/constants.d.ts +0 -3
  274. package/dist/reactions/reactions.d.ts +0 -4
  275. package/dist/reactions/reactions.type.d.ts +0 -32
  276. package/dist/reconnection-manager/index.d.ts +0 -112
  277. package/dist/recording-controller/enums.d.ts +0 -7
  278. package/dist/recording-controller/index.d.ts +0 -193
  279. package/dist/recording-controller/util.d.ts +0 -13
  280. package/dist/roap/collection.d.ts +0 -10
  281. package/dist/roap/collection.js +0 -63
  282. package/dist/roap/collection.js.map +0 -1
  283. package/dist/roap/handler.d.ts +0 -47
  284. package/dist/roap/handler.js +0 -279
  285. package/dist/roap/handler.js.map +0 -1
  286. package/dist/roap/index.d.ts +0 -116
  287. package/dist/roap/request.d.ts +0 -35
  288. package/dist/roap/state.d.ts +0 -9
  289. package/dist/roap/state.js +0 -127
  290. package/dist/roap/state.js.map +0 -1
  291. package/dist/roap/turnDiscovery.d.ts +0 -81
  292. package/dist/roap/util.d.ts +0 -2
  293. package/dist/roap/util.js +0 -76
  294. package/dist/roap/util.js.map +0 -1
  295. package/dist/rtcMetrics/constants.d.ts +0 -4
  296. package/dist/rtcMetrics/constants.js.map +0 -1
  297. package/dist/rtcMetrics/index.d.ts +0 -61
  298. package/dist/rtcMetrics/index.js +0 -197
  299. package/dist/rtcMetrics/index.js.map +0 -1
  300. package/dist/statsAnalyzer/global.d.ts +0 -118
  301. package/dist/statsAnalyzer/global.js +0 -127
  302. package/dist/statsAnalyzer/global.js.map +0 -1
  303. package/dist/statsAnalyzer/index.d.ts +0 -193
  304. package/dist/statsAnalyzer/index.js +0 -1019
  305. package/dist/statsAnalyzer/index.js.map +0 -1
  306. package/dist/statsAnalyzer/mqaUtil.d.ts +0 -22
  307. package/dist/statsAnalyzer/mqaUtil.js +0 -181
  308. package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
  309. package/dist/transcription/index.d.ts +0 -64
  310. package/dist/types/common/errors/reconnection-in-progress.d.ts +0 -9
  311. package/dist/types/mediaQualityMetrics/config.d.ts +0 -241
  312. package/dist/types/networkQualityMonitor/index.d.ts +0 -70
  313. package/dist/types/rtcMetrics/constants.d.ts +0 -4
  314. package/dist/types/rtcMetrics/index.d.ts +0 -71
  315. package/dist/types/statsAnalyzer/global.d.ts +0 -36
  316. package/dist/types/statsAnalyzer/index.d.ts +0 -217
  317. package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
  318. package/dist/webinar/collection.d.ts +0 -16
  319. package/dist/webinar/index.d.ts +0 -5
@@ -30,6 +30,7 @@ import MembersUtil from './util';
30
30
  import {ReceiveSlotManager} from '../multistream/receiveSlotManager';
31
31
  import {MediaRequestManager} from '../multistream/mediaRequestManager';
32
32
  import {ServerRoleShape} from './types';
33
+ import {Invitee} from '../meeting/type';
33
34
 
34
35
  /**
35
36
  * Members Update Event
@@ -73,7 +74,11 @@ import {ServerRoleShape} from './types';
73
74
  * @memberof Members
74
75
  */
75
76
 
76
- type UpdatedMembers = {added: Array<Member>; updated: Array<Member>};
77
+ type UpdatedMembers = {
78
+ added: Array<Member>;
79
+ updated: Array<Member>;
80
+ removedIds?: Array<string>; // removed member ids
81
+ };
77
82
  /**
78
83
  * @class Members
79
84
  */
@@ -383,12 +388,18 @@ export default class Members extends StatelessWebexPlugin {
383
388
  * when new participant updates come in, both delta and full participants, update them in members collection
384
389
  * delta object in the event will have {updated, added} and full will be the full membersCollection
385
390
  * @param {Object} payload
386
- * @param {Object} payload.participants
391
+ * @param {Object} payload.participants new/updated participants
392
+ * @param {Boolean} payload.isReplace whether to replace the whole members collection
393
+ * @param {Object} payload.removedParticipantIds ids of the removed participants
387
394
  * @returns {undefined}
388
395
  * @private
389
396
  * @memberof Members
390
397
  */
391
- locusParticipantsUpdate(payload: {participants: object; isReplace?: boolean}) {
398
+ locusParticipantsUpdate(payload: {
399
+ participants: object;
400
+ isReplace?: boolean;
401
+ removedParticipantIds?: Array<string>;
402
+ }) {
392
403
  if (payload) {
393
404
  if (payload.isReplace) {
394
405
  this.clearMembers();
@@ -546,10 +557,22 @@ export default class Members extends StatelessWebexPlugin {
546
557
  private handleMembersUpdate(membersUpdate: UpdatedMembers) {
547
558
  this.constructMembers(membersUpdate.updated, true);
548
559
  this.constructMembers(membersUpdate.added, false);
560
+ this.removeMembers(membersUpdate.removedIds);
549
561
 
550
562
  return this.membersCollection.getAll();
551
563
  }
552
564
 
565
+ /**
566
+ * removes members from the collection
567
+ * @param {Array<string>} removedMembers removed members ids
568
+ * @returns {void}
569
+ */
570
+ private removeMembers(removedMembers: Array<string>) {
571
+ removedMembers.forEach((memberId) => {
572
+ this.membersCollection.remove(memberId);
573
+ });
574
+ }
575
+
553
576
  /**
554
577
  * set members to the member collection from each updated/added lists as passed in
555
578
  * @param {Array} list
@@ -599,6 +622,10 @@ export default class Members extends StatelessWebexPlugin {
599
622
  }
600
623
  const memberUpdate = this.update(payload.participants);
601
624
 
625
+ // this code depends on memberIds being the same as participantIds
626
+ // if MemberUtil.extractId() ever changes, this will need to be updated
627
+ memberUpdate.removedIds = payload.removedParticipantIds || [];
628
+
602
629
  return memberUpdate;
603
630
  }
604
631
 
@@ -800,18 +827,18 @@ export default class Members extends StatelessWebexPlugin {
800
827
 
801
828
  /**
802
829
  * Adds a guest Member to the associated meeting
803
- * @param {String} invitee
830
+ * @param {Invitee} invitee
804
831
  * @param {Boolean} [alertIfActive]
805
832
  * @returns {Promise}
806
833
  * @memberof Members
807
834
  */
808
- addMember(invitee: any, alertIfActive?: boolean) {
835
+ addMember(invitee: Invitee, alertIfActive?: boolean) {
809
836
  if (!this.locusUrl) {
810
837
  return Promise.reject(
811
838
  new ParameterError('The associated locus url for this meeting object must be defined.')
812
839
  );
813
840
  }
814
- if (MembersUtil.isInvalidInvitee(invitee)) {
841
+ if (invitee?.skipEmailValidation !== true && MembersUtil.isInvalidInvitee(invitee)) {
815
842
  return Promise.reject(
816
843
  new ParameterError(
817
844
  'The invitee must be defined with either a valid email, emailAddress or phoneNumber property.'
@@ -825,11 +852,11 @@ export default class Members extends StatelessWebexPlugin {
825
852
 
826
853
  /**
827
854
  * Cancels an outgoing PSTN call to the associated meeting
828
- * @param {String} invitee
855
+ * @param {Invitee} invitee
829
856
  * @returns {Promise}
830
857
  * @memberof Members
831
858
  */
832
- cancelPhoneInvite(invitee: any) {
859
+ cancelPhoneInvite(invitee: Invitee) {
833
860
  if (!this.locusUrl) {
834
861
  return Promise.reject(
835
862
  new ParameterError('The associated locus url for this meeting object must be defined.')
@@ -846,12 +873,14 @@ export default class Members extends StatelessWebexPlugin {
846
873
  }
847
874
 
848
875
  /**
849
- * Cancels an SIP call to the associated meeting
850
- * @param {String} invitee
876
+ * Cancels an SIP/phone call to the associated meeting
877
+ * @param {Invitee} invitee
878
+ * @param {String} invitee.memberId - The memberId of the invitee
879
+ * @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
851
880
  * @returns {Promise}
852
881
  * @memberof Members
853
882
  */
854
- cancelSIPInvite(invitee: any) {
883
+ cancelInviteByMemberId(invitee: Invitee) {
855
884
  if (!this.locusUrl) {
856
885
  return Promise.reject(
857
886
  new ParameterError('The associated locus url for this meeting object must be defined.')
@@ -862,9 +891,9 @@ export default class Members extends StatelessWebexPlugin {
862
891
  new ParameterError('The invitee must be defined with a memberId property.')
863
892
  );
864
893
  }
865
- const options = MembersUtil.cancelSIPInviteOptions(invitee, this.locusUrl);
894
+ const options = MembersUtil.cancelInviteByMemberIdOptions(invitee, this.locusUrl);
866
895
 
867
- return this.membersRequest.cancelSIPInvite(options);
896
+ return this.membersRequest.cancelInviteByMemberId(options);
868
897
  }
869
898
 
870
899
  /**
@@ -1178,11 +1207,17 @@ export default class Members extends StatelessWebexPlugin {
1178
1207
  * @param {string} memberId - id of the participant who is receiving request
1179
1208
  * @param {string} requestingParticipantId - id of the participant who is sending request (optional)
1180
1209
  * @param {string} [alias] - alias name
1210
+ * @param {string} [suffix] - name suffix (optional)
1181
1211
  * @returns {Promise}
1182
1212
  * @public
1183
1213
  * @memberof Members
1184
1214
  */
1185
- public editDisplayName(memberId: string, requestingParticipantId: string, alias: string) {
1215
+ public editDisplayName(
1216
+ memberId: string,
1217
+ requestingParticipantId: string,
1218
+ alias: string,
1219
+ suffix?: string
1220
+ ) {
1186
1221
  if (!this.locusUrl) {
1187
1222
  return Promise.reject(
1188
1223
  new ParameterError(
@@ -1202,7 +1237,8 @@ export default class Members extends StatelessWebexPlugin {
1202
1237
  memberId,
1203
1238
  requestingParticipantId,
1204
1239
  alias,
1205
- locusUrl
1240
+ locusUrl,
1241
+ suffix
1206
1242
  );
1207
1243
 
1208
1244
  return this.membersRequest.editDisplayNameMember(options);
@@ -285,14 +285,14 @@ export default class MembersRequest extends StatelessWebexPlugin {
285
285
  * @throws {Error} if the options are not valid and complete, must have invitee with memberId AND locusUrl
286
286
  * @memberof MembersRequest
287
287
  */
288
- cancelSIPInvite(options: any) {
288
+ cancelInviteByMemberId(options: any) {
289
289
  if (!options?.invitee?.memberId || !options?.locusUrl) {
290
290
  throw new ParameterError(
291
291
  'invitee must be passed and the associated locus url for this meeting object must be defined.'
292
292
  );
293
293
  }
294
294
 
295
- const requestParams = MembersUtil.generateCancelSIPInviteRequestParams(options);
295
+ const requestParams = MembersUtil.generateCancelInviteByMemberIdRequestParams(options);
296
296
 
297
297
  return this.locusDeltaRequest(requestParams);
298
298
  }
@@ -1,4 +1,5 @@
1
1
  import uuid from 'uuid';
2
+ import {has} from 'lodash';
2
3
  import {
3
4
  HTTP_VERBS,
4
5
  CONTROLS,
@@ -13,6 +14,7 @@ import {
13
14
  } from '../constants';
14
15
 
15
16
  import {RoleAssignmentOptions, RoleAssignmentRequest, ServerRoleShape} from './types';
17
+ import {Invitee} from '../meeting/type';
16
18
 
17
19
  const MembersUtil = {
18
20
  /**
@@ -47,6 +49,9 @@ const MembersUtil = {
47
49
  address:
48
50
  options.invitee.emailAddress || options.invitee.email || options.invitee.phoneNumber,
49
51
  ...(options.invitee.roles ? {roles: options.invitee.roles} : {}),
52
+ ...(has(options.invitee, 'isInternalNumber')
53
+ ? {isInternalNumber: options.invitee.isInternalNumber}
54
+ : {}),
50
55
  },
51
56
  ],
52
57
  alertIfActive: options.alertIfActive,
@@ -101,12 +106,16 @@ const MembersUtil = {
101
106
  return requestParams;
102
107
  },
103
108
 
104
- isInvalidInvitee: (invitee) => {
109
+ isInvalidInvitee: (invitee: Invitee) => {
105
110
  if (!(invitee && (invitee.email || invitee.emailAddress || invitee.phoneNumber))) {
106
111
  return true;
107
112
  }
108
113
 
109
114
  if (invitee.phoneNumber) {
115
+ if (invitee.isInternalNumber) {
116
+ return !DIALER_REGEX.INTERNAL_NUMBER.test(invitee.phoneNumber);
117
+ }
118
+
110
119
  return !DIALER_REGEX.E164_FORMAT.test(invitee.phoneNumber);
111
120
  }
112
121
 
@@ -181,13 +190,21 @@ const MembersUtil = {
181
190
  * @param {String} requestingParticipantId id of the participant who is sending request (optional)
182
191
  * @param {String} alias alias name
183
192
  * @param {String} locusUrl url
193
+ * @param {String} suffix optional suffix
184
194
  * @returns {Object} consists of {memberID: string, requestingParticipantId: string, alias: string, locusUrl: string}
185
195
  */
186
- generateEditDisplayNameMemberOptions: (memberId, requestingParticipantId, alias, locusUrl) => ({
196
+ generateEditDisplayNameMemberOptions: (
197
+ memberId,
198
+ requestingParticipantId,
199
+ alias,
200
+ locusUrl,
201
+ suffix
202
+ ) => ({
187
203
  memberId,
188
204
  requestingParticipantId,
189
205
  alias,
190
206
  locusUrl,
207
+ suffix,
191
208
  }),
192
209
 
193
210
  getMuteMemberRequestParams: (options) => {
@@ -292,10 +309,18 @@ const MembersUtil = {
292
309
  * @returns {Object} request parameters (method, uri, body) needed to make a editDisplayName request
293
310
  */
294
311
  editDisplayNameMemberRequestParams: (options) => {
295
- const body = {
312
+ const body: {
313
+ aliasValue: string;
314
+ requestingParticipantId: string;
315
+ suffixValue?: string;
316
+ } = {
296
317
  aliasValue: options.alias,
297
318
  requestingParticipantId: options.requestingParticipantId,
298
319
  };
320
+
321
+ if (options.suffix !== undefined) {
322
+ body.suffixValue = options.suffix;
323
+ }
299
324
  const uri = `${options.locusUrl}/${PARTICIPANT}/${options.memberId}/${ALIAS}`;
300
325
 
301
326
  return {
@@ -371,17 +396,20 @@ const MembersUtil = {
371
396
  return requestParams;
372
397
  },
373
398
 
374
- cancelSIPInviteOptions: (invitee, locusUrl) => ({
399
+ cancelInviteByMemberIdOptions: (invitee, locusUrl) => ({
375
400
  invitee,
376
401
  locusUrl,
377
402
  }),
378
403
 
379
- generateCancelSIPInviteRequestParams: (options) => {
404
+ generateCancelInviteByMemberIdRequestParams: (options) => {
405
+ const {memberId, isInternalNumber} = options.invitee;
406
+ const hasIsInternalNumberProp = has(options.invitee, 'isInternalNumber');
380
407
  const body = {
381
408
  actionType: _REMOVE_,
382
409
  invitees: [
383
410
  {
384
- address: options.invitee.memberId,
411
+ address: memberId,
412
+ ...(hasIsInternalNumberProp ? {isInternalNumber} : {}),
385
413
  },
386
414
  ],
387
415
  };
@@ -72,6 +72,7 @@ const BEHAVIORAL_METRICS = {
72
72
  MEETING_INFO_POLICY_ERROR: 'js_sdk_meeting_info_policy_error',
73
73
  LOCUS_DELTA_SYNC_FAILED: 'js_sdk_locus_delta_sync_failed',
74
74
  LOCUS_DELTA_OUT_OF_ORDER: 'js_sdk_locus_delta_ooo',
75
+ LOCUS_SYNC_HANDLING_FAILED: 'js_sdk_locus_sync_handling_failed',
75
76
  PERMISSION_TOKEN_REFRESH: 'js_sdk_permission_token_refresh',
76
77
  PERMISSION_TOKEN_REFRESH_ERROR: 'js_sdk_permission_token_refresh_error',
77
78
  TURN_DISCOVERY_LATENCY: 'js_sdk_turn_discovery_latency',
@@ -85,6 +86,7 @@ const BEHAVIORAL_METRICS = {
85
86
  VERIFY_REGISTRATION_ID_SUCCESS: 'js_sdk_verify_registrationId_success',
86
87
  VERIFY_REGISTRATION_ID_ERROR: 'js_sdk_verify_registrationId_error',
87
88
  JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',
89
+ MEDIA_ISSUE_DETECTED: 'js_sdk_media_issue_detected',
88
90
  };
89
91
 
90
92
  export {BEHAVIORAL_METRICS as default};
@@ -15,7 +15,7 @@ import {cloneDeepWith, debounce, isEmpty} from 'lodash';
15
15
  import LoggerProxy from '../common/logs/logger-proxy';
16
16
 
17
17
  import {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';
18
- import {getMaxFs} from './remoteMedia';
18
+ import {MAX_FS_VALUES} from './remoteMedia';
19
19
 
20
20
  export interface ActiveSpeakerPolicyInfo {
21
21
  policy: 'active-speaker';
@@ -123,12 +123,12 @@ export class MediaRequestManager {
123
123
 
124
124
  private getDegradedClientRequests(clientRequests: ClientRequestsMap) {
125
125
  const maxFsLimits = [
126
- getMaxFs('best'),
127
- getMaxFs('large'),
128
- getMaxFs('medium'),
129
- getMaxFs('small'),
130
- getMaxFs('very small'),
131
- getMaxFs('thumbnail'),
126
+ MAX_FS_VALUES['1080p'],
127
+ MAX_FS_VALUES['720p'],
128
+ MAX_FS_VALUES['540p'],
129
+ MAX_FS_VALUES['360p'],
130
+ MAX_FS_VALUES['180p'],
131
+ MAX_FS_VALUES['90p'],
132
132
  ];
133
133
 
134
134
  // reduce max-fs until total macroblocks is below limit
@@ -19,17 +19,18 @@ export type RemoteVideoResolution =
19
19
  | 'large' // 1080p or less
20
20
  | 'best'; // highest possible resolution
21
21
 
22
- const MAX_FS_VALUES = {
22
+ export const MAX_FS_VALUES = {
23
23
  '90p': 60,
24
24
  '180p': 240,
25
25
  '360p': 920,
26
+ '540p': 2040,
26
27
  '720p': 3600,
27
28
  '1080p': 8192,
28
29
  };
29
30
 
30
31
  /**
31
32
  * Converts pane size into h264 maxFs
32
- * @param {PaneSize} paneSize
33
+ * @param {RemoteVideoResolution} paneSize
33
34
  * @returns {number}
34
35
  */
35
36
  export function getMaxFs(paneSize: RemoteVideoResolution): number {
@@ -89,6 +90,13 @@ export class RemoteMedia extends EventsScope {
89
90
 
90
91
  public readonly id: RemoteMediaId;
91
92
 
93
+ /**
94
+ * The max frame size of the media request, used for logging and media requests.
95
+ * Set by setSizeHint() based on video element dimensions.
96
+ * When > 0, this value takes precedence over options.resolution in sendMediaRequest().
97
+ */
98
+ private maxFrameSize = 0;
99
+
92
100
  /**
93
101
  * Constructs RemoteMedia instance
94
102
  *
@@ -136,15 +144,34 @@ export class RemoteMedia extends EventsScope {
136
144
  fs = MAX_FS_VALUES['180p'];
137
145
  } else if (height < getThresholdHeight(360)) {
138
146
  fs = MAX_FS_VALUES['360p'];
147
+ } else if (height < getThresholdHeight(540)) {
148
+ fs = MAX_FS_VALUES['540p'];
139
149
  } else if (height <= 720) {
140
150
  fs = MAX_FS_VALUES['720p'];
141
151
  } else {
142
152
  fs = MAX_FS_VALUES['1080p'];
143
153
  }
144
154
 
155
+ this.maxFrameSize = fs;
145
156
  this.receiveSlot?.setMaxFs(fs);
146
157
  }
147
158
 
159
+ /**
160
+ * Get the current effective maxFs value that would be used in media requests
161
+ * @returns {number | undefined} The maxFs value, or undefined if no constraints
162
+ */
163
+ public getEffectiveMaxFs(): number | undefined {
164
+ if (this.maxFrameSize > 0) {
165
+ return this.maxFrameSize;
166
+ }
167
+
168
+ if (this.options.resolution) {
169
+ return getMaxFs(this.options.resolution);
170
+ }
171
+
172
+ return undefined;
173
+ }
174
+
148
175
  /**
149
176
  * Invalidates the remote media by clearing the reference to a receive slot and
150
177
  * cancelling the media request.
@@ -185,6 +212,9 @@ export class RemoteMedia extends EventsScope {
185
212
  throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');
186
213
  }
187
214
 
215
+ // Use maxFrameSize from setSizeHint if available, otherwise fallback to options.resolution
216
+ const maxFs = this.getEffectiveMaxFs();
217
+
188
218
  this.mediaRequestId = this.mediaRequestManager.addRequest(
189
219
  {
190
220
  policyInfo: {
@@ -192,9 +222,9 @@ export class RemoteMedia extends EventsScope {
192
222
  csi,
193
223
  },
194
224
  receiveSlots: [this.receiveSlot],
195
- codecInfo: this.options.resolution && {
225
+ codecInfo: maxFs && {
196
226
  codec: 'h264',
197
- maxFs: getMaxFs(this.options.resolution),
227
+ maxFs,
198
228
  },
199
229
  },
200
230
  commit
@@ -215,6 +215,9 @@ export class RemoteMediaGroup {
215
215
  private sendActiveSpeakerMediaRequest(commit: boolean) {
216
216
  this.cancelActiveSpeakerMediaRequest(false);
217
217
 
218
+ // Calculate the effective maxFs based on all unpinned RemoteMedia instances
219
+ const effectiveMaxFs = this.getEffectiveMaxFsForActiveSpeaker();
220
+
218
221
  this.mediaRequestId = this.mediaRequestManager.addRequest(
219
222
  {
220
223
  policyInfo: {
@@ -230,9 +233,9 @@ export class RemoteMediaGroup {
230
233
  receiveSlots: this.unpinnedRemoteMedia.map((remoteMedia) =>
231
234
  remoteMedia.getUnderlyingReceiveSlot()
232
235
  ) as ReceiveSlot[],
233
- codecInfo: this.options.resolution && {
236
+ codecInfo: effectiveMaxFs && {
234
237
  codec: 'h264',
235
- maxFs: getMaxFs(this.options.resolution),
238
+ maxFs: effectiveMaxFs,
236
239
  },
237
240
  },
238
241
  commit
@@ -300,4 +303,36 @@ export class RemoteMediaGroup {
300
303
  this.unpinnedRemoteMedia.includes(remoteMedia) || this.pinnedRemoteMedia.includes(remoteMedia)
301
304
  );
302
305
  }
306
+
307
+ /**
308
+ * Calculate the effective maxFs for the active speaker media request based on unpinned RemoteMedia instances
309
+ * @returns {number | undefined} The calculated maxFs value, or undefined if no constraints
310
+ * @private
311
+ */
312
+ private getEffectiveMaxFsForActiveSpeaker(): number | undefined {
313
+ // Get all effective maxFs values from unpinned RemoteMedia instances
314
+ const maxFsValues = this.unpinnedRemoteMedia
315
+ .map((remoteMedia) => remoteMedia.getEffectiveMaxFs())
316
+ .filter((maxFs) => maxFs !== undefined);
317
+
318
+ // Use the highest maxFs value to ensure we don't under-request resolution for any instance
319
+ if (maxFsValues.length > 0) {
320
+ return Math.max(...maxFsValues);
321
+ }
322
+
323
+ // Fall back to group's resolution option
324
+ if (this.options.resolution) {
325
+ return getMaxFs(this.options.resolution);
326
+ }
327
+
328
+ return undefined;
329
+ }
330
+
331
+ /**
332
+ * Get the current effective maxFs that would be used for the active speaker media request
333
+ * @returns {number | undefined} The effective maxFs value
334
+ */
335
+ public getEffectiveMaxFs(): number | undefined {
336
+ return this.getEffectiveMaxFsForActiveSpeaker();
337
+ }
303
338
  }
@@ -7,10 +7,20 @@ import {
7
7
  StreamState,
8
8
  } from '@webex/internal-media-core';
9
9
 
10
+ /**
11
+ * This class is used to manage the sendSlots for the given media types.
12
+ */
10
13
  export default class SendSlotManager {
11
14
  private readonly slots: Map<MediaType, SendSlot> = new Map();
12
15
  private readonly LoggerProxy: any;
16
+ private readonly sourceStateOverrides: Map<MediaType, StreamState> = new Map();
13
17
 
18
+ /**
19
+ * Constructor for SendSlotManager
20
+ *
21
+ * @param {any} LoggerProxy is used to log the messages
22
+ * @constructor
23
+ */
14
24
  constructor(LoggerProxy: any) {
15
25
  this.LoggerProxy = LoggerProxy;
16
26
  }
@@ -93,7 +103,7 @@ export default class SendSlotManager {
93
103
  public setSourceStateOverride(mediaType: MediaType, state: StreamState | null) {
94
104
  if (mediaType !== MediaType.VideoMain) {
95
105
  throw new Error(
96
- `sendSlotManager cannot set source state override which media type is ${mediaType}`
106
+ `Invalid media type '${mediaType}'. Source state overrides are only applicable to ${MediaType.VideoMain}.`
97
107
  );
98
108
  }
99
109
 
@@ -103,17 +113,39 @@ export default class SendSlotManager {
103
113
  throw new Error(`Slot for ${mediaType} does not exist`);
104
114
  }
105
115
 
116
+ const currentStateOverride = this.getSourceStateOverride(mediaType);
117
+ if (currentStateOverride === state) {
118
+ return;
119
+ }
120
+
106
121
  if (state) {
107
122
  slot.setSourceStateOverride(state);
123
+ this.sourceStateOverrides.set(mediaType, state);
108
124
  } else {
109
125
  slot.clearSourceStateOverride();
126
+ this.sourceStateOverrides.delete(mediaType);
110
127
  }
111
128
 
112
129
  this.LoggerProxy.logger.info(
113
- `SendSlotsManager->setSourceStateOverride#set source state override for ${mediaType} to ${state}`
130
+ `SendSlotManager->setSourceStateOverride#set source state override for ${mediaType} to ${state}`
114
131
  );
115
132
  }
116
133
 
134
+ /**
135
+ * Gets the source state override for the given media type.
136
+ * @param {MediaType} mediaType - The type of media to get the source state override for.
137
+ * @returns {StreamState | null} - The current source state override or null if not set.
138
+ */
139
+ private getSourceStateOverride(mediaType: MediaType): StreamState | null {
140
+ if (mediaType !== MediaType.VideoMain) {
141
+ throw new Error(
142
+ `Invalid media type '${mediaType}'. Source state overrides are only applicable to ${MediaType.VideoMain}.`
143
+ );
144
+ }
145
+
146
+ return this.sourceStateOverrides.get(mediaType) || null;
147
+ }
148
+
117
149
  /**
118
150
  * This method publishes the given stream to the sendSlot for the given mediaType
119
151
  * @param {MediaType} mediaType MediaType of the sendSlot to which a stream needs to be published (AUDIO_MAIN/VIDEO_MAIN/AUDIO_SLIDES/VIDEO_SLIDES)
@@ -140,22 +140,14 @@ export default class Reachability extends EventsScope {
140
140
 
141
141
  /**
142
142
  * Checks if the given subnet is reachable
143
- * @param {string} mediaServerIp - media server ip
143
+ * @param {string} selectedSubnetFirstOctet - selected subnet first octet, e.g. "10" for "10.X.X.X"
144
144
  * @returns {boolean | null} true if reachable, false if not reachable, null if mediaServerIp is not provided
145
145
  * @public
146
146
  * @memberof Reachability
147
147
  */
148
- public isSubnetReachable(mediaServerIp?: string): boolean | null {
149
- if (!mediaServerIp) {
150
- LoggerProxy.logger.error(`Reachability:index#isSubnetReachable --> mediaServerIp is null`);
151
-
152
- return null;
153
- }
154
-
155
- const subnetFirstOctet = mediaServerIp.split('.')[0];
156
-
148
+ public isSubnetReachable(selectedSubnetFirstOctet: string): boolean | null {
157
149
  LoggerProxy.logger.info(
158
- `Reachability:index#isSubnetReachable --> Looking for subnet: ${subnetFirstOctet}.X.X.X`
150
+ `Reachability:index#isSubnetReachable --> Looking for subnet: ${selectedSubnetFirstOctet}.X.X.X`
159
151
  );
160
152
 
161
153
  const matchingReachedClusters = Object.values(this.clusterReachability).reduce(
@@ -167,7 +159,7 @@ export default class Reachability extends EventsScope {
167
159
  const subnet = reachedSubnetsArray[i];
168
160
  const reachedSubnetFirstOctet = subnet.split('.')[0];
169
161
 
170
- if (subnetFirstOctet === reachedSubnetFirstOctet) {
162
+ if (selectedSubnetFirstOctet === reachedSubnetFirstOctet) {
171
163
  acc.add(cluster.name);
172
164
  }
173
165
 
@@ -186,7 +178,7 @@ export default class Reachability extends EventsScope {
186
178
  );
187
179
 
188
180
  LoggerProxy.logger.info(
189
- `Reachability:index#isSubnetReachable --> Found ${matchingReachedClusters.size} clusters that use the subnet ${subnetFirstOctet}.X.X.X`
181
+ `Reachability:index#isSubnetReachable --> Found ${matchingReachedClusters.size} clusters that use the subnet ${selectedSubnetFirstOctet}.X.X.X`
190
182
  );
191
183
 
192
184
  return matchingReachedClusters.size > 0;
@@ -931,10 +923,10 @@ export default class Reachability extends EventsScope {
931
923
 
932
924
  // update expected results counters to include this cluster
933
925
  this.expectedResultsCount[cluster.isVideoMesh ? 'videoMesh' : 'public'].udp +=
934
- cluster.udp.length;
926
+ cluster.udp.length > 0 ? 1 : 0;
935
927
  if (!cluster.isVideoMesh) {
936
- this.expectedResultsCount.public.tcp += cluster.tcp.length;
937
- this.expectedResultsCount.public.xtls += cluster.xtls.length;
928
+ this.expectedResultsCount.public.tcp += cluster.tcp.length > 0 ? 1 : 0;
929
+ this.expectedResultsCount.public.xtls += cluster.xtls.length > 0 ? 1 : 0;
938
930
  }
939
931
  });
940
932
 
@@ -18,16 +18,6 @@ const USER_AGENT_SAFARI_MAC =
18
18
  const USER_AGENT_FIREFOX_MAC =
19
19
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) ' + 'Gecko/20100101 Firefox/87.0';
20
20
 
21
- const mockDetectionObject = {
22
- /* eslint-disable global-require */
23
- getOSName: () => require('os').platform(),
24
- getOSVersion: () => require('os').release(),
25
- /* eslint-enable global-require */
26
- getBrowserName: () => '',
27
- getBrowserVersion: () => '',
28
- isBrowser: () => false,
29
- };
30
-
31
21
  describe('common/browser-detection', () => {
32
22
  it('returns the correct browser name.', () => {
33
23
  assert.equal(
@@ -102,18 +92,4 @@ describe('common/browser-detection', () => {
102
92
  'This browser is NOT Firefox'
103
93
  );
104
94
  });
105
-
106
- it('returns the mock object when there is no userAgent', () => {
107
- Object.defineProperty(global.window.navigator, 'userAgent', {
108
- get: () => undefined,
109
- configurable: true,
110
- });
111
-
112
- const {getBrowserName, getBrowserVersion, getOSName, getOSVersion} = BrowserDetection(null);
113
-
114
- assert.equal(getBrowserName(), mockDetectionObject.getBrowserName());
115
- assert.equal(getBrowserVersion(), mockDetectionObject.getBrowserVersion());
116
- assert.equal(getOSName(), mockDetectionObject.getOSName());
117
- assert.equal(getOSVersion(), mockDetectionObject.getOSVersion());
118
- });
119
95
  });