@webex/plugin-meetings 3.12.0-next.9 → 3.12.0-next.91

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 (213) hide show
  1. package/AGENTS.md +9 -0
  2. package/dist/aiEnableRequest/index.js +15 -2
  3. package/dist/aiEnableRequest/index.js.map +1 -1
  4. package/dist/breakouts/breakout.js +8 -3
  5. package/dist/breakouts/breakout.js.map +1 -1
  6. package/dist/breakouts/index.js +26 -2
  7. package/dist/breakouts/index.js.map +1 -1
  8. package/dist/config.js +2 -2
  9. package/dist/config.js.map +1 -1
  10. package/dist/constants.js +35 -9
  11. package/dist/constants.js.map +1 -1
  12. package/dist/controls-options-manager/constants.js +11 -1
  13. package/dist/controls-options-manager/constants.js.map +1 -1
  14. package/dist/controls-options-manager/index.js +67 -29
  15. package/dist/controls-options-manager/index.js.map +1 -1
  16. package/dist/controls-options-manager/util.js +91 -0
  17. package/dist/controls-options-manager/util.js.map +1 -1
  18. package/dist/hashTree/constants.js +13 -1
  19. package/dist/hashTree/constants.js.map +1 -1
  20. package/dist/hashTree/hashTreeParser.js +880 -382
  21. package/dist/hashTree/hashTreeParser.js.map +1 -1
  22. package/dist/hashTree/utils.js +42 -0
  23. package/dist/hashTree/utils.js.map +1 -1
  24. package/dist/index.js +7 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/interceptors/dataChannelAuthToken.js +75 -15
  27. package/dist/interceptors/dataChannelAuthToken.js.map +1 -1
  28. package/dist/interceptors/locusRetry.js +23 -8
  29. package/dist/interceptors/locusRetry.js.map +1 -1
  30. package/dist/interpretation/index.js +10 -1
  31. package/dist/interpretation/index.js.map +1 -1
  32. package/dist/interpretation/interpretation.types.js +7 -0
  33. package/dist/interpretation/interpretation.types.js.map +1 -0
  34. package/dist/interpretation/siLanguage.js +1 -1
  35. package/dist/locus-info/controlsUtils.js +4 -1
  36. package/dist/locus-info/controlsUtils.js.map +1 -1
  37. package/dist/locus-info/index.js +303 -88
  38. package/dist/locus-info/index.js.map +1 -1
  39. package/dist/locus-info/infoUtils.js +36 -5
  40. package/dist/locus-info/infoUtils.js.map +1 -1
  41. package/dist/locus-info/types.js +19 -0
  42. package/dist/locus-info/types.js.map +1 -1
  43. package/dist/media/index.js +3 -1
  44. package/dist/media/index.js.map +1 -1
  45. package/dist/media/properties.js +1 -0
  46. package/dist/media/properties.js.map +1 -1
  47. package/dist/meeting/in-meeting-actions.js +5 -1
  48. package/dist/meeting/in-meeting-actions.js.map +1 -1
  49. package/dist/meeting/index.js +1233 -793
  50. package/dist/meeting/index.js.map +1 -1
  51. package/dist/meeting/locusMediaRequest.js +229 -82
  52. package/dist/meeting/locusMediaRequest.js.map +1 -1
  53. package/dist/meeting/muteState.js +10 -1
  54. package/dist/meeting/muteState.js.map +1 -1
  55. package/dist/meeting/request.js +5 -2
  56. package/dist/meeting/request.js.map +1 -1
  57. package/dist/meeting/util.js +35 -2
  58. package/dist/meeting/util.js.map +1 -1
  59. package/dist/meeting-info/meeting-info-v2.js +2 -2
  60. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  61. package/dist/meetings/index.js +231 -118
  62. package/dist/meetings/index.js.map +1 -1
  63. package/dist/meetings/meetings.types.js +6 -1
  64. package/dist/meetings/meetings.types.js.map +1 -1
  65. package/dist/meetings/request.js +39 -0
  66. package/dist/meetings/request.js.map +1 -1
  67. package/dist/meetings/util.js +79 -5
  68. package/dist/meetings/util.js.map +1 -1
  69. package/dist/member/index.js +10 -0
  70. package/dist/member/index.js.map +1 -1
  71. package/dist/member/types.js.map +1 -1
  72. package/dist/member/util.js +30 -0
  73. package/dist/member/util.js.map +1 -1
  74. package/dist/members/index.js +101 -43
  75. package/dist/members/index.js.map +1 -1
  76. package/dist/members/util.js +8 -1
  77. package/dist/members/util.js.map +1 -1
  78. package/dist/metrics/constants.js +5 -1
  79. package/dist/metrics/constants.js.map +1 -1
  80. package/dist/multistream/codec/constants.js +63 -0
  81. package/dist/multistream/codec/constants.js.map +1 -0
  82. package/dist/multistream/mediaRequestManager.js +62 -15
  83. package/dist/multistream/mediaRequestManager.js.map +1 -1
  84. package/dist/multistream/receiveSlot.js +9 -0
  85. package/dist/multistream/receiveSlot.js.map +1 -1
  86. package/dist/reachability/index.js +10 -13
  87. package/dist/reachability/index.js.map +1 -1
  88. package/dist/reachability/reachability.types.js +2 -0
  89. package/dist/reachability/reachability.types.js.map +1 -1
  90. package/dist/reachability/util.js +45 -0
  91. package/dist/reachability/util.js.map +1 -1
  92. package/dist/reactions/reactions.type.js.map +1 -1
  93. package/dist/recording-controller/index.js +1 -3
  94. package/dist/recording-controller/index.js.map +1 -1
  95. package/dist/types/config.d.ts +2 -2
  96. package/dist/types/constants.d.ts +12 -1
  97. package/dist/types/controls-options-manager/constants.d.ts +6 -1
  98. package/dist/types/controls-options-manager/index.d.ts +16 -0
  99. package/dist/types/hashTree/constants.d.ts +2 -0
  100. package/dist/types/hashTree/hashTreeParser.d.ts +146 -17
  101. package/dist/types/hashTree/utils.d.ts +18 -0
  102. package/dist/types/index.d.ts +3 -0
  103. package/dist/types/interceptors/locusRetry.d.ts +4 -4
  104. package/dist/types/interpretation/interpretation.types.d.ts +10 -0
  105. package/dist/types/locus-info/index.d.ts +50 -6
  106. package/dist/types/locus-info/infoUtils.d.ts +8 -0
  107. package/dist/types/locus-info/types.d.ts +21 -1
  108. package/dist/types/media/properties.d.ts +1 -0
  109. package/dist/types/meeting/in-meeting-actions.d.ts +4 -0
  110. package/dist/types/meeting/index.d.ts +94 -7
  111. package/dist/types/meeting/locusMediaRequest.d.ts +12 -0
  112. package/dist/types/meeting/request.d.ts +1 -0
  113. package/dist/types/meeting/util.d.ts +9 -0
  114. package/dist/types/meetings/index.d.ts +30 -18
  115. package/dist/types/meetings/meetings.types.d.ts +15 -0
  116. package/dist/types/meetings/request.d.ts +14 -0
  117. package/dist/types/member/index.d.ts +1 -0
  118. package/dist/types/member/types.d.ts +1 -0
  119. package/dist/types/member/util.d.ts +9 -0
  120. package/dist/types/members/index.d.ts +15 -2
  121. package/dist/types/members/util.d.ts +1 -5
  122. package/dist/types/metrics/constants.d.ts +4 -0
  123. package/dist/types/multistream/codec/constants.d.ts +7 -0
  124. package/dist/types/multistream/mediaRequestManager.d.ts +22 -5
  125. package/dist/types/reachability/index.d.ts +1 -1
  126. package/dist/types/reachability/reachability.types.d.ts +7 -0
  127. package/dist/types/reachability/util.d.ts +17 -0
  128. package/dist/types/reactions/reactions.type.d.ts +3 -0
  129. package/dist/webinar/index.js +305 -159
  130. package/dist/webinar/index.js.map +1 -1
  131. package/package.json +22 -22
  132. package/src/aiEnableRequest/index.ts +16 -0
  133. package/src/breakouts/breakout.ts +3 -1
  134. package/src/breakouts/index.ts +31 -0
  135. package/src/config.ts +2 -2
  136. package/src/constants.ts +20 -3
  137. package/src/controls-options-manager/constants.ts +14 -1
  138. package/src/controls-options-manager/index.ts +87 -28
  139. package/src/controls-options-manager/util.ts +81 -1
  140. package/src/hashTree/constants.ts +16 -0
  141. package/src/hashTree/hashTreeParser.ts +580 -196
  142. package/src/hashTree/utils.ts +36 -0
  143. package/src/index.ts +6 -0
  144. package/src/interceptors/dataChannelAuthToken.ts +88 -12
  145. package/src/interceptors/locusRetry.ts +25 -4
  146. package/src/interpretation/index.ts +27 -9
  147. package/src/interpretation/interpretation.types.ts +11 -0
  148. package/src/locus-info/controlsUtils.ts +3 -1
  149. package/src/locus-info/index.ts +304 -100
  150. package/src/locus-info/infoUtils.ts +41 -6
  151. package/src/locus-info/types.ts +25 -1
  152. package/src/media/index.ts +3 -0
  153. package/src/media/properties.ts +1 -0
  154. package/src/meeting/in-meeting-actions.ts +8 -0
  155. package/src/meeting/index.ts +494 -67
  156. package/src/meeting/locusMediaRequest.ts +106 -6
  157. package/src/meeting/muteState.ts +10 -1
  158. package/src/meeting/request.ts +11 -0
  159. package/src/meeting/util.ts +47 -5
  160. package/src/meeting-info/meeting-info-v2.ts +4 -2
  161. package/src/meetings/index.ts +133 -78
  162. package/src/meetings/meetings.types.ts +19 -0
  163. package/src/meetings/request.ts +43 -0
  164. package/src/meetings/util.ts +97 -1
  165. package/src/member/index.ts +10 -0
  166. package/src/member/types.ts +1 -0
  167. package/src/member/util.ts +29 -0
  168. package/src/members/index.ts +70 -7
  169. package/src/members/util.ts +12 -4
  170. package/src/metrics/constants.ts +4 -0
  171. package/src/multistream/codec/constants.ts +58 -0
  172. package/src/multistream/mediaRequestManager.ts +119 -28
  173. package/src/multistream/receiveSlot.ts +18 -0
  174. package/src/reachability/index.ts +19 -15
  175. package/src/reachability/reachability.types.ts +11 -0
  176. package/src/reachability/util.ts +36 -0
  177. package/src/reactions/reactions.type.ts +3 -0
  178. package/src/recording-controller/index.ts +1 -2
  179. package/src/webinar/index.ts +214 -36
  180. package/test/unit/spec/aiEnableRequest/index.ts +86 -0
  181. package/test/unit/spec/breakouts/breakout.ts +9 -3
  182. package/test/unit/spec/breakouts/index.ts +49 -0
  183. package/test/unit/spec/controls-options-manager/index.js +244 -29
  184. package/test/unit/spec/controls-options-manager/util.js +165 -0
  185. package/test/unit/spec/hashTree/hashTreeParser.ts +1838 -180
  186. package/test/unit/spec/hashTree/utils.ts +125 -1
  187. package/test/unit/spec/interceptors/dataChannelAuthToken.ts +196 -0
  188. package/test/unit/spec/interceptors/locusRetry.ts +205 -4
  189. package/test/unit/spec/interpretation/index.ts +26 -4
  190. package/test/unit/spec/locus-info/controlsUtils.js +172 -57
  191. package/test/unit/spec/locus-info/index.js +499 -81
  192. package/test/unit/spec/locus-info/infoUtils.js +184 -1
  193. package/test/unit/spec/media/index.ts +31 -0
  194. package/test/unit/spec/meeting/in-meeting-actions.ts +4 -0
  195. package/test/unit/spec/meeting/index.js +1615 -42
  196. package/test/unit/spec/meeting/locusMediaRequest.ts +302 -4
  197. package/test/unit/spec/meeting/muteState.js +81 -0
  198. package/test/unit/spec/meeting/request.js +12 -0
  199. package/test/unit/spec/meeting/utils.js +157 -1
  200. package/test/unit/spec/meeting-info/meetinginfov2.js +19 -10
  201. package/test/unit/spec/meetings/index.js +363 -36
  202. package/test/unit/spec/meetings/request.js +141 -0
  203. package/test/unit/spec/meetings/utils.js +189 -0
  204. package/test/unit/spec/member/index.js +7 -0
  205. package/test/unit/spec/member/util.js +89 -0
  206. package/test/unit/spec/members/index.js +216 -0
  207. package/test/unit/spec/members/request.js +37 -1
  208. package/test/unit/spec/members/utils.js +63 -0
  209. package/test/unit/spec/multistream/mediaRequestManager.ts +501 -37
  210. package/test/unit/spec/reachability/index.ts +59 -46
  211. package/test/unit/spec/reachability/util.ts +31 -0
  212. package/test/unit/spec/recording-controller/index.js +9 -8
  213. package/test/unit/spec/webinar/index.ts +329 -28
@@ -303,6 +303,67 @@ describe('plugin-meetings', () => {
303
303
  });
304
304
  });
305
305
 
306
+ describe('#transferHostToMember', () => {
307
+ it('should reject if no locus url is set and no breakoutLocusUrl is provided', async () => {
308
+ const members = createMembers({url: false});
309
+
310
+ await assert.isRejected(members.transferHostToMember('bob'));
311
+ });
312
+
313
+ it('should reject if no memberId is provided', async () => {
314
+ const members = createMembers({url: url1});
315
+
316
+ await assert.isRejected(members.transferHostToMember());
317
+ });
318
+
319
+ it('uses the main locus url when no breakoutLocusUrl is provided', async () => {
320
+ sandbox.spy(MembersUtil, 'generateTransferHostMemberOptions');
321
+
322
+ const members = createMembers({url: url1});
323
+ const {membersRequest} = members;
324
+ sandbox.spy(membersRequest, 'transferHostToMember');
325
+
326
+ await members.transferHostToMember('bob', true);
327
+
328
+ assert.calledOnceWithExactly(
329
+ MembersUtil.generateTransferHostMemberOptions,
330
+ 'bob',
331
+ true,
332
+ url1
333
+ );
334
+ assert.calledOnceWithExactly(membersRequest.transferHostToMember, {
335
+ memberId: 'bob',
336
+ moderator: true,
337
+ locusUrl: url1,
338
+ });
339
+ });
340
+
341
+ it('uses the breakoutLocusUrl when provided', async () => {
342
+ sandbox.spy(MembersUtil, 'generateTransferHostMemberOptions');
343
+
344
+ const members = createMembers({url: url1});
345
+ const {membersRequest} = members;
346
+ sandbox.spy(membersRequest, 'transferHostToMember');
347
+
348
+ const breakoutLocusUrl = 'https://example.com/breakout-locus';
349
+
350
+ await members.transferHostToMember('bob', true, breakoutLocusUrl);
351
+
352
+ assert.calledOnceWithExactly(
353
+ MembersUtil.generateTransferHostMemberOptions,
354
+ 'bob',
355
+ true,
356
+ breakoutLocusUrl
357
+ );
358
+ assert.calledOnceWithExactly(membersRequest.transferHostToMember, {
359
+ memberId: 'bob',
360
+ moderator: true,
361
+ locusUrl: breakoutLocusUrl,
362
+ authorizingLocusUrl: url1,
363
+ });
364
+ });
365
+ });
366
+
306
367
  describe('#clearMembers', () => {
307
368
  it('should send clear event if clear members', () => {
308
369
  const members = createMembers({url: url1});
@@ -322,6 +383,28 @@ describe('plugin-meetings', () => {
322
383
  );
323
384
  sinon.restore();
324
385
  });
386
+
387
+ it('should not clear memberIdByHistoryCsi so it survives member removal (e.g. BO entry/exit)', () => {
388
+ const members = createMembers({url: url1});
389
+ members.memberIdByHistoryCsi.set(1000, 'test1');
390
+ members.clearMembers();
391
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 1);
392
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'test1');
393
+ });
394
+
395
+ it("captures the current members' CSIs into memberIdByHistoryCsi before resetting", () => {
396
+ const members = createMembers({url: url1});
397
+ members.membersCollection.setAll({
398
+ m1: {id: 'm1', participant: {devices: [{csis: [1000, 1001]}]}},
399
+ m2: {id: 'm2', participant: {devices: [{csis: [2000]}]}},
400
+ });
401
+ sinon.stub(Trigger, 'trigger');
402
+ members.clearMembers();
403
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
404
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1001), 'm1');
405
+ assert.strictEqual(members.memberIdByHistoryCsi.get(2000), 'm2');
406
+ sinon.restore();
407
+ });
325
408
  });
326
409
  describe('#locusParticipantsUpdate', () => {
327
410
  beforeEach(() => {
@@ -1165,6 +1248,139 @@ describe('plugin-meetings', () => {
1165
1248
  it('returns correct member when CSI matches the second device', () => {
1166
1249
  assert.strictEqual(members.findMemberByCsi(2001), fakeCollection.oneWithSomeCsis);
1167
1250
  });
1251
+
1252
+ it('falls back to memberIdByHistoryCsi when CSI is no longer on the current devices', () => {
1253
+ members.memberIdByHistoryCsi.set(9999, 'oneWithDevicesWithoutCsis');
1254
+ assert.strictEqual(
1255
+ members.findMemberByCsi(9999),
1256
+ fakeCollection.oneWithDevicesWithoutCsis
1257
+ );
1258
+ });
1259
+
1260
+ it('returns undefined when the memberIdByHistoryCsi entry points to a removed member', () => {
1261
+ members.memberIdByHistoryCsi.set(8888, 'not-in-collection');
1262
+ assert.strictEqual(members.findMemberByCsi(8888), undefined);
1263
+ });
1264
+
1265
+ it('prefers a current device match over a memberIdByHistoryCsi match', () => {
1266
+ members.memberIdByHistoryCsi.set(1001, 'oneWithDevicesWithoutCsis');
1267
+ assert.strictEqual(members.findMemberByCsi(1001), fakeCollection.oneWithSomeCsis);
1268
+ });
1269
+ });
1270
+
1271
+ describe('memberIdByHistoryCsi tracking', () => {
1272
+ let members;
1273
+
1274
+ const participantWithCsis = (id, csis) => ({
1275
+ id,
1276
+ type: 'USER',
1277
+ person: {},
1278
+ devices: [{csis}],
1279
+ });
1280
+
1281
+ beforeEach(() => {
1282
+ sinon.stub(Trigger, 'trigger');
1283
+ members = createMembers({url: url1});
1284
+ });
1285
+
1286
+ afterEach(() => {
1287
+ sinon.restore();
1288
+ });
1289
+
1290
+ it('does not populate the map when adding a brand new member', () => {
1291
+ members.locusParticipantsUpdate({
1292
+ participants: [participantWithCsis('m1', [1000])],
1293
+ });
1294
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 0);
1295
+ });
1296
+
1297
+ it('does not populate the map when devices have not changed between updates', () => {
1298
+ const devices = [{csis: [1000]}];
1299
+
1300
+ members.locusParticipantsUpdate({
1301
+ participants: [{id: 'm1', type: 'USER', person: {}, devices}],
1302
+ });
1303
+ members.locusParticipantsUpdate({
1304
+ participants: [{id: 'm1', type: 'USER', person: {}, devices}],
1305
+ });
1306
+
1307
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 0);
1308
+ });
1309
+
1310
+ it('captures previous CSIs into the map when devices change on update', () => {
1311
+ members.locusParticipantsUpdate({
1312
+ participants: [participantWithCsis('m1', [1000, 1001])],
1313
+ });
1314
+ members.locusParticipantsUpdate({
1315
+ participants: [participantWithCsis('m1', [2000])],
1316
+ });
1317
+
1318
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1319
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1001), 'm1');
1320
+ });
1321
+
1322
+ it('preserves history when a member is removed and re-added (breakout scenario)', () => {
1323
+ members.locusParticipantsUpdate({
1324
+ participants: [participantWithCsis('m1', [1000])],
1325
+ });
1326
+ // change devices so previous CSIs are captured into history
1327
+ members.locusParticipantsUpdate({
1328
+ participants: [participantWithCsis('m1', [2000])],
1329
+ });
1330
+ // remove the member
1331
+ members.locusParticipantsUpdate({
1332
+ participants: [],
1333
+ removedParticipantIds: ['m1'],
1334
+ });
1335
+
1336
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1337
+
1338
+ // re-add the member with brand new CSIs
1339
+ members.locusParticipantsUpdate({
1340
+ participants: [participantWithCsis('m1', [3000])],
1341
+ });
1342
+
1343
+ const member = members.findMemberByCsi(1000);
1344
+ assert.isDefined(member);
1345
+ assert.strictEqual(member.id, 'm1');
1346
+ });
1347
+
1348
+ it("captures the removed member's current CSIs even without a prior device-change update", () => {
1349
+ // member is added, then removed in the very next delta without any
1350
+ // intermediate device-change update - their current CSIs must still be
1351
+ // captured into the history map on removal
1352
+ members.locusParticipantsUpdate({
1353
+ participants: [participantWithCsis('m1', [1000, 1001])],
1354
+ });
1355
+
1356
+ assert.strictEqual(members.memberIdByHistoryCsi.size, 0);
1357
+
1358
+ members.locusParticipantsUpdate({
1359
+ participants: [],
1360
+ removedParticipantIds: ['m1'],
1361
+ });
1362
+
1363
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1364
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1001), 'm1');
1365
+ });
1366
+
1367
+ it('merges existing history with CSIs captured at removal time', () => {
1368
+ members.locusParticipantsUpdate({
1369
+ participants: [participantWithCsis('m1', [1000])],
1370
+ });
1371
+ // device change captures 1000 into history; member now reports 2000
1372
+ members.locusParticipantsUpdate({
1373
+ participants: [participantWithCsis('m1', [2000])],
1374
+ });
1375
+ // removal should additionally capture the member's current CSIs (2000)
1376
+ members.locusParticipantsUpdate({
1377
+ participants: [],
1378
+ removedParticipantIds: ['m1'],
1379
+ });
1380
+
1381
+ assert.strictEqual(members.memberIdByHistoryCsi.get(1000), 'm1');
1382
+ assert.strictEqual(members.memberIdByHistoryCsi.get(2000), 'm1');
1383
+ });
1168
1384
  });
1169
1385
 
1170
1386
  describe('getCsisForMember()', () => {
@@ -194,7 +194,43 @@ describe('plugin-meetings', () => {
194
194
  checkRequest({
195
195
  method: 'PATCH',
196
196
  uri: 'https://example.com/12345/participant/member1/controls',
197
- body: {role: {moderator: true}},
197
+ body: {
198
+ role: {
199
+ roles: [
200
+ {
201
+ hasRole: true,
202
+ type: 'MODERATOR',
203
+ },
204
+ ],
205
+ },
206
+ },
207
+ });
208
+ });
209
+
210
+ it('sends a request with authorizingLocusUrl when provided', async () => {
211
+ const options = {
212
+ locusUrl: url1,
213
+ memberId: 'member1',
214
+ moderator: true,
215
+ authorizingLocusUrl: 'https://example.com/breakout-locus',
216
+ };
217
+
218
+ await membersRequest.transferHostToMember(options);
219
+
220
+ checkRequest({
221
+ method: 'PATCH',
222
+ uri: 'https://example.com/12345/participant/member1/controls',
223
+ body: {
224
+ role: {
225
+ roles: [
226
+ {
227
+ hasRole: true,
228
+ type: 'MODERATOR',
229
+ },
230
+ ],
231
+ },
232
+ authorizingLocusUrl: 'https://example.com/breakout-locus',
233
+ },
198
234
  });
199
235
  });
200
236
  });
@@ -226,6 +226,69 @@ describe('plugin-meetings', () => {
226
226
  });
227
227
  });
228
228
 
229
+ describe('#generateTransferHostMemberOptions', () => {
230
+ it('returns the correct options', () => {
231
+ assert.deepEqual(
232
+ MembersUtil.generateTransferHostMemberOptions('member1', true, 'locusUrl'),
233
+ {
234
+ memberId: 'member1',
235
+ moderator: true,
236
+ locusUrl: 'locusUrl',
237
+ }
238
+ );
239
+ });
240
+ });
241
+
242
+ describe('#getTransferHostToMemberRequestParams', () => {
243
+ it('returns the correct request params without authorizingLocusUrl', () => {
244
+ const options = {
245
+ locusUrl: 'locusUrl',
246
+ memberId: 'member1',
247
+ moderator: true,
248
+ };
249
+
250
+ assert.deepEqual(MembersUtil.getTransferHostToMemberRequestParams(options), {
251
+ method: HTTP_VERBS.PATCH,
252
+ uri: 'locusUrl/participant/member1/controls',
253
+ body: {
254
+ role: {
255
+ roles: [
256
+ {
257
+ hasRole: true,
258
+ type: 'MODERATOR',
259
+ },
260
+ ],
261
+ },
262
+ },
263
+ });
264
+ });
265
+
266
+ it('returns the correct request params with authorizingLocusUrl', () => {
267
+ const options = {
268
+ locusUrl: 'mainLocusUrl',
269
+ memberId: 'member1',
270
+ moderator: true,
271
+ authorizingLocusUrl: 'breakoutLocusUrl',
272
+ };
273
+
274
+ assert.deepEqual(MembersUtil.getTransferHostToMemberRequestParams(options), {
275
+ method: HTTP_VERBS.PATCH,
276
+ uri: 'mainLocusUrl/participant/member1/controls',
277
+ body: {
278
+ role: {
279
+ roles: [
280
+ {
281
+ hasRole: true,
282
+ type: 'MODERATOR',
283
+ },
284
+ ],
285
+ },
286
+ authorizingLocusUrl: 'breakoutLocusUrl',
287
+ },
288
+ });
289
+ });
290
+ });
291
+
229
292
  describe('#generateMuteMemberOptions', () => {
230
293
  const testOptions = (isAudio) => {
231
294
  const memberId = 'bob';