@wazo/sdk 0.38.7 → 0.38.8

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 (106) hide show
  1. package/dist/wazo-sdk.js +2 -2
  2. package/esm/__tests__/api-client.test.js +142 -2
  3. package/esm/__tests__/web-rtc-client.test.js +227 -27
  4. package/esm/api/calld.js +8 -0
  5. package/esm/api/confd.js +134 -2
  6. package/esm/api-client.js +142 -2
  7. package/esm/checker/Checker.js +183 -24
  8. package/esm/checker/checks/aor.js +142 -2
  9. package/esm/checker/checks/api.js +142 -2
  10. package/esm/checker/checks/index.js +183 -24
  11. package/esm/checker/checks/wazo-websocket.js +2 -0
  12. package/esm/checker/checks/webrtc-transport.js +181 -24
  13. package/esm/checker/checks/webrtc.js +181 -24
  14. package/esm/domain/AdHocAPIConference.js +142 -2
  15. package/esm/domain/Features.js +142 -2
  16. package/esm/domain/Meeting.js +18 -0
  17. package/esm/domain/MeetingAuthorization.js +70 -0
  18. package/esm/domain/Phone/CTIPhone.js +142 -2
  19. package/esm/domain/__tests__/Meeting.test.js +87 -1
  20. package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
  21. package/esm/index.js +226 -27
  22. package/esm/service/CallApi.js +142 -2
  23. package/esm/service/getApiClient.js +142 -2
  24. package/esm/simple/Auth.js +226 -27
  25. package/esm/simple/Configuration.js +226 -27
  26. package/esm/simple/Directory.js +142 -2
  27. package/esm/simple/Phone.js +226 -27
  28. package/esm/simple/Websocket.js +3 -0
  29. package/esm/simple/index.js +226 -27
  30. package/esm/simple/room/LocalParticipant.js +226 -27
  31. package/esm/simple/room/Participant.js +226 -27
  32. package/esm/simple/room/RemoteParticipant.js +226 -27
  33. package/esm/simple/room/Room.js +226 -27
  34. package/esm/simple/room/SipRoom.js +226 -27
  35. package/esm/simple/room/Stream.js +226 -27
  36. package/esm/simple/room/__tests__/Participant.test.js +14747 -0
  37. package/esm/simple/room/__tests__/RemoteParticipant.test.js +226 -27
  38. package/esm/simple/utils.js +226 -27
  39. package/esm/utils/__tests__/object.test.js +57 -0
  40. package/esm/utils/__tests__/string.test.js +30 -0
  41. package/esm/utils/object.js +24 -0
  42. package/esm/utils/string.js +10 -0
  43. package/esm/web-rtc-client.js +181 -24
  44. package/esm/websocket-client.js +3 -1
  45. package/lib/__tests__/api-client.test.js +142 -2
  46. package/lib/__tests__/web-rtc-client.test.js +227 -27
  47. package/lib/api/calld.js +8 -0
  48. package/lib/api/confd.js +134 -2
  49. package/lib/api-client.js +142 -2
  50. package/lib/checker/Checker.js +183 -24
  51. package/lib/checker/checks/aor.js +142 -2
  52. package/lib/checker/checks/api.js +142 -2
  53. package/lib/checker/checks/index.js +183 -24
  54. package/lib/checker/checks/wazo-websocket.js +2 -0
  55. package/lib/checker/checks/webrtc-transport.js +181 -24
  56. package/lib/checker/checks/webrtc.js +181 -24
  57. package/lib/domain/AdHocAPIConference.js +142 -2
  58. package/lib/domain/Features.js +142 -2
  59. package/lib/domain/Meeting.js +18 -0
  60. package/lib/domain/MeetingAuthorization.js +79 -0
  61. package/lib/domain/Phone/CTIPhone.js +142 -2
  62. package/lib/domain/__tests__/Meeting.test.js +87 -1
  63. package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
  64. package/lib/index.js +226 -27
  65. package/lib/service/CallApi.js +142 -2
  66. package/lib/service/getApiClient.js +142 -2
  67. package/lib/simple/Auth.js +226 -27
  68. package/lib/simple/Configuration.js +226 -27
  69. package/lib/simple/Directory.js +142 -2
  70. package/lib/simple/Phone.js +226 -27
  71. package/lib/simple/Websocket.js +3 -0
  72. package/lib/simple/index.js +226 -27
  73. package/lib/simple/room/LocalParticipant.js +226 -27
  74. package/lib/simple/room/Participant.js +226 -27
  75. package/lib/simple/room/RemoteParticipant.js +226 -27
  76. package/lib/simple/room/Room.js +226 -27
  77. package/lib/simple/room/SipRoom.js +226 -27
  78. package/lib/simple/room/Stream.js +226 -27
  79. package/lib/simple/room/__tests__/Participant.test.js +14757 -0
  80. package/lib/simple/room/__tests__/RemoteParticipant.test.js +226 -27
  81. package/lib/simple/utils.js +226 -27
  82. package/lib/utils/__tests__/object.test.js +59 -0
  83. package/lib/utils/__tests__/string.test.js +32 -0
  84. package/lib/utils/object.js +28 -0
  85. package/lib/utils/string.js +14 -0
  86. package/lib/web-rtc-client.js +181 -24
  87. package/lib/websocket-client.js +3 -0
  88. package/package.json +2 -2
  89. package/src/__tests__/web-rtc-client.test.js +46 -3
  90. package/src/api/calld.js +8 -0
  91. package/src/api/confd.js +43 -2
  92. package/src/domain/Meeting.js +20 -0
  93. package/src/domain/MeetingAuthorization.js +67 -0
  94. package/src/domain/__tests__/Meeting.test.js +70 -1
  95. package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
  96. package/src/simple/room/Participant.js +40 -0
  97. package/src/simple/room/Room.js +2 -2
  98. package/src/simple/room/SipRoom.js +1 -1
  99. package/src/simple/room/__tests__/Participant.test.js +81 -0
  100. package/src/types/WebSocketMessage.js +7 -1
  101. package/src/utils/__tests__/object.test.js +35 -0
  102. package/src/utils/__tests__/string.test.js +23 -0
  103. package/src/utils/object.js +15 -0
  104. package/src/utils/string.js +8 -0
  105. package/src/web-rtc-client.js +39 -22
  106. package/src/websocket-client.js +2 -0
@@ -2671,6 +2671,70 @@ class ExternalApp {
2671
2671
 
2672
2672
  //
2673
2673
 
2674
+ class MeetingAuthorization {
2675
+
2676
+
2677
+
2678
+
2679
+
2680
+
2681
+ constructor({
2682
+ meetingUuid,
2683
+ uuid,
2684
+ userUuid,
2685
+ userName,
2686
+ } = {}) {
2687
+ this.meetingUuid = meetingUuid;
2688
+ this.uuid = uuid;
2689
+ this.userUuid = userUuid;
2690
+ this.userName = userName;
2691
+ }
2692
+
2693
+ setStatus(status ) {
2694
+ this.status = status;
2695
+ }
2696
+
2697
+ getStatus() {
2698
+ return this.status;
2699
+ }
2700
+
2701
+ static parse(plain ) {
2702
+ const {
2703
+ meeting_uuid: meetingUuid,
2704
+ uuid,
2705
+ guest_uuid: userUuid,
2706
+ guest_name: userName,
2707
+ } = plain;
2708
+
2709
+ return new MeetingAuthorization({
2710
+ meetingUuid,
2711
+ uuid,
2712
+ userUuid,
2713
+ userName,
2714
+ });
2715
+ }
2716
+
2717
+ static parseMany(items ) {
2718
+ if (!items) {
2719
+ return [];
2720
+ }
2721
+ return items.map(MeetingAuthorization.parse);
2722
+ }
2723
+ }
2724
+
2725
+ //
2726
+
2727
+
2728
+
2729
+
2730
+
2731
+
2732
+
2733
+
2734
+
2735
+
2736
+
2737
+
2674
2738
 
2675
2739
 
2676
2740
 
@@ -2681,6 +2745,7 @@ class ExternalApp {
2681
2745
 
2682
2746
 
2683
2747
 
2748
+
2684
2749
 
2685
2750
 
2686
2751
  class Meeting {
@@ -2695,6 +2760,8 @@ class Meeting {
2695
2760
 
2696
2761
 
2697
2762
 
2763
+
2764
+
2698
2765
 
2699
2766
  static parse(plain ) {
2700
2767
  return new Meeting({
@@ -2707,6 +2774,7 @@ class Meeting {
2707
2774
  extension: plain.exten,
2708
2775
  persistent: plain.persistent,
2709
2776
  creationTime: moment(plain.creation_time).toDate(),
2777
+ requireAuthorization: plain.require_authorization,
2710
2778
  });
2711
2779
  }
2712
2780
 
@@ -2731,6 +2799,7 @@ class Meeting {
2731
2799
  extension,
2732
2800
  persistent,
2733
2801
  creationTime,
2802
+ requireAuthorization,
2734
2803
  } = {}) {
2735
2804
  this.guestSipAuthorization = guestSipAuthorization;
2736
2805
  this.uri = uri;
@@ -2741,6 +2810,7 @@ class Meeting {
2741
2810
  this.extension = extension;
2742
2811
  this.persistent = persistent;
2743
2812
  this.creationTime = creationTime;
2813
+ this.requireAuthorization = requireAuthorization;
2744
2814
 
2745
2815
  // Useful to compare instead of instanceof with minified code
2746
2816
  this.type = 'Meeting';
@@ -2751,8 +2821,32 @@ class Meeting {
2751
2821
  const [username, secret] = atob(this.guestSipAuthorization).split(':');
2752
2822
  return { username, secret };
2753
2823
  }
2824
+
2754
2825
  }
2755
2826
 
2827
+ //
2828
+
2829
+ const camelToUnderscore = (key ) => {
2830
+ if (typeof key !== 'string') {
2831
+ throw new Error('Input is not a string');
2832
+ }
2833
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
2834
+ };
2835
+
2836
+ //
2837
+
2838
+ const convertKeysFromCamelToUnderscore = (args ) => {
2839
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
2840
+ throw new Error('Input is not an object');
2841
+ }
2842
+
2843
+ return Object.keys(args).reduce((acc, key) => {
2844
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
2845
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
2846
+ return acc;
2847
+ }, {});
2848
+ };
2849
+
2756
2850
  /* */
2757
2851
 
2758
2852
  var confdMethods = (client , baseUrl ) => ({
@@ -2821,8 +2915,18 @@ var confdMethods = (client , baseUrl ) => ({
2821
2915
  getMyMeetings: () =>
2822
2916
  client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
2823
2917
 
2824
- createMyMeeting: (name , persistent ) =>
2825
- client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
2918
+ createMyMeeting: (args ) =>
2919
+ client
2920
+ .post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
2921
+ .then(Meeting.parse),
2922
+
2923
+ updateMyMeeting: (meetingUuid , data ) =>
2924
+ client.put(
2925
+ `${baseUrl}/users/me/meetings/${meetingUuid}`,
2926
+ convertKeysFromCamelToUnderscore(data),
2927
+ null,
2928
+ ApiRequester.successResponseParser,
2929
+ ),
2826
2930
 
2827
2931
  deleteMyMeeting: (meetingUuid ) =>
2828
2932
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -2830,8 +2934,36 @@ var confdMethods = (client , baseUrl ) => ({
2830
2934
  getMeeting: (meetingUuid ) =>
2831
2935
  client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2832
2936
 
2937
+ meetingAuthorizations: (meetingUuid ) =>
2938
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
2939
+
2940
+ meetingAuthorizationReject: (meetingUuid , authorizationUuid ) =>
2941
+ client.put(
2942
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
2943
+ {},
2944
+ null,
2945
+ ApiRequester.successResponseParser,
2946
+ ),
2947
+
2948
+ meetingAuthorizationAccept: (meetingUuid , authorizationUuid ) =>
2949
+ client.put(
2950
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
2951
+ {},
2952
+ null,
2953
+ ApiRequester.successResponseParser,
2954
+ ),
2955
+
2833
2956
  guestGetMeeting: (meetingUuid ) =>
2834
2957
  client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2958
+
2959
+ guestAuthorizationRequest: (userUuid , meetingUuid , username ) =>
2960
+ client
2961
+ .post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
2962
+ .then(MeetingAuthorization.parse),
2963
+
2964
+ guestAuthorizationCheck: (userUuid , meetingUuid , authorizationUuid ) =>
2965
+ client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
2966
+
2835
2967
  });
2836
2968
 
2837
2969
  //
@@ -5056,6 +5188,14 @@ var calldMethods = (client , baseUrl ) => ({
5056
5188
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
5057
5189
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
5058
5190
 
5191
+ banMeetingParticipant: (meetingUuid , participantUuid ) =>
5192
+ client.delete(
5193
+ `${baseUrl}/users/me/meetings/${meetingUuid}/participants/${participantUuid}`,
5194
+ null,
5195
+ null,
5196
+ ApiRequester.successResponseParser,
5197
+ ),
5198
+
5059
5199
  listTrunks: () => client.get(`${baseUrl}/trunks`),
5060
5200
 
5061
5201
  mute: (callId ) =>
@@ -7814,7 +7954,7 @@ class WebRTCClient extends Emitter {
7814
7954
  });
7815
7955
  }
7816
7956
 
7817
- changeAudioInputDevice(id , session , force ) {
7957
+ async changeAudioInputDevice(id , session , force ) {
7818
7958
  const currentId = this.getAudioDeviceId();
7819
7959
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7820
7960
 
@@ -7822,33 +7962,50 @@ class WebRTCClient extends Emitter {
7822
7962
  return null;
7823
7963
  }
7824
7964
 
7965
+ // in order to handle an audio track change for default devices
7966
+ // we need the actual id of the device (not 'default')
7967
+ let deviceId = id;
7968
+ if (id === 'default' && navigator.mediaDevices) {
7969
+ const devices = await navigator.mediaDevices.enumerateDevices();
7970
+ const defaultDevice = devices.find(device => device.deviceId === 'default');
7971
+ if (defaultDevice) {
7972
+ const deviceLabel = defaultDevice.label.replace('Default - ', '');
7973
+ const targetDevice = devices.find(device => device.label === deviceLabel);
7974
+ if (targetDevice) {
7975
+ deviceId = targetDevice.deviceId;
7976
+ if (!force && deviceId === currentId) {
7977
+ return null;
7978
+ }
7979
+ }
7980
+ }
7981
+ }
7982
+
7825
7983
  // let's update the local audio value
7826
7984
  if (this.audio) {
7827
7985
  this.audio = {
7828
7986
  deviceId: {
7829
- exact: id,
7987
+ exact: deviceId,
7830
7988
  },
7831
7989
  };
7832
7990
  }
7833
7991
 
7834
- if (session) {
7992
+ if (session && navigator.mediaDevices) {
7835
7993
  const sdh = session.sessionDescriptionHandler;
7836
7994
  const pc = sdh.peerConnection;
7837
7995
 
7838
- // $FlowFixMe
7839
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
7840
- const audioTrack = stream.getAudioTracks()[0];
7841
- const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
7996
+ const constraints = { audio: { deviceId: { exact: deviceId } } };
7997
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
7998
+ const audioTrack = stream.getAudioTracks()[0];
7999
+ const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
7842
8000
 
7843
- if (sender) {
7844
- if (sender.track) {
7845
- audioTrack.enabled = sender.track.enabled;
7846
- }
7847
- sender.replaceTrack(audioTrack);
8001
+ if (sender) {
8002
+ if (sender.track) {
8003
+ audioTrack.enabled = sender.track.enabled;
7848
8004
  }
8005
+ sender.replaceTrack(audioTrack);
8006
+ }
7849
8007
 
7850
- return stream;
7851
- });
8008
+ return stream;
7852
8009
  }
7853
8010
  }
7854
8011
 
@@ -7868,14 +8025,14 @@ class WebRTCClient extends Emitter {
7868
8025
  return null;
7869
8026
  }
7870
8027
 
7871
- // let's update the local video value
7872
- if (this.video) {
7873
- this.video = {
7874
- deviceId: {
7875
- exact: id,
7876
- },
7877
- };
7878
- }
8028
+ // let's make sure we don't lose other video constraints settings -- width, height, frameRate...
8029
+ const videoObject = typeof this.video === 'object' ? this.video : {};
8030
+ this.video = {
8031
+ ...videoObject,
8032
+ deviceId: {
8033
+ exact: id,
8034
+ },
8035
+ };
7879
8036
  }
7880
8037
 
7881
8038
  changeSessionVideoInputDevice(id , session ) {
@@ -11270,6 +11427,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
11270
11427
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
11271
11428
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
11272
11429
  const MEETING_USER_PROGRESS = 'meeting_user_progress';
11430
+ const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
11273
11431
 
11274
11432
  const BLACKLIST_EVENTS = [
11275
11433
  CHAT_MESSAGE_SENT,
@@ -11621,6 +11779,7 @@ WebSocketClient.eventLists = [
11621
11779
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11622
11780
  CONFERENCE_ADHOC_DELETED,
11623
11781
  MEETING_USER_PROGRESS,
11782
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11624
11783
  ];
11625
11784
 
11626
11785
  var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
@@ -11692,6 +11851,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
11692
11851
  CONFERENCE_ADHOC_PARTICIPANT_LEFT: CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11693
11852
  CONFERENCE_ADHOC_DELETED: CONFERENCE_ADHOC_DELETED,
11694
11853
  MEETING_USER_PROGRESS: MEETING_USER_PROGRESS,
11854
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED: MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11695
11855
  HEARTBEAT_ENGINE_VERSION: HEARTBEAT_ENGINE_VERSION,
11696
11856
  'default': WebSocketClient
11697
11857
  });
@@ -11789,7 +11949,7 @@ class SipRoom extends Room {
11789
11949
  logger$3.info('connecting to sip room', { extension, audioOnly, room: !!room });
11790
11950
 
11791
11951
  if (!room) {
11792
- await Wazo.Phone.connect();
11952
+ await Wazo.Phone.connect({ media: constraints });
11793
11953
 
11794
11954
  const withCamera = constraints && !!constraints.video;
11795
11955
 
@@ -13471,7 +13631,7 @@ class Room extends Emitter {
13471
13631
  logger$1.info('connecting to room', { extension, audioOnly, room: !!room });
13472
13632
 
13473
13633
  if (!room) {
13474
- await Wazo.Phone.connect();
13634
+ await Wazo.Phone.connect({ media: constraints });
13475
13635
 
13476
13636
  const withCamera = constraints && !!constraints.video;
13477
13637
 
@@ -13916,7 +14076,7 @@ class Room extends Emitter {
13916
14076
  const participant = this._getParticipantFromCallId(status.callId);
13917
14077
 
13918
14078
  if (participant) {
13919
- // we're received, so no need to broadcast, hence the input false arg
14079
+ // we're receiving, so no need to broadcast
13920
14080
  participant.updateStatus(status, false);
13921
14081
  }
13922
14082
  break;
@@ -14190,6 +14350,7 @@ class Participant extends Emitter {
14190
14350
 
14191
14351
 
14192
14352
 
14353
+
14193
14354
 
14194
14355
 
14195
14356
 
@@ -14207,6 +14368,7 @@ class Participant extends Emitter {
14207
14368
 
14208
14369
 
14209
14370
 
14371
+
14210
14372
 
14211
14373
  /**
14212
14374
  * @param room Room The room where the participant is
@@ -14230,6 +14392,7 @@ class Participant extends Emitter {
14230
14392
  this.screensharing = false;
14231
14393
  this.isOnHold = false;
14232
14394
  this.extra = extra;
14395
+ this.banned = false;
14233
14396
 
14234
14397
  this.ON_UPDATED = 'participant/ON_UPDATED';
14235
14398
  this.ON_START_TALKING = 'participant/ON_START_TALKING';
@@ -14246,6 +14409,7 @@ class Participant extends Emitter {
14246
14409
  this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
14247
14410
  this.ON_HOLD = 'participant/ON_HOLD';
14248
14411
  this.ON_RESUME = 'participant/ON_RESUME';
14412
+ this.ON_BAN = 'participant/ON_BAN';
14249
14413
  }
14250
14414
 
14251
14415
  triggerEvent(name , ...args ) {
@@ -14286,6 +14450,10 @@ class Participant extends Emitter {
14286
14450
  status.extra = this.extra;
14287
14451
  break;
14288
14452
  }
14453
+ case this.ON_BAN: {
14454
+ status.banned = true;
14455
+ break;
14456
+ }
14289
14457
  }
14290
14458
 
14291
14459
  if (broadcast) {
@@ -14388,6 +14556,11 @@ class Participant extends Emitter {
14388
14556
  this.triggerUpdate(this.ON_RESUME, broadcast);
14389
14557
  }
14390
14558
 
14559
+ onBan(broadcast = true) {
14560
+ this.banned = true;
14561
+ this.triggerUpdate(this.ON_BAN, broadcast);
14562
+ }
14563
+
14391
14564
  getStatus() {
14392
14565
  return {
14393
14566
  callId: this.callId,
@@ -14434,6 +14607,10 @@ class Participant extends Emitter {
14434
14607
  }
14435
14608
  }
14436
14609
 
14610
+ if (status.banned) {
14611
+ this.onBan(false);
14612
+ }
14613
+
14437
14614
  // Poor man's object comparison
14438
14615
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
14439
14616
  this.extra = { ...this.extra, ...status.extra };
@@ -14461,6 +14638,28 @@ class Participant extends Emitter {
14461
14638
  this.streams = streams;
14462
14639
  this.videoStreams = streams;
14463
14640
  }
14641
+
14642
+ async ban(apiRequestDelay = null) {
14643
+ const { meetingUuid } = this.room;
14644
+ if (!meetingUuid) {
14645
+ throw new Error('Attempting to ban a participant without a `meetingUuid`');
14646
+ }
14647
+
14648
+ // this notifies all that someone is being banned
14649
+ this.onBan(true);
14650
+
14651
+ // this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
14652
+ if (apiRequestDelay) {
14653
+ await this.delay(apiRequestDelay);
14654
+ }
14655
+
14656
+ // proceed with the actual kick
14657
+ return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
14658
+ }
14659
+
14660
+ async delay(ms ) {
14661
+ return new Promise(resolve => setTimeout(resolve, ms));
14662
+ }
14464
14663
  }
14465
14664
 
14466
14665
  //