@webex/plugin-meetings 3.9.0-next.1 → 3.9.0-next.11

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 (45) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/interpretation/index.js +1 -1
  4. package/dist/interpretation/siLanguage.js +1 -1
  5. package/dist/locus-info/index.js +15 -6
  6. package/dist/locus-info/index.js.map +1 -1
  7. package/dist/locus-info/parser.js +4 -1
  8. package/dist/locus-info/parser.js.map +1 -1
  9. package/dist/meeting/index.js +101 -79
  10. package/dist/meeting/index.js.map +1 -1
  11. package/dist/meeting-info/meeting-info-v2.js +29 -21
  12. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  13. package/dist/meetings/index.js +31 -25
  14. package/dist/meetings/index.js.map +1 -1
  15. package/dist/members/index.js +3 -2
  16. package/dist/members/index.js.map +1 -1
  17. package/dist/members/util.js +7 -2
  18. package/dist/members/util.js.map +1 -1
  19. package/dist/reachability/index.js +3 -3
  20. package/dist/reachability/index.js.map +1 -1
  21. package/dist/types/locus-info/index.d.ts +2 -0
  22. package/dist/types/meeting/index.d.ts +1 -0
  23. package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
  24. package/dist/types/meetings/index.d.ts +3 -1
  25. package/dist/types/members/index.d.ts +2 -1
  26. package/dist/types/members/util.d.ts +6 -3
  27. package/dist/webinar/index.js +1 -1
  28. package/package.json +13 -13
  29. package/src/locus-info/index.ts +13 -5
  30. package/src/locus-info/parser.ts +5 -1
  31. package/src/meeting/index.ts +29 -3
  32. package/src/meeting-info/meeting-info-v2.ts +24 -5
  33. package/src/meetings/index.ts +9 -3
  34. package/src/members/index.ts +9 -2
  35. package/src/members/util.ts +18 -2
  36. package/src/reachability/index.ts +3 -3
  37. package/test/unit/spec/locus-info/index.js +7 -7
  38. package/test/unit/spec/locus-info/parser.js +3 -2
  39. package/test/unit/spec/meeting/index.js +96 -22
  40. package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
  41. package/test/unit/spec/meetings/index.js +10 -1
  42. package/test/unit/spec/members/index.js +30 -2
  43. package/test/unit/spec/members/request.js +55 -0
  44. package/test/unit/spec/members/utils.js +116 -14
  45. package/test/unit/spec/reachability/index.ts +158 -3
@@ -728,13 +728,17 @@ export default class Parser {
728
728
  break;
729
729
 
730
730
  case USE_INCOMING:
731
- case LOCUS_URL_CHANGED:
732
731
  // update working copy for future comparisons.
733
732
  // Note: The working copy of parser gets updated in .onFullLocus()
734
733
  // and here when USE_INCOMING or LOCUS_URL_CHANGED locus.
735
734
  this.workingCopy = newLoci;
736
735
  break;
737
736
 
737
+ case LOCUS_URL_CHANGED:
738
+ // clear the working copy completely, do a full locus sync
739
+ this.workingCopy = null;
740
+ break;
741
+
738
742
  case WAIT:
739
743
  // we've taken newLoci from the front of the queue, so put it back there as we have to wait
740
744
  // for the one that should be in front of it, before we can process it
@@ -269,6 +269,7 @@ export enum ScreenShareFloorStatus {
269
269
  type FetchMeetingInfoParams = {
270
270
  password?: string;
271
271
  registrationId?: string;
272
+ classificationId?: string;
272
273
  captchaCode?: string;
273
274
  extraParams?: Record<string, any>;
274
275
  sendCAevents?: boolean;
@@ -1902,6 +1903,7 @@ export default class Meeting extends StatelessWebexPlugin {
1902
1903
  extraParams = {},
1903
1904
  sendCAevents = false,
1904
1905
  registrationId = null,
1906
+ classificationId = null,
1905
1907
  }): Promise<void> {
1906
1908
  try {
1907
1909
  const captchaInfo = captchaCode
@@ -1918,7 +1920,9 @@ export default class Meeting extends StatelessWebexPlugin {
1918
1920
  this.locusId,
1919
1921
  extraParams,
1920
1922
  {meetingId: this.id, sendCAevents},
1921
- registrationId
1923
+ registrationId,
1924
+ null,
1925
+ classificationId
1922
1926
  );
1923
1927
 
1924
1928
  this.parseMeetingInfo(info?.body, this.destination, info?.errors);
@@ -3149,6 +3153,23 @@ export default class Meeting extends StatelessWebexPlugin {
3149
3153
  },
3150
3154
  EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
3151
3155
  );
3156
+ // @ts-ignore
3157
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
3158
+ key: 'internal.client.share.stopped',
3159
+ });
3160
+ // @ts-ignore
3161
+ this.webex.internal.newMetrics.submitClientEvent({
3162
+ name: 'client.share.stopped',
3163
+ payload: {
3164
+ mediaType: 'whiteboard',
3165
+ shareDuration:
3166
+ // @ts-ignore
3167
+ this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
3168
+ },
3169
+ options: {
3170
+ meetingId: this.id,
3171
+ },
3172
+ });
3152
3173
  break;
3153
3174
 
3154
3175
  case SHARE_STATUS.NO_SHARE:
@@ -6948,10 +6969,10 @@ export default class Meeting extends StatelessWebexPlugin {
6948
6969
  }
6949
6970
  }
6950
6971
 
6951
- // Count members that are in the meeting.
6972
+ // Count members that are in the meeting or in the lobby.
6952
6973
  const {members} = this.getMembers().membersCollection;
6953
6974
  event.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
6954
- (member: Member) => member.isInMeeting
6975
+ (member: Member) => member.isInMeeting || member.isInLobby
6955
6976
  ).length;
6956
6977
 
6957
6978
  // @ts-ignore
@@ -7819,6 +7840,9 @@ export default class Meeting extends StatelessWebexPlugin {
7819
7840
 
7820
7841
  this.allowMediaInLobby = options?.allowMediaInLobby;
7821
7842
 
7843
+ // @ts-ignore
7844
+ const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
7845
+
7822
7846
  // If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
7823
7847
  // @ts-ignore - isUserUnadmitted coming from SelfUtil
7824
7848
  if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
@@ -7917,6 +7941,7 @@ export default class Meeting extends StatelessWebexPlugin {
7917
7941
  locus_id: this.locusUrl.split('/').pop(),
7918
7942
  connectionType,
7919
7943
  ipVersion,
7944
+ ipver,
7920
7945
  selectedCandidatePairChanges,
7921
7946
  numTransports,
7922
7947
  isMultistream: this.isMultistream,
@@ -7985,6 +8010,7 @@ export default class Meeting extends StatelessWebexPlugin {
7985
8010
  ...reachabilityMetrics,
7986
8011
  ...iceCandidateErrors,
7987
8012
  iceCandidatesCount: this.iceCandidatesCount,
8013
+ ipver,
7988
8014
  });
7989
8015
 
7990
8016
  await this.cleanUpOnAddMediaFailure();
@@ -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
  {
@@ -1589,6 +1594,7 @@ export default class Meetings extends WebexPlugin {
1589
1594
  // @ts-ignore
1590
1595
  const {enableUnifiedMeetings} = this.config.experimental;
1591
1596
  const meetingInfoOptions = {
1597
+ classificationId,
1592
1598
  extraParams: infoExtraParams,
1593
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
1594
1600
  };
@@ -1181,11 +1181,17 @@ export default class Members extends StatelessWebexPlugin {
1181
1181
  * @param {string} memberId - id of the participant who is receiving request
1182
1182
  * @param {string} requestingParticipantId - id of the participant who is sending request (optional)
1183
1183
  * @param {string} [alias] - alias name
1184
+ * @param {string} [suffix] - name suffix (optional)
1184
1185
  * @returns {Promise}
1185
1186
  * @public
1186
1187
  * @memberof Members
1187
1188
  */
1188
- public editDisplayName(memberId: string, requestingParticipantId: string, alias: string) {
1189
+ public editDisplayName(
1190
+ memberId: string,
1191
+ requestingParticipantId: string,
1192
+ alias: string,
1193
+ suffix?: string
1194
+ ) {
1189
1195
  if (!this.locusUrl) {
1190
1196
  return Promise.reject(
1191
1197
  new ParameterError(
@@ -1205,7 +1211,8 @@ export default class Members extends StatelessWebexPlugin {
1205
1211
  memberId,
1206
1212
  requestingParticipantId,
1207
1213
  alias,
1208
- locusUrl
1214
+ locusUrl,
1215
+ suffix
1209
1216
  );
1210
1217
 
1211
1218
  return this.membersRequest.editDisplayNameMember(options);
@@ -190,13 +190,21 @@ const MembersUtil = {
190
190
  * @param {String} requestingParticipantId id of the participant who is sending request (optional)
191
191
  * @param {String} alias alias name
192
192
  * @param {String} locusUrl url
193
+ * @param {String} suffix optional suffix
193
194
  * @returns {Object} consists of {memberID: string, requestingParticipantId: string, alias: string, locusUrl: string}
194
195
  */
195
- generateEditDisplayNameMemberOptions: (memberId, requestingParticipantId, alias, locusUrl) => ({
196
+ generateEditDisplayNameMemberOptions: (
196
197
  memberId,
197
198
  requestingParticipantId,
198
199
  alias,
199
200
  locusUrl,
201
+ suffix
202
+ ) => ({
203
+ memberId,
204
+ requestingParticipantId,
205
+ alias,
206
+ locusUrl,
207
+ suffix,
200
208
  }),
201
209
 
202
210
  getMuteMemberRequestParams: (options) => {
@@ -301,10 +309,18 @@ const MembersUtil = {
301
309
  * @returns {Object} request parameters (method, uri, body) needed to make a editDisplayName request
302
310
  */
303
311
  editDisplayNameMemberRequestParams: (options) => {
304
- const body = {
312
+ const body: {
313
+ aliasValue: string;
314
+ requestingParticipantId: string;
315
+ suffixValue?: string;
316
+ } = {
305
317
  aliasValue: options.alias,
306
318
  requestingParticipantId: options.requestingParticipantId,
307
319
  };
320
+
321
+ if (options.suffix !== undefined) {
322
+ body.suffixValue = options.suffix;
323
+ }
308
324
  const uri = `${options.locusUrl}/${PARTICIPANT}/${options.memberId}/${ALIAS}`;
309
325
 
310
326
  return {
@@ -923,10 +923,10 @@ export default class Reachability extends EventsScope {
923
923
 
924
924
  // update expected results counters to include this cluster
925
925
  this.expectedResultsCount[cluster.isVideoMesh ? 'videoMesh' : 'public'].udp +=
926
- cluster.udp.length;
926
+ cluster.udp.length > 0 ? 1 : 0;
927
927
  if (!cluster.isVideoMesh) {
928
- this.expectedResultsCount.public.tcp += cluster.tcp.length;
929
- 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;
930
930
  }
931
931
  });
932
932
 
@@ -2369,23 +2369,23 @@ describe('plugin-meetings', () => {
2369
2369
 
2370
2370
  it('applyLocusDeltaData handles LOCUS_URL_CHANGED action correctly', () => {
2371
2371
  const {LOCUS_URL_CHANGED} = LocusDeltaParser.loci;
2372
- const fakeDeltaLocus = {id: 'fake delta locus'};
2372
+ const fakeFullLocus = {
2373
+ url: 'new full loci url',
2374
+ };
2373
2375
  const meeting = {
2374
2376
  meetingRequest: {
2375
- getLocusDTO: sandbox.stub().resolves({body: fakeDeltaLocus}),
2377
+ getLocusDTO: sandbox.stub().resolves({body: fakeFullLocus}),
2376
2378
  },
2377
2379
  locusInfo: {
2378
2380
  handleLocusDelta: sandbox.stub(),
2379
2381
  },
2380
- locusUrl: 'current locus url',
2382
+ locusUrl: 'current BO session locus url',
2381
2383
  };
2382
2384
 
2383
- locusInfo.locusParser.workingCopy = {
2384
- syncUrl: 'current sync url',
2385
- };
2385
+ locusInfo.locusParser.workingCopy = null;
2386
2386
 
2387
2387
  locusInfo.applyLocusDeltaData(LOCUS_URL_CHANGED, fakeLocus, meeting);
2388
- assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: 'current sync url'});
2388
+ assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: fakeLocus.url});
2389
2389
  });
2390
2390
 
2391
2391
  describe('edge cases for sync failing', () => {
@@ -253,7 +253,8 @@ describe('locus-info/parser', () => {
253
253
  });
254
254
 
255
255
  it('replaces current loci when the locus URL changes and incoming sequence is later, even when baseSequence doesn\'t match', () => {
256
- const {USE_INCOMING} = LocusDeltaParser.loci;
256
+ const {LOCUS_URL_CHANGED} = LocusDeltaParser.loci;
257
+ sandbox.stub(LocusDeltaParser, 'compare').returns(LOCUS_URL_CHANGED);
257
258
 
258
259
  parser.queue.dequeue = sandbox.stub().returns(NEW_LOCI);
259
260
  parser.onDeltaAction = sandbox.stub();
@@ -262,7 +263,7 @@ describe('locus-info/parser', () => {
262
263
 
263
264
  parser.processDeltaEvent();
264
265
 
265
- assert.equal(parser.workingCopy, NEW_LOCI);
266
+ assert.equal(parser.workingCopy, null);
266
267
  });
267
268
 
268
269
  it('does not replace current loci when the locus URL changes but incoming sequence is not later', () => {