@webex/plugin-meetings 3.9.0-next.15 → 3.9.0-next.16

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.
@@ -101,14 +101,14 @@ declare const MeetingUtil: {
101
101
  */
102
102
  addSequence: (meeting: any, requestBody: any) => void;
103
103
  /**
104
- * Updates the locus info for the meeting with the delta locus
105
- * returned from requests that include the sequence information
104
+ * Updates the locus info for the meeting with the locus
105
+ * information returned from API requests made to Locus
106
106
  * Returns the original response object
107
107
  * @param {Object} meeting The meeting object
108
108
  * @param {Object} response The response of the http request
109
109
  * @returns {Object}
110
110
  */
111
- updateLocusWithDelta: (meeting: any, response: any) => any;
111
+ updateLocusFromApiResponse: (meeting: any, response: any) => any;
112
112
  generateBuildLocusDeltaRequestOptions: (originalMeeting: any) => (originalOptions: any) => any;
113
113
  generateLocusDeltaRequest: (originalMeeting: any) => (originalOptions: any) => any;
114
114
  selfSupportsFeature: (feature: SELF_POLICY, userPolicies: Record<SELF_POLICY, boolean>) => boolean;
@@ -458,7 +458,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
458
458
  }, _callee7);
459
459
  }))();
460
460
  },
461
- version: "3.9.0-next.15"
461
+ version: "3.9.0-next.16"
462
462
  });
463
463
  var _default = exports.default = Webinar;
464
464
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -92,5 +92,5 @@
92
92
  "//": [
93
93
  "TODO: upgrade jwt-decode when moving to node 18"
94
94
  ],
95
- "version": "3.9.0-next.15"
95
+ "version": "3.9.0-next.16"
96
96
  }
@@ -31,6 +31,51 @@ import LocusDeltaParser from './parser';
31
31
  import Metrics from '../metrics';
32
32
  import BEHAVIORAL_METRICS from '../metrics/constants';
33
33
 
34
+ export type LocusDTO = {
35
+ controls?: any;
36
+ fullState?: {
37
+ active: boolean;
38
+ count: number;
39
+ lastActive: string;
40
+ locked: boolean;
41
+ sessionId: string;
42
+ seessionIds: string[];
43
+ startTime: number;
44
+ state: string;
45
+ type: string;
46
+ };
47
+ host?: {
48
+ id: string;
49
+ incomingCallProtocols: any[];
50
+ isExternal: boolean;
51
+ name: string;
52
+ orgId: string;
53
+ };
54
+ info?: any;
55
+ links?: any;
56
+ mediaShares?: any[];
57
+ meetings?: any[];
58
+ participants: any[];
59
+ replaces?: any[];
60
+ self?: any;
61
+ sequence?: {
62
+ dirtyParticipants: number;
63
+ entries: number[];
64
+ rangeEnd: number;
65
+ rangeStart: number;
66
+ sequenceHash: number;
67
+ sessionToken: string;
68
+ since: string;
69
+ totalParticipants: number;
70
+ };
71
+ syncUrl?: string;
72
+ url?: string;
73
+ };
74
+
75
+ export type LocusApiResponseBody = {
76
+ locus: LocusDTO; // this LocusDTO here might not be the full one (for example it won't have all the participants, but it should have self)
77
+ };
78
+
34
79
  /**
35
80
  * @description LocusInfo extends ChildEmitter to convert locusInfo info a private emitter to parent object
36
81
  * @export
@@ -323,6 +368,16 @@ export default class LocusInfo extends EventsScope {
323
368
  this.emitChange = true;
324
369
  }
325
370
 
371
+ /**
372
+ * Handles HTTP response from Locus API call.
373
+ * @param {Meeting} meeting meeting object
374
+ * @param {LocusApiResponseBody} responseBody body of the http response from Locus API call
375
+ * @returns {void}
376
+ */
377
+ handleLocusAPIResponse(meeting, responseBody: LocusApiResponseBody): void {
378
+ this.handleLocusDelta(responseBody.locus, meeting);
379
+ }
380
+
326
381
  /**
327
382
  * @param {Meeting} meeting
328
383
  * @param {Object} data
@@ -291,18 +291,14 @@ export class MuteState {
291
291
  );
292
292
 
293
293
  return MeetingUtil.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted)
294
- .then((locus) => {
294
+ .then((response) => {
295
295
  LoggerProxy.logger.info(
296
296
  `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: local mute (audio=${audioMuted}, video=${videoMuted}) applied to server`
297
297
  );
298
298
 
299
299
  this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;
300
300
 
301
- if (locus) {
302
- meeting.locusInfo.handleLocusDelta(locus, meeting);
303
- }
304
-
305
- return locus;
301
+ return MeetingUtil.updateLocusFromApiResponse(meeting, response);
306
302
  })
307
303
  .catch((remoteUpdateError) => {
308
304
  LoggerProxy.logger.warn(
@@ -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,
@@ -695,22 +693,20 @@ const MeetingUtil = {
695
693
  },
696
694
 
697
695
  /**
698
- * Updates the locus info for the meeting with the delta locus
699
- * returned from requests that include the sequence information
696
+ * Updates the locus info for the meeting with the locus
697
+ * information returned from API requests made to Locus
700
698
  * Returns the original response object
701
699
  * @param {Object} meeting The meeting object
702
700
  * @param {Object} response The response of the http request
703
701
  * @returns {Object}
704
702
  */
705
- updateLocusWithDelta: (meeting, response) => {
703
+ updateLocusFromApiResponse: (meeting, response) => {
706
704
  if (!meeting) {
707
705
  return response;
708
706
  }
709
707
 
710
- const locus = response?.body?.locus;
711
-
712
- if (locus) {
713
- meeting.locusInfo.handleLocusDelta(locus, meeting);
708
+ if (response?.body?.locus) {
709
+ meeting.locusInfo.handleLocusAPIResponse(meeting, response.body);
714
710
  }
715
711
 
716
712
  return response;
@@ -757,7 +753,7 @@ const MeetingUtil = {
757
753
 
758
754
  return meeting
759
755
  .request(options)
760
- .then((response) => MeetingUtil.updateLocusWithDelta(meeting, response));
756
+ .then((response) => MeetingUtil.updateLocusFromApiResponse(meeting, response));
761
757
  };
762
758
 
763
759
  return locusDeltaRequest;
@@ -2040,6 +2040,18 @@ describe('plugin-meetings', () => {
2040
2040
  });
2041
2041
  });
2042
2042
 
2043
+ describe('#handleLocusAPIResponse', () => {
2044
+ it('calls handleLocusDelta', () => {
2045
+ const fakeLocus = {eventType: LOCUSEVENT.DIFFERENCE};
2046
+
2047
+ sinon.stub(locusInfo, 'handleLocusDelta');
2048
+
2049
+ locusInfo.handleLocusAPIResponse(mockMeeting, {locus: fakeLocus});
2050
+
2051
+ assert.calledWith(locusInfo.handleLocusDelta, fakeLocus, mockMeeting);
2052
+ });
2053
+ });
2054
+
2043
2055
  describe('#LocusDeltaEvents', () => {
2044
2056
  const fakeMeeting = 'fakeMeeting';
2045
2057
  let sandbox = null;
@@ -12,7 +12,7 @@ describe('plugin-meetings', () => {
12
12
  let video;
13
13
  let originalRemoteUpdateAudioVideo;
14
14
 
15
- const fakeLocus = {info: 'this is a fake locus'};
15
+ const fakeLocusResponse = {body: {locus: {info: 'this is a fake locus'}}};
16
16
 
17
17
  const createFakeLocalStream = (id, userMuted, systemMuted) => {
18
18
  return {
@@ -38,9 +38,6 @@ describe('plugin-meetings', () => {
38
38
  unmuteAllowed: true,
39
39
  remoteVideoMuted: false,
40
40
  unmuteVideoAllowed: true,
41
- locusInfo: {
42
- handleLocusDelta: sinon.stub(),
43
- },
44
41
  members: {
45
42
  selfId: 'fake self id',
46
43
  muteMember: sinon.stub().resolves(),
@@ -49,7 +46,8 @@ describe('plugin-meetings', () => {
49
46
 
50
47
  originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
51
48
 
52
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves(fakeLocus);
49
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves(fakeLocusResponse);
50
+ MeetingUtil.updateLocusFromApiResponse = sinon.stub();
53
51
 
54
52
  audio = createMuteState(AUDIO, meeting, true);
55
53
  video = createMuteState(VIDEO, meeting, true);
@@ -141,6 +139,7 @@ describe('plugin-meetings', () => {
141
139
  // and local unmute was sent to server
142
140
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
143
141
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, false, undefined);
142
+ assert.calledWith(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
144
143
 
145
144
  assert.isFalse(audio.isMuted());
146
145
  });
@@ -173,6 +172,7 @@ describe('plugin-meetings', () => {
173
172
 
174
173
  // system was muted so local unmute was not sent to server
175
174
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
175
+ assert.notCalled(MeetingUtil.updateLocusFromApiResponse);
176
176
 
177
177
  assert.isTrue(audio.isMuted());
178
178
  });
@@ -207,6 +207,7 @@ describe('plugin-meetings', () => {
207
207
  // and local unmute was sent to server
208
208
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
209
209
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
210
+ assert.calledWith(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
210
211
 
211
212
  assert.isFalse(video.isMuted());
212
213
  });
@@ -219,7 +220,9 @@ describe('plugin-meetings', () => {
219
220
 
220
221
  assert.isTrue(video.isMuted());
221
222
 
223
+ await testUtils.flushPromises();
222
224
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
225
+ MeetingUtil.updateLocusFromApiResponse.resetHistory();
223
226
 
224
227
  // now simulate server requiring us to locally unmute
225
228
  // assuming setServerMuted succeeds at updating userMuted
@@ -239,6 +242,7 @@ describe('plugin-meetings', () => {
239
242
 
240
243
  // system was muted so local unmute was not sent to server
241
244
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
245
+ assert.notCalled(MeetingUtil.updateLocusFromApiResponse);
242
246
 
243
247
  assert.isTrue(video.isMuted());
244
248
  });
@@ -443,6 +447,7 @@ describe('plugin-meetings', () => {
443
447
 
444
448
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
445
449
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
450
+ assert.calledWith(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
446
451
 
447
452
  // now allow the first request to complete
448
453
  serverResponseResolve();
@@ -559,6 +564,7 @@ describe('plugin-meetings', () => {
559
564
  await testUtils.flushPromises();
560
565
 
561
566
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
567
+ MeetingUtil.updateLocusFromApiResponse.resetHistory();
562
568
  };
563
569
 
564
570
  const setupSpies = (mediaType) => {
@@ -605,13 +611,15 @@ describe('plugin-meetings', () => {
605
611
  {mediaType: VIDEO, title: 'video'},
606
612
  ];
607
613
 
614
+ const fakeLocusResponse = {body: {locus: {info: 'fake locus'}}};
615
+
608
616
  tests.forEach(({mediaType, title}) =>
609
617
  describe(title, () => {
610
618
  let originalRemoteUpdateAudioVideo;
611
619
 
612
620
  beforeEach(() => {
613
621
  originalRemoteUpdateAudioVideo = MeetingUtil.remoteUpdateAudioVideo;
614
- MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves({info: 'fake locus'});
622
+ MeetingUtil.remoteUpdateAudioVideo = sinon.stub().resolves(fakeLocusResponse);
615
623
  });
616
624
 
617
625
  afterEach(() => {
@@ -660,6 +668,7 @@ describe('plugin-meetings', () => {
660
668
  assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
661
669
  assert.notCalled(setServerMutedSpy);
662
670
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
671
+ assert.notCalled(MeetingUtil.updateLocusFromApiResponse);
663
672
  assert.isTrue(muteState.state.client.localMute);
664
673
  });
665
674
 
@@ -672,6 +681,7 @@ describe('plugin-meetings', () => {
672
681
  assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
673
682
  assert.notCalled(setServerMutedSpy);
674
683
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
684
+ assert.notCalled(MeetingUtil.updateLocusFromApiResponse);
675
685
  assert.isTrue(muteState.state.client.localMute);
676
686
  });
677
687
 
@@ -681,9 +691,12 @@ describe('plugin-meetings', () => {
681
691
 
682
692
  muteState.init(meeting);
683
693
 
694
+ await testUtils.flushPromises();
695
+
684
696
  assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
685
697
  assert.notCalled(setServerMutedSpy);
686
698
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
699
+ assert.calledOnceWithExactly(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
687
700
  assert.isFalse(muteState.state.client.localMute);
688
701
  });
689
702
 
@@ -707,6 +720,7 @@ describe('plugin-meetings', () => {
707
720
  simulateUserMute(mediaType, true);
708
721
  muteState.handleLocalStreamMuteStateChange(meeting);
709
722
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
723
+ assert.notCalled(MeetingUtil.updateLocusFromApiResponse);
710
724
 
711
725
  assert.isFalse(muteState.state.client.localMute);
712
726
  });
@@ -716,8 +730,11 @@ describe('plugin-meetings', () => {
716
730
 
717
731
  simulateUserMute(mediaType, false);
718
732
  muteState.handleLocalStreamMuteStateChange(meeting);
733
+ await testUtils.flushPromises();
734
+
719
735
  assert.equal(muteState.state.client.localMute, false);
720
736
  assert.called(MeetingUtil.remoteUpdateAudioVideo);
737
+ assert.calledOnceWithExactly(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
721
738
  });
722
739
 
723
740
  it('tests localMute - user mute from false to true', async () => {
@@ -725,8 +742,11 @@ describe('plugin-meetings', () => {
725
742
 
726
743
  simulateUserMute(mediaType, true);
727
744
  muteState.handleLocalStreamMuteStateChange(meeting);
745
+ await testUtils.flushPromises();
746
+
728
747
  assert.equal(muteState.state.client.localMute, true);
729
748
  assert.called(MeetingUtil.remoteUpdateAudioVideo);
749
+ assert.calledOnceWithExactly(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
730
750
  });
731
751
 
732
752
  it('tests localMute - system mute from true to false', async () => {
@@ -734,8 +754,11 @@ describe('plugin-meetings', () => {
734
754
 
735
755
  simulateSystemMute(mediaType, false);
736
756
  muteState.handleLocalStreamMuteStateChange(meeting);
757
+ await testUtils.flushPromises();
758
+
737
759
  assert.equal(muteState.state.client.localMute, false);
738
760
  assert.called(MeetingUtil.remoteUpdateAudioVideo);
761
+ assert.calledOnceWithExactly(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
739
762
  });
740
763
 
741
764
  it('tests localMute - system mute from false to true', async () => {
@@ -743,8 +766,11 @@ describe('plugin-meetings', () => {
743
766
 
744
767
  simulateSystemMute(mediaType, true);
745
768
  muteState.handleLocalStreamMuteStateChange(meeting);
769
+ await testUtils.flushPromises();
770
+
746
771
  assert.equal(muteState.state.client.localMute, true);
747
772
  assert.called(MeetingUtil.remoteUpdateAudioVideo);
773
+ assert.calledOnceWithExactly(MeetingUtil.updateLocusFromApiResponse, meeting, fakeLocusResponse);
748
774
  });
749
775
  });
750
776
 
@@ -228,11 +228,11 @@ describe('plugin-meetings', () => {
228
228
  });
229
229
  });
230
230
 
231
- describe('updateLocusWithDelta', () => {
232
- it('should call handleLocusDelta with the new delta locus', () => {
231
+ describe('updateLocusFromApiResponse', () => {
232
+ it('should call handleLocusAPIResponse with the response body', () => {
233
233
  const meeting = {
234
234
  locusInfo: {
235
- handleLocusDelta: sinon.stub(),
235
+ handleLocusAPIResponse: sinon.stub(),
236
236
  },
237
237
  };
238
238
 
@@ -242,16 +242,16 @@ describe('plugin-meetings', () => {
242
242
  },
243
243
  };
244
244
 
245
- const response = MeetingUtil.updateLocusWithDelta(meeting, originalResponse);
245
+ const response = MeetingUtil.updateLocusFromApiResponse(meeting, originalResponse);
246
246
 
247
247
  assert.deepEqual(response, originalResponse);
248
- assert.calledOnceWithExactly(meeting.locusInfo.handleLocusDelta, 'locus', meeting);
248
+ assert.calledOnceWithExactly(meeting.locusInfo.handleLocusAPIResponse, meeting, originalResponse.body);
249
249
  });
250
250
 
251
251
  it('should handle locus being missing from the response', () => {
252
252
  const meeting = {
253
253
  locusInfo: {
254
- handleLocusDelta: sinon.stub(),
254
+ handleLocusAPIResponse: sinon.stub(),
255
255
  },
256
256
  };
257
257
 
@@ -259,10 +259,10 @@ describe('plugin-meetings', () => {
259
259
  body: {},
260
260
  };
261
261
 
262
- const response = MeetingUtil.updateLocusWithDelta(meeting, originalResponse);
262
+ const response = MeetingUtil.updateLocusFromApiResponse(meeting, originalResponse);
263
263
 
264
264
  assert.deepEqual(response, originalResponse);
265
- assert.notCalled(meeting.locusInfo.handleLocusDelta);
265
+ assert.notCalled(meeting.locusInfo.handleLocusAPIResponse);
266
266
  });
267
267
 
268
268
  it('should work with an undefined meeting', () => {
@@ -272,14 +272,14 @@ describe('plugin-meetings', () => {
272
272
  },
273
273
  };
274
274
 
275
- const response = MeetingUtil.updateLocusWithDelta(undefined, originalResponse);
275
+ const response = MeetingUtil.updateLocusFromApiResponse(undefined, originalResponse);
276
276
  assert.deepEqual(response, originalResponse);
277
277
  });
278
278
  });
279
279
 
280
280
  describe('generateLocusDeltaRequest', () => {
281
281
  it('generates the correct wrapper function', async () => {
282
- const updateLocusWithDeltaSpy = sinon.spy(MeetingUtil, 'updateLocusWithDelta');
282
+ const updateLocusFromApiResponseSpy = sinon.spy(MeetingUtil, 'updateLocusFromApiResponse');
283
283
  const addSequenceSpy = sinon.spy(MeetingUtil, 'addSequence');
284
284
 
285
285
  const meeting = {
@@ -296,16 +296,16 @@ describe('plugin-meetings', () => {
296
296
  let result = await locusDeltaRequest(options);
297
297
 
298
298
  assert.equal(result, 'result');
299
- assert.calledOnceWithExactly(updateLocusWithDeltaSpy, meeting, 'result');
299
+ assert.calledOnceWithExactly(updateLocusFromApiResponseSpy, meeting, 'result');
300
300
  assert.calledOnceWithExactly(addSequenceSpy, meeting, options.body);
301
301
 
302
- updateLocusWithDeltaSpy.resetHistory();
302
+ updateLocusFromApiResponseSpy.resetHistory();
303
303
  addSequenceSpy.resetHistory();
304
304
 
305
305
  // body missing from options
306
306
  result = await locusDeltaRequest({});
307
307
  assert.equal(result, 'result');
308
- assert.calledOnceWithExactly(updateLocusWithDeltaSpy, meeting, 'result');
308
+ assert.calledOnceWithExactly(updateLocusFromApiResponseSpy, meeting, 'result');
309
309
  assert.calledOnceWithExactly(addSequenceSpy, meeting, options.body);
310
310
 
311
311
  // meeting disappears so the WeakRef returns undefined
@@ -359,7 +359,11 @@ describe('plugin-meetings', () => {
359
359
  });
360
360
 
361
361
  describe('remoteUpdateAudioVideo', () => {
362
- it('#Should call meetingRequest.locusMediaRequest with correct parameters', async () => {
362
+ it('#Should call meetingRequest.locusMediaRequest with correct parameters and return the full response', async () => {
363
+ const fakeResponse = {
364
+ body: { locus: { url: 'locusUrl'}},
365
+ headers: { },
366
+ };
363
367
  const meeting = {
364
368
  id: 'meeting-id',
365
369
  mediaId: '12345',
@@ -368,13 +372,14 @@ describe('plugin-meetings', () => {
368
372
  sequence: {},
369
373
  },
370
374
  locusMediaRequest: {
371
- send: sinon.stub().resolves({body: {}, headers: {}}),
375
+ send: sinon.stub().resolves(fakeResponse),
372
376
  },
373
377
  getWebexObject: sinon.stub().returns(webex),
374
378
  };
375
379
 
376
- await MeetingUtil.remoteUpdateAudioVideo(meeting, true, false);
380
+ const result = await MeetingUtil.remoteUpdateAudioVideo(meeting, true, false);
377
381
 
382
+ assert.deepEqual(result, fakeResponse);
378
383
  assert.calledOnceWithExactly(meeting.locusMediaRequest.send, {
379
384
  mediaId: '12345',
380
385
  muteOptions: {