@webex/plugin-meetings 3.8.1-web-workers-keepalive.1 → 3.9.0-multipleLLM.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.js +26 -2
  4. package/dist/constants.js.map +1 -1
  5. package/dist/interpretation/index.js +1 -1
  6. package/dist/interpretation/siLanguage.js +1 -1
  7. package/dist/locus-info/index.js +77 -95
  8. package/dist/locus-info/index.js.map +1 -1
  9. package/dist/locus-info/parser.js +4 -1
  10. package/dist/locus-info/parser.js.map +1 -1
  11. package/dist/media/properties.js +53 -5
  12. package/dist/media/properties.js.map +1 -1
  13. package/dist/meeting/brbState.js +14 -12
  14. package/dist/meeting/brbState.js.map +1 -1
  15. package/dist/meeting/in-meeting-actions.js +8 -0
  16. package/dist/meeting/in-meeting-actions.js.map +1 -1
  17. package/dist/meeting/index.js +443 -225
  18. package/dist/meeting/index.js.map +1 -1
  19. package/dist/meeting/muteState.js +2 -5
  20. package/dist/meeting/muteState.js.map +1 -1
  21. package/dist/meeting/request.js +44 -0
  22. package/dist/meeting/request.js.map +1 -1
  23. package/dist/meeting/request.type.js.map +1 -1
  24. package/dist/meeting/type.js +7 -0
  25. package/dist/meeting/type.js.map +1 -0
  26. package/dist/meeting/util.js +98 -13
  27. package/dist/meeting/util.js.map +1 -1
  28. package/dist/meeting-info/meeting-info-v2.js +29 -21
  29. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  30. package/dist/meetings/index.js +18 -10
  31. package/dist/meetings/index.js.map +1 -1
  32. package/dist/member/index.js.map +1 -1
  33. package/dist/member/types.js.map +1 -1
  34. package/dist/members/collection.js +13 -0
  35. package/dist/members/collection.js.map +1 -1
  36. package/dist/members/index.js +53 -29
  37. package/dist/members/index.js.map +1 -1
  38. package/dist/members/request.js +3 -3
  39. package/dist/members/request.js.map +1 -1
  40. package/dist/members/util.js +25 -8
  41. package/dist/members/util.js.map +1 -1
  42. package/dist/metrics/constants.js +2 -1
  43. package/dist/metrics/constants.js.map +1 -1
  44. package/dist/multistream/mediaRequestManager.js +1 -1
  45. package/dist/multistream/mediaRequestManager.js.map +1 -1
  46. package/dist/multistream/remoteMedia.js +34 -5
  47. package/dist/multistream/remoteMedia.js.map +1 -1
  48. package/dist/multistream/remoteMediaGroup.js +42 -2
  49. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  50. package/dist/multistream/sendSlotManager.js +32 -2
  51. package/dist/multistream/sendSlotManager.js.map +1 -1
  52. package/dist/reachability/index.js +3 -3
  53. package/dist/reachability/index.js.map +1 -1
  54. package/dist/types/constants.d.ts +24 -0
  55. package/dist/types/locus-info/index.d.ts +54 -10
  56. package/dist/types/media/properties.d.ts +21 -0
  57. package/dist/types/meeting/brbState.d.ts +0 -1
  58. package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
  59. package/dist/types/meeting/index.d.ts +51 -20
  60. package/dist/types/meeting/request.d.ts +18 -1
  61. package/dist/types/meeting/request.type.d.ts +74 -0
  62. package/dist/types/meeting/type.d.ts +9 -0
  63. package/dist/types/meeting/util.d.ts +13 -3
  64. package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
  65. package/dist/types/meetings/index.d.ts +3 -1
  66. package/dist/types/member/types.d.ts +1 -0
  67. package/dist/types/members/collection.d.ts +6 -0
  68. package/dist/types/members/index.d.ts +22 -9
  69. package/dist/types/members/request.d.ts +1 -1
  70. package/dist/types/members/util.d.ts +13 -6
  71. package/dist/types/metrics/constants.d.ts +1 -0
  72. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  73. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  74. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  75. package/dist/webinar/index.js +1 -1
  76. package/package.json +23 -24
  77. package/src/constants.ts +25 -2
  78. package/src/locus-info/index.ts +133 -96
  79. package/src/locus-info/parser.ts +5 -1
  80. package/src/media/properties.ts +43 -0
  81. package/src/meeting/brbState.ts +9 -7
  82. package/src/meeting/in-meeting-actions.ts +17 -0
  83. package/src/meeting/index.ts +273 -42
  84. package/src/meeting/muteState.ts +2 -6
  85. package/src/meeting/request.ts +39 -0
  86. package/src/meeting/request.type.ts +64 -0
  87. package/src/meeting/type.ts +9 -0
  88. package/src/meeting/util.ts +114 -22
  89. package/src/meeting-info/meeting-info-v2.ts +24 -5
  90. package/src/meetings/index.ts +12 -5
  91. package/src/member/index.ts +1 -0
  92. package/src/member/types.ts +1 -0
  93. package/src/members/collection.ts +11 -0
  94. package/src/members/index.ts +51 -15
  95. package/src/members/request.ts +2 -2
  96. package/src/members/util.ts +34 -6
  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/multistream/sendSlotManager.ts +34 -2
  102. package/src/reachability/index.ts +3 -3
  103. package/test/unit/spec/locus-info/index.js +229 -98
  104. package/test/unit/spec/locus-info/parser.js +3 -2
  105. package/test/unit/spec/media/properties.ts +137 -0
  106. package/test/unit/spec/meeting/brbState.ts +9 -9
  107. package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
  108. package/test/unit/spec/meeting/index.js +1022 -93
  109. package/test/unit/spec/meeting/muteState.js +32 -6
  110. package/test/unit/spec/meeting/request.js +92 -0
  111. package/test/unit/spec/meeting/utils.js +167 -17
  112. package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
  113. package/test/unit/spec/meetings/index.js +12 -1
  114. package/test/unit/spec/members/collection.js +120 -0
  115. package/test/unit/spec/members/index.js +140 -12
  116. package/test/unit/spec/members/request.js +57 -2
  117. package/test/unit/spec/members/utils.js +139 -17
  118. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  119. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  120. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  121. package/test/unit/spec/reachability/index.ts +158 -1
@@ -32,6 +32,7 @@ import {
32
32
  BrbOptions,
33
33
  ToggleReactionsOptions,
34
34
  PostMeetingDataConsentOptions,
35
+ SynchronizeVideoLayout,
35
36
  } from './request.type';
36
37
  import MeetingUtil from './util';
37
38
  import {AnnotationInfo} from '../annotation/annotation.types';
@@ -969,4 +970,42 @@ export default class MeetingRequest extends StatelessWebexPlugin {
969
970
  },
970
971
  });
971
972
  }
973
+
974
+ /**
975
+ * Synchronize the stage for a meeting
976
+ *
977
+ * @param {LocusUrl} locusUrl The locus URL
978
+ * @param {SetStageVideoLayout} videoLayout The video layout to synchronize
979
+ * @returns {Promise} The locus request
980
+ */
981
+ synchronizeStage(locusUrl: string, videoLayout: SynchronizeVideoLayout) {
982
+ return this.locusDeltaRequest({
983
+ method: HTTP_VERBS.PATCH,
984
+ uri: `${locusUrl}/${CONTROLS}`,
985
+ body: {videoLayout},
986
+ });
987
+ }
988
+
989
+ /**
990
+ * Sends a request to notify the host of a meeting.
991
+ * @param {string} siteFullUrl - The site URL.
992
+ * @param {string} locusId - The locus ID.
993
+ * @param {string} meetingUuid - The meeting UUID.
994
+ * @param {Array<string>} displayName - The display names to notify the host about.
995
+ * @returns {Promise}
996
+ */
997
+ notifyHost(siteFullUrl: string, locusId: string, meetingUuid: string, displayName: string[]) {
998
+ // @ts-ignore
999
+ return this.request({
1000
+ method: HTTP_VERBS.POST,
1001
+ uri: `https://${siteFullUrl}/wbxappapi/v1/meetings/${meetingUuid}/notifyhost`,
1002
+ body: {
1003
+ displayName,
1004
+ size: displayName?.length,
1005
+ },
1006
+ headers: {
1007
+ locusId,
1008
+ },
1009
+ });
1010
+ }
972
1011
  }
@@ -25,3 +25,67 @@ export type PostMeetingDataConsentOptions = {
25
25
  deviceUrl: string;
26
26
  selfId: string;
27
27
  };
28
+
29
+ export type StageCustomLogoPositions =
30
+ | 'LowerLeft'
31
+ | 'LowerMiddle'
32
+ | 'LowerRight'
33
+ | 'UpperLeft'
34
+ | 'UpperMiddle'
35
+ | 'UpperRight';
36
+
37
+ export type StageNameLabelType = 'Primary' | 'PrimaryInverted' | 'Secondary' | 'SecondaryInverted';
38
+
39
+ export type StageCustomBackground = {
40
+ url: string;
41
+ [others: string]: unknown;
42
+ };
43
+
44
+ export type StageCustomLogo = {
45
+ url: string;
46
+ position: StageCustomLogoPositions;
47
+ [others: string]: unknown;
48
+ };
49
+
50
+ export type StageCustomNameLabel = {
51
+ accentColor: string;
52
+ background: {color: string};
53
+ border: {color: string};
54
+ content: {displayName: {color: string}; subtitle: {color: string}};
55
+ decoration: {color: string};
56
+ fadeOut?: {delay: number};
57
+ type: StageNameLabelType;
58
+ [others: string]: unknown;
59
+ };
60
+
61
+ export type SetStageOptions = {
62
+ activeSpeakerProportion?: number;
63
+ customBackground?: StageCustomBackground;
64
+ customLogo?: StageCustomLogo;
65
+ customNameLabel?: StageCustomNameLabel;
66
+ importantParticipants?: {mainCsi: number; participantId: string}[];
67
+ lockAttendeeViewOnStage?: boolean;
68
+ showActiveSpeaker?: boolean;
69
+ };
70
+
71
+ export type SetStageVideoLayout = {
72
+ overrideDefault: true;
73
+ lockAttendeeViewOnStageOnly: boolean;
74
+ stageParameters: {
75
+ importantParticipants?: {participantId: string; mainCsi: number; order: number}[];
76
+ showActiveSpeaker: {show: boolean; order: number};
77
+ activeSpeakerProportion: number;
78
+ stageManagerType: number;
79
+ };
80
+ customLayouts?: {
81
+ background?: StageCustomBackground;
82
+ logo?: StageCustomLogo;
83
+ };
84
+ nameLabelStyle?: StageCustomNameLabel;
85
+ };
86
+
87
+ export type UnsetStageVideoLayout = {
88
+ overrideDefault: false;
89
+ };
90
+
91
+ export type SynchronizeVideoLayout = SetStageVideoLayout | UnsetStageVideoLayout;
@@ -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
+ };
@@ -59,18 +59,16 @@ const MeetingUtil = {
59
59
  );
60
60
  }
61
61
 
62
- return meeting.locusMediaRequest
63
- .send({
64
- type: 'LocalMute',
65
- selfUrl: meeting.selfUrl,
66
- mediaId: meeting.mediaId,
67
- sequence: meeting.locusInfo.sequence,
68
- muteOptions: {
69
- audioMuted,
70
- videoMuted,
71
- },
72
- })
73
- .then((response) => response?.body?.locus);
62
+ return meeting.locusMediaRequest.send({
63
+ type: 'LocalMute',
64
+ selfUrl: meeting.selfUrl,
65
+ mediaId: meeting.mediaId,
66
+ sequence: meeting.locusInfo.sequence,
67
+ muteOptions: {
68
+ audioMuted,
69
+ videoMuted,
70
+ },
71
+ });
74
72
  },
75
73
 
76
74
  hasOwner: (info) => info && info.owner,
@@ -115,6 +113,28 @@ const MeetingUtil = {
115
113
  return IP_VERSION.unknown;
116
114
  },
117
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
+
118
138
  joinMeeting: async (meeting, options) => {
119
139
  if (!meeting) {
120
140
  return Promise.reject(new ParameterError('You need a meeting object.'));
@@ -197,6 +217,17 @@ const MeetingUtil = {
197
217
  });
198
218
 
199
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;
200
231
  });
201
232
  },
202
233
 
@@ -208,6 +239,10 @@ const MeetingUtil = {
208
239
  meeting.simultaneousInterpretation.cleanUp();
209
240
  meeting.locusMediaRequest = undefined;
210
241
 
242
+ meeting.webex?.internal?.newMetrics?.callDiagnosticMetrics?.clearEventLimitsForCorrelationId(
243
+ meeting.correlationId
244
+ );
245
+
211
246
  // make sure we send last metrics before we close the peerconnection
212
247
  const stopStatsAnalyzer = meeting.statsAnalyzer
213
248
  ? meeting.statsAnalyzer.stopAnalyzer()
@@ -328,10 +363,57 @@ const MeetingUtil = {
328
363
  meeting.resourceId = meeting.resourceId || options.resourceId;
329
364
 
330
365
  if (meeting.requiredCaptcha) {
331
- 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);
332
390
  }
391
+
333
392
  if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
334
- 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);
335
417
  }
336
418
 
337
419
  if (options.pin) {
@@ -542,11 +624,23 @@ const MeetingUtil = {
542
624
  canStartManualCaption: (displayHints) =>
543
625
  displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_START),
544
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
+
545
636
  canStopManualCaption: (displayHints) => displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STOP),
546
637
 
547
638
  isManualCaptionActive: (displayHints) =>
548
639
  displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STATUS_ACTIVE),
549
640
 
641
+ isSpokenLanguageAutoDetectionEnabled: (displayHints) =>
642
+ displayHints.includes(DISPLAY_HINTS.SPOKEN_LANGUAGE_AUTO_DETECTION_ENABLED),
643
+
550
644
  isWebexAssistantActive: (displayHints) =>
551
645
  displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE),
552
646
 
@@ -602,22 +696,20 @@ const MeetingUtil = {
602
696
  },
603
697
 
604
698
  /**
605
- * Updates the locus info for the meeting with the delta locus
606
- * returned from requests that include the sequence information
699
+ * Updates the locus info for the meeting with the locus
700
+ * information returned from API requests made to Locus
607
701
  * Returns the original response object
608
702
  * @param {Object} meeting The meeting object
609
703
  * @param {Object} response The response of the http request
610
704
  * @returns {Object}
611
705
  */
612
- updateLocusWithDelta: (meeting, response) => {
706
+ updateLocusFromApiResponse: (meeting, response) => {
613
707
  if (!meeting) {
614
708
  return response;
615
709
  }
616
710
 
617
- const locus = response?.body?.locus;
618
-
619
- if (locus) {
620
- meeting.locusInfo.handleLocusDelta(locus, meeting);
711
+ if (response?.body?.locus) {
712
+ meeting.locusInfo.handleLocusAPIResponse(meeting, response.body);
621
713
  }
622
714
 
623
715
  return response;
@@ -664,7 +756,7 @@ const MeetingUtil = {
664
756
 
665
757
  return meeting
666
758
  .request(options)
667
- .then((response) => MeetingUtil.updateLocusWithDelta(meeting, response));
759
+ .then((response) => MeetingUtil.updateLocusFromApiResponse(meeting, response));
668
760
  };
669
761
 
670
762
  return locusDeltaRequest;
@@ -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({
@@ -1331,6 +1331,7 @@ export default class Meetings extends WebexPlugin {
1331
1331
  * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1332
1332
  * @param {String} [meetingLookupUrl] - meeting info prefetch url
1333
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
1334
1335
  * @returns {Promise<Meeting>} A new Meeting.
1335
1336
  * @public
1336
1337
  * @memberof Meetings
@@ -1345,7 +1346,8 @@ export default class Meetings extends WebexPlugin {
1345
1346
  callStateForMetrics: CallStateForMetrics = undefined,
1346
1347
  meetingInfo = undefined,
1347
1348
  meetingLookupUrl = undefined,
1348
- sessionCorrelationId: string = undefined
1349
+ sessionCorrelationId: string = undefined,
1350
+ classificationId: string = undefined
1349
1351
  ) {
1350
1352
  // Validate meeting information based on the provided destination and
1351
1353
  // type. This must be performed prior to determining if the meeting is
@@ -1415,7 +1417,8 @@ export default class Meetings extends WebexPlugin {
1415
1417
  callStateForMetrics,
1416
1418
  failOnMissingMeetingInfo,
1417
1419
  meetingInfo,
1418
- meetingLookupUrl
1420
+ meetingLookupUrl,
1421
+ classificationId
1419
1422
  ).then((createdMeeting: any) => {
1420
1423
  // If the meeting was successfully created.
1421
1424
  if (createdMeeting && createdMeeting.on) {
@@ -1529,6 +1532,7 @@ export default class Meetings extends WebexPlugin {
1529
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)
1530
1533
  * @param {Object} [meetingInfo] - Pre-fetched complete meeting info
1531
1534
  * @param {String} [meetingLookupUrl] - meeting info prefetch url
1535
+ * @param {String} classificationId see create()
1532
1536
  * @returns {Promise} a new meeting instance complete with meeting info and destination
1533
1537
  * @private
1534
1538
  * @memberof Meetings
@@ -1541,7 +1545,8 @@ export default class Meetings extends WebexPlugin {
1541
1545
  callStateForMetrics: CallStateForMetrics = undefined,
1542
1546
  failOnMissingMeetingInfo = false,
1543
1547
  meetingInfo = undefined,
1544
- meetingLookupUrl = undefined
1548
+ meetingLookupUrl = undefined,
1549
+ classificationId = undefined
1545
1550
  ) {
1546
1551
  const meeting = new Meeting(
1547
1552
  {
@@ -1560,11 +1565,12 @@ export default class Meetings extends WebexPlugin {
1560
1565
  {
1561
1566
  // @ts-ignore
1562
1567
  parent: this.webex,
1568
+ },
1569
+ (newMeeting) => {
1570
+ this.meetingCollection.set(newMeeting);
1563
1571
  }
1564
1572
  );
1565
1573
 
1566
- this.meetingCollection.set(meeting);
1567
-
1568
1574
  try {
1569
1575
  // if no participant has joined the scheduled meeting (meaning meeting is not active) and we get a locusEvent,
1570
1576
  // it means the meeting will start in 5-6 min. In that case, we want to fetchMeetingInfo
@@ -1588,6 +1594,7 @@ export default class Meetings extends WebexPlugin {
1588
1594
  // @ts-ignore
1589
1595
  const {enableUnifiedMeetings} = this.config.experimental;
1590
1596
  const meetingInfoOptions = {
1597
+ classificationId,
1591
1598
  extraParams: infoExtraParams,
1592
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
1593
1600
  };
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import {MEETINGS, _IN_LOBBY_, _NOT_IN_MEETING_, _IN_MEETING_, _OBSERVE_} from '../constants';
5
5
  import {IExternalRoles, IMediaStatus, Participant, ParticipantUrl} from './types';
6
+
6
7
  import MemberUtil from './util';
7
8
 
8
9
  export type MemberId = string;
@@ -109,4 +109,5 @@ export interface Participant {
109
109
  status: ParticipantMediaStatus;
110
110
  type: string;
111
111
  url: ParticipantUrl;
112
+ isRemoved: boolean; // JS-SDK internal field to indicate in updates when the participant is removed
112
113
  }
@@ -39,6 +39,17 @@ export default class MembersCollection {
39
39
  return this.members;
40
40
  }
41
41
 
42
+ /**
43
+ * Removes a member from the collection
44
+ * @param {String} id
45
+ * @returns {void}
46
+ */
47
+ remove(id: string) {
48
+ if (this.members[id]) {
49
+ delete this.members[id];
50
+ }
51
+ }
52
+
42
53
  /**
43
54
  * @returns {void}
44
55
  * reset members
@@ -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);