@webex/plugin-meetings 3.9.0-webinar5k.1 → 3.10.0

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 (138) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.js +24 -0
  4. package/dist/constants.js.map +1 -1
  5. package/dist/controls-options-manager/index.js +22 -5
  6. package/dist/controls-options-manager/index.js.map +1 -1
  7. package/dist/index.js +2 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/interceptors/index.js +7 -0
  10. package/dist/interceptors/index.js.map +1 -1
  11. package/dist/interceptors/locusRouteToken.js +116 -0
  12. package/dist/interceptors/locusRouteToken.js.map +1 -0
  13. package/dist/interpretation/index.js +1 -1
  14. package/dist/interpretation/siLanguage.js +1 -1
  15. package/dist/locus-info/controlsUtils.js +11 -2
  16. package/dist/locus-info/controlsUtils.js.map +1 -1
  17. package/dist/locus-info/index.js +76 -322
  18. package/dist/locus-info/index.js.map +1 -1
  19. package/dist/locus-info/parser.js +4 -1
  20. package/dist/locus-info/parser.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/in-meeting-actions.js +14 -0
  24. package/dist/meeting/in-meeting-actions.js.map +1 -1
  25. package/dist/meeting/index.js +467 -277
  26. package/dist/meeting/index.js.map +1 -1
  27. package/dist/meeting/request.js +177 -14
  28. package/dist/meeting/request.js.map +1 -1
  29. package/dist/meeting/type.js +7 -0
  30. package/dist/meeting/type.js.map +1 -0
  31. package/dist/meeting/util.js +100 -3
  32. package/dist/meeting/util.js.map +1 -1
  33. package/dist/meeting-info/meeting-info-v2.js +29 -21
  34. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  35. package/dist/meetings/index.js +20 -16
  36. package/dist/meetings/index.js.map +1 -1
  37. package/dist/member/index.js +9 -0
  38. package/dist/member/index.js.map +1 -1
  39. package/dist/member/util.js +10 -0
  40. package/dist/member/util.js.map +1 -1
  41. package/dist/members/index.js +10 -7
  42. package/dist/members/index.js.map +1 -1
  43. package/dist/members/util.js +7 -2
  44. package/dist/members/util.js.map +1 -1
  45. package/dist/metrics/constants.js +2 -1
  46. package/dist/metrics/constants.js.map +1 -1
  47. package/dist/multistream/mediaRequestManager.js +1 -1
  48. package/dist/multistream/mediaRequestManager.js.map +1 -1
  49. package/dist/multistream/remoteMedia.js +34 -5
  50. package/dist/multistream/remoteMedia.js.map +1 -1
  51. package/dist/multistream/remoteMediaGroup.js +42 -2
  52. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  53. package/dist/reachability/index.js +3 -3
  54. package/dist/reachability/index.js.map +1 -1
  55. package/dist/types/constants.d.ts +23 -0
  56. package/dist/types/controls-options-manager/index.d.ts +9 -1
  57. package/dist/types/interceptors/index.d.ts +2 -1
  58. package/dist/types/interceptors/locusRouteToken.d.ts +38 -0
  59. package/dist/types/locus-info/index.d.ts +9 -54
  60. package/dist/types/media/properties.d.ts +21 -0
  61. package/dist/types/meeting/in-meeting-actions.d.ts +14 -0
  62. package/dist/types/meeting/index.d.ts +64 -29
  63. package/dist/types/meeting/request.d.ts +42 -0
  64. package/dist/types/meeting/type.d.ts +9 -0
  65. package/dist/types/meeting/util.d.ts +13 -0
  66. package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
  67. package/dist/types/meetings/index.d.ts +3 -1
  68. package/dist/types/member/index.d.ts +1 -0
  69. package/dist/types/member/util.d.ts +5 -0
  70. package/dist/types/members/index.d.ts +12 -11
  71. package/dist/types/members/util.d.ts +8 -4
  72. package/dist/types/metrics/constants.d.ts +1 -0
  73. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  74. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  75. package/dist/webinar/index.js +1 -1
  76. package/package.json +25 -27
  77. package/src/constants.ts +26 -2
  78. package/src/controls-options-manager/index.ts +26 -5
  79. package/src/index.ts +2 -1
  80. package/src/interceptors/index.ts +2 -1
  81. package/src/interceptors/locusRouteToken.ts +80 -0
  82. package/src/locus-info/controlsUtils.ts +18 -0
  83. package/src/locus-info/index.ts +69 -357
  84. package/src/locus-info/parser.ts +5 -1
  85. package/src/media/properties.ts +43 -0
  86. package/src/meeting/in-meeting-actions.ts +29 -0
  87. package/src/meeting/index.ts +296 -87
  88. package/src/meeting/request.ts +141 -0
  89. package/src/meeting/type.ts +9 -0
  90. package/src/meeting/util.ts +107 -3
  91. package/src/meeting-info/meeting-info-v2.ts +24 -5
  92. package/src/meetings/index.ts +15 -22
  93. package/src/member/index.ts +10 -0
  94. package/src/member/util.ts +14 -0
  95. package/src/members/index.ts +20 -10
  96. package/src/members/util.ts +20 -3
  97. package/src/metrics/constants.ts +1 -0
  98. package/src/multistream/mediaRequestManager.ts +7 -7
  99. package/src/multistream/remoteMedia.ts +34 -4
  100. package/src/multistream/remoteMediaGroup.ts +37 -2
  101. package/src/reachability/index.ts +3 -3
  102. package/test/unit/spec/common/browser-detection.js +0 -24
  103. package/test/unit/spec/controls-options-manager/index.js +47 -0
  104. package/test/unit/spec/fixture/locus.js +1 -0
  105. package/test/unit/spec/interceptors/locusRouteToken.ts +87 -0
  106. package/test/unit/spec/locus-info/index.js +80 -361
  107. package/test/unit/spec/locus-info/parser.js +3 -2
  108. package/test/unit/spec/media/properties.ts +137 -0
  109. package/test/unit/spec/meeting/in-meeting-actions.ts +14 -0
  110. package/test/unit/spec/meeting/index.js +637 -53
  111. package/test/unit/spec/meeting/muteState.js +32 -6
  112. package/test/unit/spec/meeting/request.js +21 -0
  113. package/test/unit/spec/meeting/utils.js +171 -18
  114. package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
  115. package/test/unit/spec/meetings/index.js +12 -5
  116. package/test/unit/spec/member/util.js +24 -0
  117. package/test/unit/spec/members/collection.js +120 -0
  118. package/test/unit/spec/members/index.js +107 -2
  119. package/test/unit/spec/members/request.js +55 -0
  120. package/test/unit/spec/members/utils.js +116 -14
  121. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  122. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  123. package/test/unit/spec/reachability/index.ts +158 -3
  124. package/test/unit/spec/roap/turnDiscovery.ts +3 -3
  125. package/dist/hashTree/constants.js +0 -23
  126. package/dist/hashTree/constants.js.map +0 -1
  127. package/dist/hashTree/hashTree.js +0 -516
  128. package/dist/hashTree/hashTree.js.map +0 -1
  129. package/dist/hashTree/hashTreeParser.js +0 -521
  130. package/dist/hashTree/hashTreeParser.js.map +0 -1
  131. package/dist/types/hashTree/constants.d.ts +0 -8
  132. package/dist/types/hashTree/hashTree.d.ts +0 -128
  133. package/dist/types/hashTree/hashTreeParser.d.ts +0 -152
  134. package/src/hashTree/constants.ts +0 -12
  135. package/src/hashTree/hashTree.ts +0 -460
  136. package/src/hashTree/hashTreeParser.ts +0 -556
  137. package/test/unit/spec/hashTree/hashTree.ts +0 -394
  138. package/test/unit/spec/hashTree/hashTreeParser.ts +0 -156
@@ -886,6 +886,44 @@ export default class MeetingRequest extends StatelessWebexPlugin {
886
886
  });
887
887
  }
888
888
 
889
+ /**
890
+ * Extend the current meeting duration.
891
+ *
892
+ * @param {Object} params - Parameters for extending the meeting.
893
+ * @param {string} params.meetingInstanceId - The unique ID of the meeting instance.
894
+ * @param {string} params.participantId - The ID of the participant requesting the extension.
895
+ * @param {number} params.extensionMinutes - The number of minutes to extend the meeting by.
896
+ * @param {string} params.meetingPolicyUrl - The base URL for meeting policy service (dynamic, from locus links)
897
+ * @returns {Promise<any>} A promise that resolves with the server response.
898
+ */
899
+ extendMeeting({
900
+ meetingInstanceId,
901
+ participantId,
902
+ extensionMinutes,
903
+ meetingPolicyUrl,
904
+ }: {
905
+ meetingInstanceId: string;
906
+ participantId: string;
907
+ extensionMinutes: number;
908
+ meetingPolicyUrl: string;
909
+ }) {
910
+ if (!meetingPolicyUrl) {
911
+ return Promise.reject(new Error('meetingPolicyUrl is required'));
912
+ }
913
+ const uri = `${meetingPolicyUrl}/continueMeeting`;
914
+
915
+ // @ts-ignore
916
+ return this.request({
917
+ method: HTTP_VERBS.POST,
918
+ uri,
919
+ body: {
920
+ meetingInstanceId,
921
+ requestParticipantId: participantId,
922
+ extensionMinutes,
923
+ },
924
+ });
925
+ }
926
+
889
927
  /**
890
928
  * Make a network request to enable or disable reactions.
891
929
  * @param {boolean} options.enable - determines if we need to enable or disable.
@@ -985,4 +1023,107 @@ export default class MeetingRequest extends StatelessWebexPlugin {
985
1023
  body: {videoLayout},
986
1024
  });
987
1025
  }
1026
+
1027
+ /**
1028
+ * Sends a request to notify the host of a meeting.
1029
+ * @param {string} siteFullUrl - The site URL.
1030
+ * @param {string} locusId - The locus ID.
1031
+ * @param {string} meetingUuid - The meeting UUID.
1032
+ * @param {Array<string>} displayName - The display names to notify the host about.
1033
+ * @returns {Promise}
1034
+ */
1035
+ notifyHost(siteFullUrl: string, locusId: string, meetingUuid: string, displayName: string[]) {
1036
+ // @ts-ignore
1037
+ return this.request({
1038
+ method: HTTP_VERBS.POST,
1039
+ uri: `https://${siteFullUrl}/wbxappapi/v1/meetings/${meetingUuid}/notifyhost`,
1040
+ body: {
1041
+ displayName,
1042
+ size: displayName?.length,
1043
+ },
1044
+ headers: {
1045
+ locusId,
1046
+ },
1047
+ });
1048
+ }
1049
+
1050
+ /**
1051
+ * Call out to a SIP participant
1052
+ *
1053
+ * @param {any} meetingId - The meeting ID.
1054
+ * @param {any} meetingNumber - The meeting number.
1055
+ * @param {string} address - The SIP address to call out.
1056
+ * @param {string} displayName - The display name for the participant.
1057
+ * @returns {Promise} The API response
1058
+ */
1059
+ public async sipCallOut(meetingId, meetingNumber, address, displayName) {
1060
+ const body: any = {
1061
+ meetingId,
1062
+ meetingNumber,
1063
+ address,
1064
+ displayName,
1065
+ };
1066
+ try {
1067
+ // @ts-ignore
1068
+ const response = await this.request({
1069
+ method: HTTP_VERBS.POST,
1070
+ service: 'hydra',
1071
+ resource: 'meetingParticipants/callout',
1072
+ body,
1073
+ headers: {
1074
+ Accept: 'application/json',
1075
+ },
1076
+ });
1077
+
1078
+ LoggerProxy.logger.info('Meetings:request#sipCallOut --> SIP call-out successful', response);
1079
+
1080
+ return response.body;
1081
+ } catch (err) {
1082
+ LoggerProxy.logger.error(
1083
+ `Meetings:request#sipCallOut --> Error calling out SIP participant, error ${JSON.stringify(
1084
+ err
1085
+ )}`
1086
+ );
1087
+ throw err;
1088
+ }
1089
+ }
1090
+
1091
+ /**
1092
+ * Cancel an ongoing SIP call-out
1093
+ *
1094
+ * @param {string} participantId - The ID of the participant whose SIP call-out should be cancelled.
1095
+ * @returns {Promise} The API response
1096
+ */
1097
+ public async cancelSipCallOut(participantId) {
1098
+ const body = {
1099
+ participantId,
1100
+ };
1101
+
1102
+ try {
1103
+ // @ts-ignore
1104
+ const response = await this.request({
1105
+ method: HTTP_VERBS.POST,
1106
+ service: 'hydra',
1107
+ resource: 'meetingParticipants/cancelCallout',
1108
+ body,
1109
+ headers: {
1110
+ Accept: 'application/json',
1111
+ },
1112
+ });
1113
+
1114
+ LoggerProxy.logger.info(
1115
+ 'Meetings:request#cancelSipCallOut --> SIP call-out cancelled successfully',
1116
+ response
1117
+ );
1118
+
1119
+ return response.body;
1120
+ } catch (err) {
1121
+ LoggerProxy.logger.error(
1122
+ `Meetings:request#cancelSipCallOut --> Error cancelling SIP participant call-out, error ${JSON.stringify(
1123
+ err
1124
+ )}`
1125
+ );
1126
+ throw err;
1127
+ }
1128
+ }
988
1129
  }
@@ -0,0 +1,9 @@
1
+ export type Invitee = {
2
+ memberId: string;
3
+ emailAddress: string;
4
+ email: string;
5
+ phoneNumber: string;
6
+ roles: Array<string>;
7
+ skipEmailValidation?: boolean;
8
+ isInternalNumber?: boolean;
9
+ };
@@ -31,7 +31,6 @@ const MeetingUtil = {
31
31
 
32
32
  // First todo: add check for existance
33
33
  parsed.locus = response.body.locus;
34
- parsed.dataSets = response.body.dataSets;
35
34
  parsed.mediaConnections = response.body.mediaConnections;
36
35
  parsed.locusUrl = parsed.locus.url;
37
36
  parsed.locusId = parsed.locus.url.split('/').pop();
@@ -114,6 +113,28 @@ const MeetingUtil = {
114
113
  return IP_VERSION.unknown;
115
114
  },
116
115
 
116
+ /**
117
+ * Returns CA event labels related to Orpheus ipver parameter that can be sent to CA with any CA event
118
+ * @param {any} webex instance
119
+ * @returns {Array<string>|undefined} array of CA event labels or undefined if no labels should be sent
120
+ */
121
+ getCaEventLabelsForIpVersion(webex: any): Array<string> | undefined {
122
+ const ipver = MeetingUtil.getIpVersion(webex);
123
+
124
+ switch (ipver) {
125
+ case IP_VERSION.unknown:
126
+ return undefined;
127
+ case IP_VERSION.only_ipv4:
128
+ return ['hasIpv4_true'];
129
+ case IP_VERSION.only_ipv6:
130
+ return ['hasIpv6_true'];
131
+ case IP_VERSION.ipv4_and_ipv6:
132
+ return ['hasIpv4_true', 'hasIpv6_true'];
133
+ default:
134
+ return undefined;
135
+ }
136
+ },
137
+
117
138
  joinMeeting: async (meeting, options) => {
118
139
  if (!meeting) {
119
140
  return Promise.reject(new ParameterError('You need a meeting object.'));
@@ -196,6 +217,17 @@ const MeetingUtil = {
196
217
  });
197
218
 
198
219
  return parsed;
220
+ })
221
+ .catch((err) => {
222
+ webex.internal.newMetrics.submitClientEvent({
223
+ name: 'client.locus.join.response',
224
+ payload: {
225
+ identifiers: {meetingLookupUrl: meeting.meetingInfo?.meetingLookupUrl},
226
+ },
227
+ options: {meetingId: meeting.id, rawError: err},
228
+ });
229
+
230
+ throw err;
199
231
  });
200
232
  },
201
233
 
@@ -207,6 +239,10 @@ const MeetingUtil = {
207
239
  meeting.simultaneousInterpretation.cleanUp();
208
240
  meeting.locusMediaRequest = undefined;
209
241
 
242
+ meeting.webex?.internal?.newMetrics?.callDiagnosticMetrics?.clearEventLimitsForCorrelationId(
243
+ meeting.correlationId
244
+ );
245
+
210
246
  // make sure we send last metrics before we close the peerconnection
211
247
  const stopStatsAnalyzer = meeting.statsAnalyzer
212
248
  ? meeting.statsAnalyzer.stopAnalyzer()
@@ -327,10 +363,57 @@ const MeetingUtil = {
327
363
  meeting.resourceId = meeting.resourceId || options.resourceId;
328
364
 
329
365
  if (meeting.requiredCaptcha) {
330
- return Promise.reject(new CaptchaError());
366
+ const errorToThrow = new CaptchaError();
367
+
368
+ // @ts-ignore
369
+ webex.internal.newMetrics.submitClientEvent({
370
+ name: 'client.meetinginfo.response',
371
+ options: {
372
+ meetingId: meeting.id,
373
+ },
374
+ payload: {
375
+ errors: [
376
+ {
377
+ fatal: false,
378
+ category: 'expected',
379
+ name: 'other',
380
+ shownToUser: false,
381
+ errorCode: errorToThrow.code,
382
+ errorDescription: errorToThrow.name,
383
+ rawErrorMessage: errorToThrow.sdkMessage,
384
+ },
385
+ ],
386
+ },
387
+ });
388
+
389
+ return Promise.reject(errorToThrow);
331
390
  }
391
+
332
392
  if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
333
- return Promise.reject(new PasswordError());
393
+ const errorToThrow = new PasswordError();
394
+
395
+ // @ts-ignore
396
+ webex.internal.newMetrics.submitClientEvent({
397
+ name: 'client.meetinginfo.response',
398
+ options: {
399
+ meetingId: meeting.id,
400
+ },
401
+ payload: {
402
+ errors: [
403
+ {
404
+ fatal: false,
405
+ category: 'expected',
406
+ name: 'other',
407
+ shownToUser: false,
408
+ errorCode: errorToThrow.code,
409
+ errorDescription: errorToThrow.name,
410
+ rawErrorMessage: errorToThrow.sdkMessage,
411
+ },
412
+ ],
413
+ },
414
+ });
415
+
416
+ return Promise.reject(errorToThrow);
334
417
  }
335
418
 
336
419
  if (options.pin) {
@@ -541,11 +624,29 @@ const MeetingUtil = {
541
624
  canStartManualCaption: (displayHints) =>
542
625
  displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_START),
543
626
 
627
+ isLocalRecordingStarted: (displayHints) =>
628
+ displayHints.includes(DISPLAY_HINTS.LOCAL_RECORDING_STATUS_STARTED),
629
+
630
+ isLocalRecordingStopped: (displayHints) =>
631
+ displayHints.includes(DISPLAY_HINTS.LOCAL_RECORDING_STATUS_STOPPED),
632
+
633
+ isLocalRecordingPaused: (displayHints) =>
634
+ displayHints.includes(DISPLAY_HINTS.LOCAL_RECORDING_STATUS_PAUSED),
635
+
636
+ isLocalStreamingStarted: (displayHints) =>
637
+ displayHints.includes(DISPLAY_HINTS.STREAMING_STATUS_STARTED),
638
+
639
+ isLocalStreamingStopped: (displayHints) =>
640
+ displayHints.includes(DISPLAY_HINTS.STREAMING_STATUS_STOPPED),
641
+
544
642
  canStopManualCaption: (displayHints) => displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STOP),
545
643
 
546
644
  isManualCaptionActive: (displayHints) =>
547
645
  displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STATUS_ACTIVE),
548
646
 
647
+ isSpokenLanguageAutoDetectionEnabled: (displayHints) =>
648
+ displayHints.includes(DISPLAY_HINTS.SPOKEN_LANGUAGE_AUTO_DETECTION_ENABLED),
649
+
549
650
  isWebexAssistantActive: (displayHints) =>
550
651
  displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE),
551
652
 
@@ -559,6 +660,9 @@ const MeetingUtil = {
559
660
 
560
661
  waitingForOthersToJoin: (displayHints) => displayHints.includes(DISPLAY_HINTS.WAITING_FOR_OTHERS),
561
662
 
663
+ showAutoEndMeetingWarning: (displayHints) =>
664
+ displayHints.includes(DISPLAY_HINTS.SHOW_AUTO_END_MEETING_WARNING),
665
+
562
666
  canSendReactions: (originalValue, displayHints) => {
563
667
  if (displayHints.includes(DISPLAY_HINTS.REACTIONS_ACTIVE)) {
564
668
  return true;
@@ -371,6 +371,7 @@ export default class MeetingInfoV2 {
371
371
  * @param {String} conversationUrl conversationUrl to start adhoc meeting on
372
372
  * @param {String} installedOrgID org ID of user's machine
373
373
  * @param {Boolean} enableStaticMeetingLink whether or not to enable static meeting link
374
+ * @param {String} classificationId need it to start adhoc meeting if space support classification
374
375
  * @returns {Promise} returns a meeting info object
375
376
  * @public
376
377
  * @memberof MeetingInfo
@@ -379,7 +380,8 @@ export default class MeetingInfoV2 {
379
380
  conversationUrl: string,
380
381
  installedOrgID?: string,
381
382
  // setting this to true enables static meeting link
382
- enableStaticMeetingLink = false
383
+ enableStaticMeetingLink = false,
384
+ classificationId = undefined
383
385
  ) {
384
386
  const getInvitees = (particpants = []) => {
385
387
  const invitees = [];
@@ -407,6 +409,7 @@ export default class MeetingInfoV2 {
407
409
  invitees: getInvitees(conversation.participants?.items),
408
410
  installedOrgID,
409
411
  schedule: enableStaticMeetingLink,
412
+ classificationId,
410
413
  };
411
414
 
412
415
  if (installedOrgID) {
@@ -429,16 +432,26 @@ export default class MeetingInfoV2 {
429
432
  * Creates adhoc space meetings for a space by fetching the conversation infomation
430
433
  * @param {String} conversationUrl conversationUrl to start adhoc meeting on
431
434
  * @param {String} installedOrgID org ID of user's machine
435
+ * @param {String} classificationId if space is support classification, it needs provide it during start instant meeting
432
436
  * @returns {Promise} returns a meeting info object
433
437
  * @public
434
438
  * @memberof MeetingInfo
435
439
  */
436
- async createAdhocSpaceMeeting(conversationUrl: string, installedOrgID?: string) {
440
+ async createAdhocSpaceMeeting(
441
+ conversationUrl: string,
442
+ installedOrgID?: string,
443
+ classificationId?: string
444
+ ) {
437
445
  if (!this.webex.meetings.preferredWebexSite) {
438
446
  throw Error('No preferred webex site found');
439
447
  }
440
448
 
441
- return this.createAdhocSpaceMeetingOrEnableStaticMeetingLink(conversationUrl, installedOrgID)
449
+ return this.createAdhocSpaceMeetingOrEnableStaticMeetingLink(
450
+ conversationUrl,
451
+ installedOrgID,
452
+ false,
453
+ classificationId
454
+ )
442
455
  .then((requestResult) => {
443
456
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
444
457
 
@@ -618,6 +631,7 @@ export default class MeetingInfoV2 {
618
631
  * @param {Object} options
619
632
  * @param {String} registrationId
620
633
  * @param {String} fullSiteUrl
634
+ * @param {String} classificationId
621
635
  * @returns {Promise} returns a meeting info object
622
636
  * @public
623
637
  * @memberof MeetingInfo
@@ -635,7 +649,8 @@ export default class MeetingInfoV2 {
635
649
  extraParams: object = {},
636
650
  options: {meetingId?: string; sendCAevents?: boolean} = {},
637
651
  registrationId: string = null,
638
- fullSiteUrl: string = null
652
+ fullSiteUrl: string = null,
653
+ classificationId: string = null
639
654
  ) {
640
655
  const {meetingId, sendCAevents} = options;
641
656
 
@@ -650,7 +665,11 @@ export default class MeetingInfoV2 {
650
665
  this.webex.config.meetings.experimental.enableAdhocMeetings &&
651
666
  this.webex.meetings.preferredWebexSite
652
667
  ) {
653
- return this.createAdhocSpaceMeeting(destinationType.destination, installedOrgID);
668
+ return this.createAdhocSpaceMeeting(
669
+ destinationType.destination,
670
+ installedOrgID,
671
+ classificationId
672
+ );
654
673
  }
655
674
 
656
675
  const body = await MeetingInfoUtil.getRequestBody({
@@ -66,7 +66,6 @@ import JoinWebinarError from '../common/errors/join-webinar-error';
66
66
  import {SpaceIDDeprecatedError} from '../common/errors/webex-errors';
67
67
  import NoMeetingInfoError from '../common/errors/no-meeting-info';
68
68
  import JoinForbiddenError from '../common/errors/join-forbidden-error';
69
- import {DataSet} from '../hashTree/hashTreeParser';
70
69
 
71
70
  let mediaLogger;
72
71
 
@@ -408,13 +407,6 @@ export default class Meetings extends WebexPlugin {
408
407
  * @memberof Meetings
409
408
  */
410
409
  getCorrespondingMeetingByLocus(data) {
411
- if (data.eventType === 'locus.state_message' && data.stateElementsMessage?.locusUrl) {
412
- return this.meetingCollection.getByKey(
413
- MEETING_KEY.LOCUS_URL,
414
- data.stateElementsMessage.locusUrl
415
- );
416
- }
417
-
418
410
  // getting meeting by correlationId. This will happen for the new event
419
411
  // Either the locus
420
412
  // TODO : Add check for the callBack Address
@@ -453,10 +445,7 @@ export default class Meetings extends WebexPlugin {
453
445
  * @private
454
446
  * @memberof Meetings
455
447
  */
456
- private handleLocusEvent(
457
- data: {locusUrl: string; locus: any; dataSets?: DataSet[]},
458
- useRandomDelayForInfo = false
459
- ) {
448
+ private handleLocusEvent(data: {locusUrl: string; locus: any}, useRandomDelayForInfo = false) {
460
449
  let meeting = this.getCorrespondingMeetingByLocus(data);
461
450
 
462
451
  // Special case when locus has got replaced, This only happend once if a replace locus exists
@@ -535,7 +524,7 @@ export default class Meetings extends WebexPlugin {
535
524
  meeting = newMeeting;
536
525
 
537
526
  // It's a new meeting so initialize the locus data
538
- meeting.locusInfo.initialSetup(data.locus, data.dataSets);
527
+ meeting.locusInfo.initialSetup(data.locus);
539
528
  this.checkHandleBreakoutLocus(data.locus);
540
529
  })
541
530
  .catch((e) => {
@@ -1342,6 +1331,7 @@ export default class Meetings extends WebexPlugin {
1342
1331
  * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1343
1332
  * @param {String} [meetingLookupUrl] - meeting info prefetch url
1344
1333
  * @param {string} sessionCorrelationId - the optional specified sessionCorrelationId (callStateForMetrics.sessionCorrelationId) can be provided instead
1334
+ * @param {String} classificationId - If space support classification, it will provide it while start instant meeting
1345
1335
  * @returns {Promise<Meeting>} A new Meeting.
1346
1336
  * @public
1347
1337
  * @memberof Meetings
@@ -1356,7 +1346,8 @@ export default class Meetings extends WebexPlugin {
1356
1346
  callStateForMetrics: CallStateForMetrics = undefined,
1357
1347
  meetingInfo = undefined,
1358
1348
  meetingLookupUrl = undefined,
1359
- sessionCorrelationId: string = undefined
1349
+ sessionCorrelationId: string = undefined,
1350
+ classificationId: string = undefined
1360
1351
  ) {
1361
1352
  // Validate meeting information based on the provided destination and
1362
1353
  // type. This must be performed prior to determining if the meeting is
@@ -1426,7 +1417,8 @@ export default class Meetings extends WebexPlugin {
1426
1417
  callStateForMetrics,
1427
1418
  failOnMissingMeetingInfo,
1428
1419
  meetingInfo,
1429
- meetingLookupUrl
1420
+ meetingLookupUrl,
1421
+ classificationId
1430
1422
  ).then((createdMeeting: any) => {
1431
1423
  // If the meeting was successfully created.
1432
1424
  if (createdMeeting && createdMeeting.on) {
@@ -1540,6 +1532,7 @@ export default class Meetings extends WebexPlugin {
1540
1532
  * @param {Boolean} failOnMissingMeetingInfo - whether to throw an error if meeting info fails to fetch (for calls that are not 1:1 or content share)
1541
1533
  * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1542
1534
  * @param {String} [meetingLookupUrl] - meeting info prefetch url
1535
+ * @param {String} classificationId see create()
1543
1536
  * @returns {Promise} a new meeting instance complete with meeting info and destination
1544
1537
  * @private
1545
1538
  * @memberof Meetings
@@ -1552,7 +1545,8 @@ export default class Meetings extends WebexPlugin {
1552
1545
  callStateForMetrics: CallStateForMetrics = undefined,
1553
1546
  failOnMissingMeetingInfo = false,
1554
1547
  meetingInfo = undefined,
1555
- meetingLookupUrl = undefined
1548
+ meetingLookupUrl = undefined,
1549
+ classificationId = undefined
1556
1550
  ) {
1557
1551
  const meeting = new Meeting(
1558
1552
  {
@@ -1571,11 +1565,12 @@ export default class Meetings extends WebexPlugin {
1571
1565
  {
1572
1566
  // @ts-ignore
1573
1567
  parent: this.webex,
1568
+ },
1569
+ (newMeeting) => {
1570
+ this.meetingCollection.set(newMeeting);
1574
1571
  }
1575
1572
  );
1576
1573
 
1577
- this.meetingCollection.set(meeting);
1578
-
1579
1574
  try {
1580
1575
  // if no participant has joined the scheduled meeting (meaning meeting is not active) and we get a locusEvent,
1581
1576
  // it means the meeting will start in 5-6 min. In that case, we want to fetchMeetingInfo
@@ -1599,6 +1594,7 @@ export default class Meetings extends WebexPlugin {
1599
1594
  // @ts-ignore
1600
1595
  const {enableUnifiedMeetings} = this.config.experimental;
1601
1596
  const meetingInfoOptions = {
1597
+ classificationId,
1602
1598
  extraParams: infoExtraParams,
1603
1599
  sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
1604
1600
  };
@@ -1835,10 +1831,7 @@ export default class Meetings extends WebexPlugin {
1835
1831
  }
1836
1832
 
1837
1833
  const associateBreakoutLocus = this.breakoutLocusForHandleLater[existIndex];
1838
- this.handleLocusEvent({
1839
- locus: associateBreakoutLocus,
1840
- locusUrl: associateBreakoutLocus.url,
1841
- });
1834
+ this.handleLocusEvent({locus: associateBreakoutLocus, locusUrl: associateBreakoutLocus.url});
1842
1835
  this.breakoutLocusForHandleLater.splice(existIndex, 1);
1843
1836
  }
1844
1837
 
@@ -42,6 +42,7 @@ export default class Member {
42
42
  status: any;
43
43
  supportsBreakouts: boolean;
44
44
  supportsInterpretation: boolean;
45
+ supportsSingleUserAutoEndMeeting: boolean;
45
46
  supportLiveAnnotation: boolean;
46
47
  type: any;
47
48
  namespace = MEETINGS;
@@ -130,6 +131,13 @@ export default class Member {
130
131
  * @memberof Member
131
132
  */
132
133
  this.supportsBreakouts = null;
134
+ /**
135
+ * @instance
136
+ * @type {Boolean}
137
+ * @public
138
+ * @memberof Member
139
+ */
140
+ this.supportsSingleUserAutoEndMeeting = null;
133
141
  /**
134
142
  * @instance
135
143
  * @type {Boolean}
@@ -339,6 +347,8 @@ export default class Member {
339
347
  this.isVideoMuted = MemberUtil.isVideoMuted(participant);
340
348
  this.isHandRaised = MemberUtil.isHandRaised(participant);
341
349
  this.supportsBreakouts = MemberUtil.isBreakoutsSupported(participant);
350
+ this.supportsSingleUserAutoEndMeeting =
351
+ MemberUtil.isSupportsSingleUserAutoEndMeeting(participant);
342
352
  this.supportsInterpretation = MemberUtil.isInterpretationSupported(participant);
343
353
  this.supportLiveAnnotation = MemberUtil.isLiveAnnotationSupported(participant);
344
354
  this.isGuest = MemberUtil.isGuest(participant);
@@ -207,6 +207,20 @@ const MemberUtil = {
207
207
  return !participant.doesNotSupportBreakouts;
208
208
  },
209
209
 
210
+ /**
211
+ * @param {Object} participant - The locus participant object.
212
+ * @returns {Boolean}
213
+ */
214
+ isSupportsSingleUserAutoEndMeeting: (participant) => {
215
+ if (!participant) {
216
+ throw new ParameterError(
217
+ 'Single user auto end meeting support could not be processed, participant is undefined.'
218
+ );
219
+ }
220
+
221
+ return !participant.doesNotSupportSingleUserAutoEndMeeting;
222
+ },
223
+
210
224
  /**
211
225
  * @param {Object} participant - The locus participant object.
212
226
  * @returns {Boolean}
@@ -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
@@ -387,7 +388,9 @@ export default class Members extends StatelessWebexPlugin {
387
388
  * when new participant updates come in, both delta and full participants, update them in members collection
388
389
  * delta object in the event will have {updated, added} and full will be the full membersCollection
389
390
  * @param {Object} payload
390
- * @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
391
394
  * @returns {undefined}
392
395
  * @private
393
396
  * @memberof Members
@@ -824,18 +827,18 @@ export default class Members extends StatelessWebexPlugin {
824
827
 
825
828
  /**
826
829
  * Adds a guest Member to the associated meeting
827
- * @param {String} invitee
830
+ * @param {Invitee} invitee
828
831
  * @param {Boolean} [alertIfActive]
829
832
  * @returns {Promise}
830
833
  * @memberof Members
831
834
  */
832
- addMember(invitee: any, alertIfActive?: boolean) {
835
+ addMember(invitee: Invitee, alertIfActive?: boolean) {
833
836
  if (!this.locusUrl) {
834
837
  return Promise.reject(
835
838
  new ParameterError('The associated locus url for this meeting object must be defined.')
836
839
  );
837
840
  }
838
- if (MembersUtil.isInvalidInvitee(invitee)) {
841
+ if (invitee?.skipEmailValidation !== true && MembersUtil.isInvalidInvitee(invitee)) {
839
842
  return Promise.reject(
840
843
  new ParameterError(
841
844
  'The invitee must be defined with either a valid email, emailAddress or phoneNumber property.'
@@ -849,11 +852,11 @@ export default class Members extends StatelessWebexPlugin {
849
852
 
850
853
  /**
851
854
  * Cancels an outgoing PSTN call to the associated meeting
852
- * @param {String} invitee
855
+ * @param {Invitee} invitee
853
856
  * @returns {Promise}
854
857
  * @memberof Members
855
858
  */
856
- cancelPhoneInvite(invitee: any) {
859
+ cancelPhoneInvite(invitee: Invitee) {
857
860
  if (!this.locusUrl) {
858
861
  return Promise.reject(
859
862
  new ParameterError('The associated locus url for this meeting object must be defined.')
@@ -871,13 +874,13 @@ export default class Members extends StatelessWebexPlugin {
871
874
 
872
875
  /**
873
876
  * Cancels an SIP/phone call to the associated meeting
874
- * @param {Object} invitee
877
+ * @param {Invitee} invitee
875
878
  * @param {String} invitee.memberId - The memberId of the invitee
876
879
  * @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
877
880
  * @returns {Promise}
878
881
  * @memberof Members
879
882
  */
880
- cancelInviteByMemberId(invitee: {memberId: string; isInternalNumber?: boolean}) {
883
+ cancelInviteByMemberId(invitee: Invitee) {
881
884
  if (!this.locusUrl) {
882
885
  return Promise.reject(
883
886
  new ParameterError('The associated locus url for this meeting object must be defined.')
@@ -1204,11 +1207,17 @@ export default class Members extends StatelessWebexPlugin {
1204
1207
  * @param {string} memberId - id of the participant who is receiving request
1205
1208
  * @param {string} requestingParticipantId - id of the participant who is sending request (optional)
1206
1209
  * @param {string} [alias] - alias name
1210
+ * @param {string} [suffix] - name suffix (optional)
1207
1211
  * @returns {Promise}
1208
1212
  * @public
1209
1213
  * @memberof Members
1210
1214
  */
1211
- public editDisplayName(memberId: string, requestingParticipantId: string, alias: string) {
1215
+ public editDisplayName(
1216
+ memberId: string,
1217
+ requestingParticipantId: string,
1218
+ alias: string,
1219
+ suffix?: string
1220
+ ) {
1212
1221
  if (!this.locusUrl) {
1213
1222
  return Promise.reject(
1214
1223
  new ParameterError(
@@ -1228,7 +1237,8 @@ export default class Members extends StatelessWebexPlugin {
1228
1237
  memberId,
1229
1238
  requestingParticipantId,
1230
1239
  alias,
1231
- locusUrl
1240
+ locusUrl,
1241
+ suffix
1232
1242
  );
1233
1243
 
1234
1244
  return this.membersRequest.editDisplayNameMember(options);