@webex/plugin-meetings 3.7.0-next.2 → 3.7.0-next.20

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 (82) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
  4. package/dist/common/errors/join-webinar-error.js.map +1 -0
  5. package/dist/config.js +1 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/constants.js +27 -6
  8. package/dist/constants.js.map +1 -1
  9. package/dist/index.js +8 -15
  10. package/dist/index.js.map +1 -1
  11. package/dist/interpretation/index.js +1 -1
  12. package/dist/interpretation/siLanguage.js +1 -1
  13. package/dist/meeting/in-meeting-actions.js +11 -1
  14. package/dist/meeting/in-meeting-actions.js.map +1 -1
  15. package/dist/meeting/index.js +84 -131
  16. package/dist/meeting/index.js.map +1 -1
  17. package/dist/meeting/util.js +0 -8
  18. package/dist/meeting/util.js.map +1 -1
  19. package/dist/meeting-info/meeting-info-v2.js +29 -17
  20. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  21. package/dist/meetings/index.js +6 -3
  22. package/dist/meetings/index.js.map +1 -1
  23. package/dist/members/util.js +4 -2
  24. package/dist/members/util.js.map +1 -1
  25. package/dist/metrics/constants.js +3 -1
  26. package/dist/metrics/constants.js.map +1 -1
  27. package/dist/multistream/remoteMedia.js +30 -15
  28. package/dist/multistream/remoteMedia.js.map +1 -1
  29. package/dist/reachability/clusterReachability.js +12 -11
  30. package/dist/reachability/clusterReachability.js.map +1 -1
  31. package/dist/recording-controller/enums.js +8 -4
  32. package/dist/recording-controller/enums.js.map +1 -1
  33. package/dist/recording-controller/index.js +18 -9
  34. package/dist/recording-controller/index.js.map +1 -1
  35. package/dist/recording-controller/util.js +13 -9
  36. package/dist/recording-controller/util.js.map +1 -1
  37. package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
  38. package/dist/types/constants.d.ts +19 -1
  39. package/dist/types/index.d.ts +3 -3
  40. package/dist/types/meeting/in-meeting-actions.d.ts +10 -0
  41. package/dist/types/meeting/index.d.ts +1 -10
  42. package/dist/types/meeting/util.d.ts +0 -1
  43. package/dist/types/meeting-info/meeting-info-v2.d.ts +4 -4
  44. package/dist/types/meetings/index.d.ts +3 -0
  45. package/dist/types/members/util.d.ts +2 -0
  46. package/dist/types/metrics/constants.d.ts +3 -1
  47. package/dist/types/recording-controller/enums.d.ts +5 -2
  48. package/dist/types/recording-controller/index.d.ts +1 -0
  49. package/dist/types/recording-controller/util.d.ts +2 -1
  50. package/dist/webinar/index.js +357 -7
  51. package/dist/webinar/index.js.map +1 -1
  52. package/package.json +22 -22
  53. package/src/common/errors/join-webinar-error.ts +24 -0
  54. package/src/config.ts +1 -1
  55. package/src/constants.ts +24 -3
  56. package/src/index.ts +2 -3
  57. package/src/meeting/in-meeting-actions.ts +21 -0
  58. package/src/meeting/index.ts +54 -48
  59. package/src/meeting/util.ts +0 -9
  60. package/src/meeting-info/meeting-info-v2.ts +23 -11
  61. package/src/meetings/index.ts +8 -2
  62. package/src/members/util.ts +1 -0
  63. package/src/metrics/constants.ts +3 -1
  64. package/src/multistream/remoteMedia.ts +28 -15
  65. package/src/reachability/clusterReachability.ts +4 -1
  66. package/src/recording-controller/enums.ts +5 -2
  67. package/src/recording-controller/index.ts +17 -4
  68. package/src/recording-controller/util.ts +20 -5
  69. package/src/webinar/index.ts +201 -9
  70. package/test/unit/spec/meeting/in-meeting-actions.ts +13 -1
  71. package/test/unit/spec/meeting/index.js +106 -77
  72. package/test/unit/spec/meeting/utils.js +0 -15
  73. package/test/unit/spec/meeting-info/meetinginfov2.js +9 -4
  74. package/test/unit/spec/meetings/index.js +9 -5
  75. package/test/unit/spec/members/utils.js +95 -0
  76. package/test/unit/spec/multistream/remoteMedia.ts +11 -7
  77. package/test/unit/spec/reachability/clusterReachability.ts +7 -0
  78. package/test/unit/spec/recording-controller/index.js +61 -5
  79. package/test/unit/spec/recording-controller/util.js +39 -3
  80. package/test/unit/spec/webinar/index.ts +363 -0
  81. package/dist/common/errors/webinar-registration-error.js.map +0 -1
  82. package/src/common/errors/webinar-registration-error.ts +0 -27
@@ -18,7 +18,7 @@ import MeetingInfo, {
18
18
  MeetingInfoV2CaptchaError,
19
19
  MeetingInfoV2AdhocMeetingError,
20
20
  MeetingInfoV2PolicyError,
21
- MeetingInfoV2WebinarRegistrationError,
21
+ MeetingInfoV2JoinWebinarError,
22
22
  } from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
23
23
  import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
24
24
  import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -895,9 +895,14 @@ describe('plugin-meetings', () => {
895
895
  {errorCode: 403021},
896
896
  {errorCode: 403022},
897
897
  {errorCode: 403024},
898
+ {errorCode: 403137},
899
+ {errorCode: 423007},
900
+ {errorCode: 403026},
901
+ {errorCode: 403037},
902
+ {errorCode: 403137},
898
903
  ],
899
904
  ({errorCode}) => {
900
- it(`should throw a MeetingInfoV2WebinarRegistrationError for error code ${errorCode}`, async () => {
905
+ it(`should throw a MeetingInfoV2JoinWebinarError for error code ${errorCode}`, async () => {
901
906
  const message = 'a message';
902
907
  const meetingInfoData = {meetingInfo: {registrationUrl: 'registrationUrl'}};
903
908
 
@@ -909,7 +914,7 @@ describe('plugin-meetings', () => {
909
914
  await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
910
915
  assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
911
916
  } catch (err) {
912
- assert.instanceOf(err, MeetingInfoV2WebinarRegistrationError);
917
+ assert.instanceOf(err, MeetingInfoV2JoinWebinarError);
913
918
  assert.deepEqual(err.message, `${message}, code=${errorCode}`);
914
919
  assert.equal(err.wbxAppApiCode, errorCode);
915
920
  assert.deepEqual(err.meetingInfo, meetingInfoData);
@@ -917,7 +922,7 @@ describe('plugin-meetings', () => {
917
922
  assert(Metrics.sendBehavioralMetric.calledOnce);
918
923
  assert.calledWith(
919
924
  Metrics.sendBehavioralMetric,
920
- BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR,
925
+ BEHAVIORAL_METRICS.JOIN_WEBINAR_ERROR,
921
926
  {code: errorCode}
922
927
  );
923
928
 
@@ -131,9 +131,9 @@ describe('plugin-meetings', () => {
131
131
  logger,
132
132
  people: {
133
133
  _getMe: sinon.stub().resolves({
134
- type: 'validuser',
134
+ type: 'validuser',
135
135
  }),
136
- }
136
+ },
137
137
  });
138
138
 
139
139
  startReachabilityStub = sinon.stub(webex.meetings, 'startReachability').resolves();
@@ -1985,6 +1985,8 @@ describe('plugin-meetings', () => {
1985
1985
  const meetingIds = {
1986
1986
  meetingId: meeting.id,
1987
1987
  correlationId: meeting.correlationId,
1988
+ roles: meeting.roles,
1989
+ callStateForMetrics: meeting.callStateForMetrics,
1988
1990
  };
1989
1991
 
1990
1992
  webex.meetings.destroy(meeting, test1);
@@ -2021,6 +2023,8 @@ describe('plugin-meetings', () => {
2021
2023
 
2022
2024
  assert.equal(deletedMeetingInfo.id, meetingIds.meetingId);
2023
2025
  assert.equal(deletedMeetingInfo.correlationId, meetingIds.correlationId);
2026
+ assert.equal(deletedMeetingInfo.roles, meetingIds.roles);
2027
+ assert.equal(deletedMeetingInfo.callStateForMetrics, meetingIds.callStateForMetrics);
2024
2028
  });
2025
2029
  });
2026
2030
 
@@ -2092,7 +2096,7 @@ describe('plugin-meetings', () => {
2092
2096
  );
2093
2097
  });
2094
2098
 
2095
- const setup = ({me = { type: 'validuser'}, user} = {}) => {
2099
+ const setup = ({me = {type: 'validuser'}, user} = {}) => {
2096
2100
  loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
2097
2101
  assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
2098
2102
 
@@ -2113,9 +2117,9 @@ describe('plugin-meetings', () => {
2113
2117
 
2114
2118
  it('should not call request.getMeetingPreferences if user is a guest', async () => {
2115
2119
  setup({me: {type: 'appuser'}});
2116
-
2120
+
2117
2121
  await webex.meetings.fetchUserPreferredWebexSite();
2118
-
2122
+
2119
2123
  assert.equal(webex.meetings.preferredWebexSite, '');
2120
2124
  assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
2121
2125
  assert.notCalled(webex.internal.services.getMeetingPreferences);
@@ -262,5 +262,100 @@ describe('plugin-meetings', () => {
262
262
  testParams(false);
263
263
  });
264
264
  });
265
+
266
+ describe('#getAddMemberBody', () => {
267
+ it('returns the correct body with email address and roles', () => {
268
+ const options = {
269
+ invitee: {
270
+ emailAddress: 'test@example.com',
271
+ roles: ['role1', 'role2'],
272
+ },
273
+ alertIfActive: true,
274
+ };
275
+
276
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
277
+ invitees: [
278
+ {
279
+ address: 'test@example.com',
280
+ roles: ['role1', 'role2'],
281
+ },
282
+ ],
283
+ alertIfActive: true,
284
+ });
285
+ });
286
+
287
+ it('returns the correct body with phone number and no roles', () => {
288
+ const options = {
289
+ invitee: {
290
+ phoneNumber: '1234567890',
291
+ },
292
+ alertIfActive: false,
293
+ };
294
+
295
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
296
+ invitees: [
297
+ {
298
+ address: '1234567890',
299
+ },
300
+ ],
301
+ alertIfActive: false,
302
+ });
303
+ });
304
+
305
+ it('returns the correct body with fallback to email', () => {
306
+ const options = {
307
+ invitee: {
308
+ email: 'fallback@example.com',
309
+ },
310
+ alertIfActive: true,
311
+ };
312
+
313
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
314
+ invitees: [
315
+ {
316
+ address: 'fallback@example.com',
317
+ },
318
+ ],
319
+ alertIfActive: true,
320
+ });
321
+ });
322
+
323
+ it('handles missing `alertIfActive` gracefully', () => {
324
+ const options = {
325
+ invitee: {
326
+ emailAddress: 'test@example.com',
327
+ roles: ['role1'],
328
+ },
329
+ };
330
+
331
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
332
+ invitees: [
333
+ {
334
+ address: 'test@example.com',
335
+ roles: ['role1'],
336
+ },
337
+ ],
338
+ alertIfActive: undefined,
339
+ });
340
+ });
341
+
342
+ it('ignores roles if not provided', () => {
343
+ const options = {
344
+ invitee: {
345
+ emailAddress: 'test@example.com',
346
+ },
347
+ alertIfActive: false,
348
+ };
349
+
350
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
351
+ invitees: [
352
+ {
353
+ address: 'test@example.com',
354
+ },
355
+ ],
356
+ alertIfActive: false,
357
+ });
358
+ });
359
+ });
265
360
  });
266
361
  });
@@ -249,14 +249,18 @@ describe('RemoteMedia', () => {
249
249
 
250
250
  forEach(
251
251
  [
252
- {height: 134, fs: 60},
253
- {height: 135, fs: 240},
254
- {height: 269, fs: 240},
255
- {height: 270, fs: 920},
256
- {height: 539, fs: 920},
257
- {height: 540, fs: 3600},
252
+ {height: 90, fs: 60}, // 90p
253
+ {height: 98, fs: 60},
254
+ {height: 99, fs: 240}, // 180p
255
+ {height: 180, fs: 240},
256
+ {height: 197, fs: 240},
257
+ {height: 198, fs: 920}, // 360p
258
+ {height: 360, fs: 920},
259
+ {height: 395, fs: 920},
260
+ {height: 396, fs: 3600}, // 720p
258
261
  {height: 720, fs: 3600},
259
- {height: 721, fs: 8192},
262
+ {height: 721, fs: 8192}, // 1080p
263
+ {height: 1080, fs: 8192},
260
264
  ],
261
265
  ({height, fs}) => {
262
266
  it(`sets the max fs to ${fs} correctly when height is ${height}`, () => {
@@ -15,6 +15,7 @@ describe('ClusterReachability', () => {
15
15
  let previousRTCPeerConnection;
16
16
  let clusterReachability;
17
17
  let fakePeerConnection;
18
+ let gatherIceCandidatesSpy;
18
19
 
19
20
  const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
20
21
  [Events.resultReady]: [],
@@ -44,6 +45,8 @@ describe('ClusterReachability', () => {
44
45
  xtls: ['stun:xtls1.webex.com', 'stun:xtls2.webex.com:443'],
45
46
  });
46
47
 
48
+ gatherIceCandidatesSpy = sinon.spy(clusterReachability, 'gatherIceCandidates');
49
+
47
50
  resetEmittedEvents();
48
51
 
49
52
  clusterReachability.on(Events.resultReady, (data: ResultEventData) => {
@@ -151,6 +154,10 @@ describe('ClusterReachability', () => {
151
154
  assert.calledOnceWithExactly(fakePeerConnection.createOffer, {offerToReceiveAudio: true});
152
155
  assert.calledOnce(fakePeerConnection.setLocalDescription);
153
156
 
157
+ // Make sure that gatherIceCandidates is called before setLocalDescription
158
+ // as setLocalDescription triggers the ICE gathering process
159
+ assert.isTrue(gatherIceCandidatesSpy.calledBefore(fakePeerConnection.setLocalDescription));
160
+
154
161
  clusterReachability.abort();
155
162
  await promise;
156
163
 
@@ -221,7 +221,21 @@ describe('plugin-meetings', () => {
221
221
 
222
222
  assert.calledWith(request.request, {
223
223
  uri: `test/loci/id/recording`,
224
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'start'}},
224
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'start'}, recordingType: 'cloud'},
225
+ method: HTTP_VERBS.PUT,
226
+ });
227
+
228
+ assert.deepEqual(result, request.request.firstCall.returnValue);
229
+ });
230
+
231
+ it('can start premise recording when the correct display hint is present', () => {
232
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_START']);
233
+
234
+ const result = controller.startRecording();
235
+
236
+ assert.calledWith(request.request, {
237
+ uri: `test/loci/id/recording`,
238
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'start'}, recordingType: 'premise'},
225
239
  method: HTTP_VERBS.PUT,
226
240
  });
227
241
 
@@ -238,14 +252,28 @@ describe('plugin-meetings', () => {
238
252
  assert.isRejected(result);
239
253
  });
240
254
 
241
- it('can start recording when the correct display hint is present', () => {
255
+ it('can stop recording when the correct display hint is present', () => {
242
256
  controller.setDisplayHints(['RECORDING_CONTROL_STOP']);
243
257
 
244
258
  const result = controller.stopRecording();
245
259
 
246
260
  assert.calledWith(request.request, {
247
261
  uri: `test/loci/id/recording`,
248
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'stop'}},
262
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'stop'}, recordingType: 'cloud'},
263
+ method: HTTP_VERBS.PUT,
264
+ });
265
+
266
+ assert.deepEqual(result, request.request.firstCall.returnValue);
267
+ });
268
+
269
+ it('can stop premise recording when the correct display hint is present', () => {
270
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_STOP']);
271
+
272
+ const result = controller.stopRecording();
273
+
274
+ assert.calledWith(request.request, {
275
+ uri: `test/loci/id/recording`,
276
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'stop'}, recordingType: 'premise'},
249
277
  method: HTTP_VERBS.PUT,
250
278
  });
251
279
 
@@ -269,7 +297,21 @@ describe('plugin-meetings', () => {
269
297
 
270
298
  assert.calledWith(request.request, {
271
299
  uri: `test/loci/id/recording`,
272
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'pause'}},
300
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'pause'}, recordingType: 'cloud'},
301
+ method: HTTP_VERBS.PUT,
302
+ });
303
+
304
+ assert.deepEqual(result, request.request.firstCall.returnValue);
305
+ });
306
+
307
+ it('can pause premise recording when the correct display hint is present', () => {
308
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_PAUSE']);
309
+
310
+ const result = controller.pauseRecording();
311
+
312
+ assert.calledWith(request.request, {
313
+ uri: `test/loci/id/recording`,
314
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'pause'}, recordingType: 'premise'},
273
315
  method: HTTP_VERBS.PUT,
274
316
  });
275
317
 
@@ -293,7 +335,21 @@ describe('plugin-meetings', () => {
293
335
 
294
336
  assert.calledWith(request.request, {
295
337
  uri: `test/loci/id/recording`,
296
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'resume'}},
338
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'resume'}, recordingType: 'cloud'},
339
+ method: HTTP_VERBS.PUT,
340
+ });
341
+
342
+ assert.deepEqual(result, request.request.firstCall.returnValue);
343
+ });
344
+
345
+ it('can resume premise recording when the correct display hint is present', () => {
346
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_RESUME']);
347
+
348
+ const result = controller.resumeRecording();
349
+
350
+ assert.calledWith(request.request, {
351
+ uri: `test/loci/id/recording`,
352
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'resume'}, recordingType: 'premise'},
297
353
  method: HTTP_VERBS.PUT,
298
354
  });
299
355
 
@@ -1,5 +1,5 @@
1
1
  import RecordingUtil from '@webex/plugin-meetings/src/recording-controller/util';
2
- import RecordingAction from '@webex/plugin-meetings/src/recording-controller/enums';
2
+ import { RecordingAction } from '@webex/plugin-meetings/src/recording-controller/enums';
3
3
  import {SELF_POLICY} from '@webex/plugin-meetings/src/constants';
4
4
 
5
5
  import {assert} from 'chai';
@@ -29,6 +29,15 @@ describe('plugin-meetings', () => {
29
29
  );
30
30
  });
31
31
 
32
+ it('can start premise recording when the correct display hint is present', () => {
33
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_START');
34
+
35
+ assert.equal(
36
+ RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints),
37
+ true
38
+ );
39
+ });
40
+
32
41
  it('can start recording when the correct display hint is present and the policy is true', () => {
33
42
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
34
43
 
@@ -69,6 +78,15 @@ describe('plugin-meetings', () => {
69
78
  );
70
79
  });
71
80
 
81
+ it('can pause premise recording when the correct display hint is present', () => {
82
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_PAUSE');
83
+
84
+ assert.equal(
85
+ RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints),
86
+ true
87
+ );
88
+ });
89
+
72
90
  it('can pause recording when the correct display hint is present and the policy is true', () => {
73
91
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
74
92
 
@@ -109,6 +127,15 @@ describe('plugin-meetings', () => {
109
127
  );
110
128
  });
111
129
 
130
+ it('can stop premise recording when the correct display hint is present', () => {
131
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_STOP');
132
+
133
+ assert.equal(
134
+ RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints),
135
+ true
136
+ );
137
+ });
138
+
112
139
  it('can stop recording when the correct display hint is present and the policy is true', () => {
113
140
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP', {
114
141
  [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
@@ -142,7 +169,7 @@ describe('plugin-meetings', () => {
142
169
  });
143
170
 
144
171
  describe('canUserResume', () => {
145
- it('can start recording when the correct display hint is present', () => {
172
+ it('can resume recording when the correct display hint is present', () => {
146
173
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
147
174
 
148
175
  assert.equal(
@@ -151,7 +178,16 @@ describe('plugin-meetings', () => {
151
178
  );
152
179
  });
153
180
 
154
- it('can start recording when the correct display hint is present and the policy is true', () => {
181
+ it('can resume premise recording when the correct display hint is present', () => {
182
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_RESUME');
183
+
184
+ assert.equal(
185
+ RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints),
186
+ true
187
+ );
188
+ });
189
+
190
+ it('can resume recording when the correct display hint is present and the policy is true', () => {
155
191
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
156
192
 
157
193
  assert.equal(