@cometchat/calls-sdk-react-native 5.0.0-beta.1 → 5.0.0-beta.10

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.
package/dist/index.js CHANGED
@@ -35,6 +35,8 @@ let react = require("react");
35
35
  react = __toESM(react);
36
36
  let lib_jitsi_meet = require("lib-jitsi-meet");
37
37
  lib_jitsi_meet = __toESM(lib_jitsi_meet);
38
+ let __react_native_async_storage_async_storage = require("@react-native-async-storage/async-storage");
39
+ __react_native_async_storage_async_storage = __toESM(__react_native_async_storage_async_storage);
38
40
  let react_native = require("react-native");
39
41
  let react_native_webrtc = require("react-native-webrtc");
40
42
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -75,17 +77,24 @@ var EventBus = class {
75
77
  }
76
78
  }
77
79
  }
78
- subscribe(actionType, listener) {
80
+ subscribe(actionType, listener, options) {
81
+ if (options?.signal?.aborted) {
82
+ return () => {};
83
+ }
79
84
  if (!this.actionListenersMap.get(actionType)) {
80
85
  this.actionListenersMap.set(actionType, []);
81
86
  }
82
87
  this.actionListenersMap.get(actionType)?.push(listener);
83
- return () => {
88
+ const unsubscribe = () => {
84
89
  const listenersList = this.actionListenersMap.get(actionType);
85
90
  if (listenersList) {
86
91
  this.actionListenersMap.set(actionType, listenersList.filter((l) => l !== listener));
87
92
  }
88
93
  };
94
+ if (options?.signal) {
95
+ options.signal.addEventListener("abort", unsubscribe, { once: true });
96
+ }
97
+ return unsubscribe;
89
98
  }
90
99
  };
91
100
  const eventBus = new EventBus();
@@ -135,10 +144,12 @@ const VIDEO_QUALITY_LEVELS = {
135
144
  LOW: 180,
136
145
  NONE: 0
137
146
  };
138
- const PLATFORM = {
147
+ const SDK_PLATFORM = {
139
148
  WEB: "web",
140
149
  ANDROID: "android",
141
- IOS: "ios"
150
+ IOS: "ios",
151
+ REACT_NATIVE_ANDROID: "react-native-android",
152
+ REACT_NATIVE_IOS: "react-native-ios"
142
153
  };
143
154
  const EVENT_LISTENER_METHODS = {
144
155
  SessionStatusListener: {
@@ -253,7 +264,7 @@ function calculateTileLayout(containerWidth, containerHeight, numberOfTiles) {
253
264
  const tileArea = totalArea / numberOfTiles;
254
265
  const minArea = MIN_TILE_WIDTH * MIN_TILE_WIDTH * MIN_ASPECT_RATIO;
255
266
  if (tileArea < minArea) {
256
- const columnCount$1 = Math.floor(containerWidth / MIN_TILE_WIDTH);
267
+ const columnCount$1 = Math.max(2, Math.floor(containerWidth / MIN_TILE_WIDTH));
257
268
  const rowCount$1 = Math.ceil(numberOfTiles / columnCount$1);
258
269
  const totalHorizontalGap$1 = columnCount$1 * GRID_GAP;
259
270
  const tileWidth$1 = (containerWidth - totalHorizontalGap$1) / columnCount$1;
@@ -436,12 +447,37 @@ function isDeviceEqual(device1, device2) {
436
447
  function getDefaultDevice(devices) {
437
448
  return devices.find((device) => device.deviceId === "default") || devices[0];
438
449
  }
450
+ /**
451
+ * Returns a promise that resolves when the given Zustand store
452
+ * satisfies the provided predicate. Resolves immediately if the
453
+ * condition is already met. Includes a timeout to avoid hanging
454
+ * forever (defaults to 5 000 ms).
455
+ */
456
+ function waitForStoreState(store, predicate, timeoutMs = 5e3) {
457
+ return new Promise((resolve, reject) => {
458
+ if (predicate(store.getState())) {
459
+ resolve();
460
+ return;
461
+ }
462
+ const timer = setTimeout(() => {
463
+ unsubscribe();
464
+ reject(new Error("waitForStoreState timed out"));
465
+ }, timeoutMs);
466
+ const unsubscribe = store.subscribe((state) => {
467
+ if (predicate(state)) {
468
+ clearTimeout(timer);
469
+ unsubscribe();
470
+ resolve();
471
+ }
472
+ });
473
+ });
474
+ }
439
475
 
440
476
  //#endregion
441
477
  //#region calls-sdk-core/utils/try-catch.ts
442
- async function tryCatch(promise) {
478
+ async function tryCatch(promise, timeoutMs) {
443
479
  try {
444
- const data = await promise;
480
+ const data = timeoutMs != null ? await Promise.race([promise, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs))]) : await promise;
445
481
  return {
446
482
  data,
447
483
  error: null
@@ -485,76 +521,163 @@ function debounce(func, delay) {
485
521
  //#endregion
486
522
  //#region calls-sdk-core/utils/session-methods-core.ts
487
523
  var SessionMethodsCore = class {
524
+ /**
525
+ * Mutes the local user's audio during the call.
526
+ */
488
527
  static muteAudio() {
489
528
  muteAudioTrack();
490
529
  }
530
+ /**
531
+ * Unmutes the local user's audio during the call.
532
+ */
491
533
  static unmuteAudio() {
492
534
  unMuteAudioTrack();
493
535
  }
536
+ /**
537
+ * Toggles the local user's audio mute state.
538
+ * If audio is muted, it will be unmuted, and vice versa.
539
+ */
540
+ static toggleAudio() {
541
+ toggleAudioTrack();
542
+ }
543
+ /**
544
+ * Pauses the local user's video stream.
545
+ */
494
546
  static pauseVideo() {
495
547
  pauseVideoTrack();
496
548
  }
549
+ /**
550
+ * Resumes the local user's video stream.
551
+ */
497
552
  static resumeVideo() {
498
553
  resumeVideoTrack();
499
554
  }
555
+ /**
556
+ * Toggles the local user's video stream.
557
+ * If video is paused, it will be resumed, and vice versa.
558
+ */
559
+ static toggleVideo() {
560
+ toggleVideoTrack();
561
+ }
562
+ /**
563
+ * Local user leaves the current session.
564
+ */
500
565
  static leaveSession() {
501
566
  leaveSession();
502
567
  }
503
- static startScreenSharing() {
504
- startScreenSharing();
505
- }
506
- static stopScreenSharing() {
507
- stopScreenSharing();
568
+ /**
569
+ * Ends the current session for all participants.
570
+ * This will terminate the conference and disconnect everyone.
571
+ */
572
+ static endSessionForAll() {
573
+ leaveSession({ shouldEndSession: true });
508
574
  }
575
+ /**
576
+ * Raises the user's virtual hand in the call.
577
+ */
509
578
  static raiseHand() {
510
579
  raisedHandLocal();
511
580
  }
581
+ /**
582
+ * Lowers the user's virtual hand in the call.
583
+ */
512
584
  static lowerHand() {
513
585
  lowerHandLocal();
514
586
  }
587
+ /**
588
+ * Toggles the user's virtual hand state.
589
+ * If the hand is raised, it will be lowered, and vice versa.
590
+ */
591
+ static toggleHand() {
592
+ toggleRaiseHand();
593
+ }
594
+ /**
595
+ * Switches between the front and rear camera.
596
+ */
515
597
  static switchCamera() {
516
598
  switchCamera();
517
599
  }
600
+ /**
601
+ * Sets the layout type for the call.
602
+ * @param layout - The type of layout to set (tile, sidebar or spotlight).
603
+ */
518
604
  static setLayout(layout$1) {
519
605
  setLayout(layout$1);
520
606
  }
521
- static startRecording() {}
522
- static stopRecording() {}
523
- static enablePictureInPictureLayout() {
524
- enablePictureInPictureLayout();
607
+ /**
608
+ * Starts recording the call.
609
+ */
610
+ static startRecording() {
611
+ startRecording();
525
612
  }
526
- static disablePictureInPictureLayout() {
527
- disablePictureInPictureLayout();
613
+ /**
614
+ * Stops the ongoing call recording.
615
+ */
616
+ static stopRecording() {
617
+ stopRecording();
618
+ }
619
+ /**
620
+ * Toggles the call recording state.
621
+ * If recording is active, it will be stopped, and vice versa.
622
+ */
623
+ static toggleRecording() {
624
+ toggleRecording();
528
625
  }
626
+ /**
627
+ * Pins a participant's video to focus on them.
628
+ * @param participantId - The ID of the participant to pin.
629
+ * @param type - The type of the participant.
630
+ */
529
631
  static pinParticipant(participantId, type) {
530
632
  pinParticipant(participantId, type);
531
633
  }
634
+ /**
635
+ * Unpins a participant's video.
636
+ */
532
637
  static unpinParticipant() {
533
638
  unpinParticipant();
534
639
  }
640
+ /**
641
+ * Mutes the audio of a specific participant.
642
+ * @param participantId - The ID of the participant to mute.
643
+ */
535
644
  static muteParticipant(participantId) {
536
645
  muteParticipant(participantId);
537
646
  }
647
+ /**
648
+ * Pauses the video stream of a specific participant.
649
+ * @param participantId - The ID of the participant whose video to pause.
650
+ */
538
651
  static pauseParticipantVideo(participantId) {
539
652
  pauseParticipantVideo(participantId);
540
653
  }
654
+ /**
655
+ * Sets the unread message count displayed on the chat button.
656
+ * @param count - The number of unread messages.
657
+ */
541
658
  static setChatButtonUnreadCount(count) {
542
659
  setChatButtonUnreadCount(count);
543
660
  }
544
661
  /**
545
- * @deprecated use startScreenSharing() instead
662
+ * Toggles the visibility of the participant list panel.
546
663
  */
547
- static startScreenShare() {
548
- this.startScreenSharing();
664
+ static toggleParticipantList() {
665
+ toggleParticipantList();
549
666
  }
550
667
  /**
551
- * @deprecated use stopScreenSharing() instead
668
+ * Shows the participant list panel.
552
669
  */
553
- static stopScreenShare() {
554
- this.stopScreenSharing();
670
+ static showParticipantList() {
671
+ showParticipantList();
555
672
  }
556
673
  /**
557
- * @deprecated switchToVideoCall is deprecated and not supported
674
+ * Hides the participant list panel.
675
+ */
676
+ static hideParticipantList() {
677
+ hideParticipantList();
678
+ }
679
+ /**
680
+ * @deprecated switchToVideoCall is deprecated and not supported.
558
681
  */
559
682
  static switchToVideoCall() {
560
683
  console.error("switchToVideoCall method deprecated and not supported.");
@@ -644,6 +767,27 @@ async function createLocalTrack(type, deviceId = null, cameraFacing = CAMERA_FAC
644
767
  }
645
768
  }
646
769
  }
770
+ function createLocalTracks() {
771
+ const enableCompanionMode = useConfigStore.getState().enableCompanionMode;
772
+ if (!enableCompanionMode) {
773
+ const audioInputDeviceId = useConfigStore.getState().audioInputDeviceId ?? useBaseStore.getState().audioInputDevice?.deviceId;
774
+ createLocalTrack("audio", audioInputDeviceId);
775
+ }
776
+ const sessionType = useConfigStore.getState().sessionType;
777
+ if (sessionType === SESSION_TYPE.VIDEO) {
778
+ const videoInputDeviceIdP1 = useConfigStore.getState().videoInputDeviceId;
779
+ const videoInputDeviceIdP2 = useBaseStore.getState().videoInputDevice?.deviceId;
780
+ const initialCameraFacingP1 = useConfigStore.getState().initialCameraFacing;
781
+ const initialCameraFacingP2 = useBaseStore.getState().cameraFacing;
782
+ if (videoInputDeviceIdP1) {
783
+ createLocalTrack("video", videoInputDeviceIdP1);
784
+ } else if (initialCameraFacingP1) {
785
+ createLocalTrack("video", null, initialCameraFacingP2);
786
+ } else {
787
+ createLocalTrack("video", videoInputDeviceIdP2, initialCameraFacingP2);
788
+ }
789
+ }
790
+ }
647
791
  function updateAudioInputDevice(deviceId) {
648
792
  const audioInputDevices = useBaseStore.getState().audioInputDevices.filter((device) => device.deviceId !== "");
649
793
  if (audioInputDevices.length > 0) {
@@ -825,7 +969,7 @@ function sendParticipantListChangedEvent() {
825
969
 
826
970
  //#endregion
827
971
  //#region calls-sdk-core/store/config.ts
828
- const initialState$7 = {
972
+ const initialState$8 = {
829
973
  sessionType: "VIDEO",
830
974
  autoStartRecording: false,
831
975
  layout: LAYOUT.TILE,
@@ -843,7 +987,6 @@ const initialState$7 = {
843
987
  hideLeaveSessionButton: false,
844
988
  hideToggleAudioButton: false,
845
989
  hideParticipantListButton: false,
846
- hideSwitchLayoutButton: false,
847
990
  hideChatButton: true,
848
991
  hideToggleVideoButton: false,
849
992
  hideScreenSharingButton: false,
@@ -856,13 +999,17 @@ const initialState$7 = {
856
999
  startVideoPaused: false,
857
1000
  title: "",
858
1001
  enableNoiseReduction: false,
1002
+ unstable_renderAudioOnly: false,
859
1003
  idleTimeoutPeriodBeforePrompt: 6e4,
860
1004
  idleTimeoutPeriodAfterPrompt: 18e4,
861
1005
  enableSpotlightDrag: true,
862
1006
  enableSpotlightSwap: true,
863
- showFrameRate: false
1007
+ showFrameRate: false,
1008
+ enableCompanionMode: false,
1009
+ isPeerCall: false,
1010
+ enableNotifications: true
864
1011
  };
865
- const useConfigStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$7, (set) => ({ reset: () => set(initialState$7) }))));
1012
+ const useConfigStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$8, (set) => ({ reset: () => set(initialState$8) }))));
866
1013
  const setConfig = (config) => {
867
1014
  useConfigStore.setState(config);
868
1015
  };
@@ -880,18 +1027,24 @@ const initialLocalParticipant = {
880
1027
  type: "human",
881
1028
  uid: "unknown"
882
1029
  };
883
- const initialState$6 = {
1030
+ const initialState$7 = {
884
1031
  dominantSpeakers: [],
885
1032
  localParticipant: initialLocalParticipant,
886
1033
  participants: [],
887
1034
  virtualParticipants: []
888
1035
  };
889
- const useParticipantStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$6, (set, get$1) => ({
1036
+ const useParticipantStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$7, (set, get$1) => ({
890
1037
  addParticipant: (participant) => {
891
- set((state) => ({ participants: [...state.participants, participant] }));
1038
+ set((state) => ({ participants: state.participants.some((p) => p.pid === participant.pid) ? state.participants.map((p) => p.pid === participant.pid ? {
1039
+ ...p,
1040
+ ...participant
1041
+ } : p) : [...state.participants, participant] }));
892
1042
  },
893
1043
  addVirtualParticipant: (participant) => {
894
- set((state) => ({ virtualParticipants: [...state.virtualParticipants, participant] }));
1044
+ set((state) => ({ virtualParticipants: state.virtualParticipants.some((p) => p.pid === participant.pid && p.type === participant.type) ? state.virtualParticipants.map((p) => p.pid === participant.pid && p.type === participant.type ? {
1045
+ ...p,
1046
+ ...participant
1047
+ } : p) : [...state.virtualParticipants, participant] }));
895
1048
  },
896
1049
  clearParticipants: () => set({
897
1050
  participants: [],
@@ -961,7 +1114,7 @@ const useParticipantStore = (0, zustand.create)()((0, zustand_middleware.subscri
961
1114
  }
962
1115
  return get$1().participants.find((p) => p.pid === pid);
963
1116
  },
964
- reset: () => set(initialState$6)
1117
+ reset: () => set(initialState$7)
965
1118
  }))));
966
1119
  function useAllParticipants() {
967
1120
  const localParticipant = useParticipantStore((state) => state.localParticipant);
@@ -1095,7 +1248,7 @@ useParticipantStore.subscribe((state) => state.participants.filter((p) => p.uid)
1095
1248
 
1096
1249
  //#endregion
1097
1250
  //#region calls-sdk-core/store/conference.ts
1098
- const initialState$5 = {
1251
+ const initialState$6 = {
1099
1252
  conference: null,
1100
1253
  conferenceJoined: false,
1101
1254
  conferenceJoinedAt: null,
@@ -1110,7 +1263,7 @@ const initialState$5 = {
1110
1263
  },
1111
1264
  isRecording: false
1112
1265
  };
1113
- const useConferenceStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$5, (set) => ({
1266
+ const useConferenceStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$6, (set) => ({
1114
1267
  conferenceWillJoin: (conference) => {
1115
1268
  if (typeof window?.APP !== "undefined") {
1116
1269
  window.APP.conference._room = conference;
@@ -1121,13 +1274,15 @@ const useConferenceStore = (0, zustand.create)()((0, zustand_middleware.subscrib
1121
1274
  });
1122
1275
  },
1123
1276
  reset: () => {
1124
- set(initialState$5);
1277
+ set(initialState$6);
1125
1278
  },
1126
1279
  raiseHand: (participantId, timestamp) => {
1127
1280
  set((state) => ({ raiseHandMap: new Map(state.raiseHandMap).set(participantId, timestamp) }));
1128
1281
  sendParticipantEvent(EVENT_LISTENER_METHODS.ParticipantEventsListner.onParticipantHandRaised, participantId);
1129
1282
  },
1130
1283
  lowerHand: (participantId) => {
1284
+ const hasRaisedHand = useConferenceStore.getState().raiseHandMap.has(participantId);
1285
+ if (!hasRaisedHand) return;
1131
1286
  set((state) => {
1132
1287
  const raiseHandMap = new Map(state.raiseHandMap);
1133
1288
  raiseHandMap.delete(participantId);
@@ -1138,13 +1293,22 @@ const useConferenceStore = (0, zustand.create)()((0, zustand_middleware.subscrib
1138
1293
  leaveConference: async () => {
1139
1294
  const conference = useConferenceStore.getState().conference;
1140
1295
  if (conference) {
1141
- const { error } = await tryCatch(conference.leave());
1296
+ const { error } = await tryCatch(conference.leave(), 500);
1142
1297
  if (error) {
1143
1298
  console.warn("Error leaving conference:", error);
1144
1299
  eventBus.publish({ type: EVENT_LISTENER_METHODS.SessionStatusListener.onSessionLeft });
1145
1300
  }
1146
1301
  }
1147
1302
  },
1303
+ endConference: async () => {
1304
+ const conference = useConferenceStore.getState().conference;
1305
+ if (conference) {
1306
+ const { error } = await tryCatch(conference.end());
1307
+ if (error) {
1308
+ console.warn("Error ending conference:", error);
1309
+ }
1310
+ }
1311
+ },
1148
1312
  stopRecording: async () => {
1149
1313
  const conference = useConferenceStore.getState().conference;
1150
1314
  if (conference) {
@@ -1284,7 +1448,7 @@ useConferenceStore.subscribe((state) => state.conference, (conference) => {
1284
1448
 
1285
1449
  //#endregion
1286
1450
  //#region calls-sdk-core/store/tracks.ts
1287
- const initialState$4 = {
1451
+ const initialState$5 = {
1288
1452
  tracks: [],
1289
1453
  permissions: {
1290
1454
  audio: false,
@@ -1292,9 +1456,9 @@ const initialState$4 = {
1292
1456
  initialized: false
1293
1457
  }
1294
1458
  };
1295
- const useTracksStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$4, (set, get$1) => ({
1459
+ const useTracksStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$5, (set, get$1) => ({
1296
1460
  reset: () => set({
1297
- ...initialState$4,
1461
+ ...initialState$5,
1298
1462
  permissions: get$1().permissions
1299
1463
  }),
1300
1464
  addTrack: (originalTrack) => set((state) => {
@@ -1316,6 +1480,12 @@ const useTracksStore = (0, zustand.create)()((0, zustand_middleware.subscribeWit
1316
1480
  muted: originalTrack.isMuted() ? 1 : 0,
1317
1481
  originalTrack
1318
1482
  };
1483
+ const existingIdx = state.tracks.findIndex((t) => t.pid === participantId && t.mediaType === track.mediaType && t.local === isLocal);
1484
+ if (existingIdx !== -1) {
1485
+ const tracks = [...state.tracks];
1486
+ tracks[existingIdx] = track;
1487
+ return { tracks };
1488
+ }
1319
1489
  return { tracks: [...state.tracks, track] };
1320
1490
  }),
1321
1491
  removeTrack: (originalTrack) => set((state) => ({ tracks: state.tracks.filter((track) => track.originalTrack !== originalTrack) })),
@@ -1517,8 +1687,13 @@ useTracksStore.subscribe((state) => state.tracks.find((t) => t.mediaType === MED
1517
1687
  }
1518
1688
  if (track) {
1519
1689
  const deviceId = track.getDeviceId();
1520
- const device = useBaseStore.getState().audioInputDevices.find((d) => d.deviceId === deviceId);
1521
- updateAudioInputDeviceState(device, true);
1690
+ waitForStoreState(useBaseStore, (state) => state.audioInputDevices.length > 0).then(() => {
1691
+ const audioInputDevices = useBaseStore.getState().audioInputDevices;
1692
+ const device = audioInputDevices.find((d) => d.deviceId === deviceId);
1693
+ updateAudioInputDeviceState(device, true);
1694
+ }).catch(() => {
1695
+ updateAudioInputDeviceState(undefined, true);
1696
+ });
1522
1697
  }
1523
1698
  });
1524
1699
  useTracksStore.subscribe((state) => state.tracks.find((t) => t.mediaType === MEDIA_TYPE.VIDEO && t.local)?.originalTrack, (track, prevTrack) => {
@@ -1665,7 +1840,7 @@ function updateConfig(config) {
1665
1840
 
1666
1841
  //#endregion
1667
1842
  //#region calls-sdk-core/store/base.ts
1668
- const initialState$3 = {
1843
+ const initialState$4 = {
1669
1844
  audioModeMenuVisible: false,
1670
1845
  audioModes: [],
1671
1846
  audioInputDevices: [],
@@ -1700,20 +1875,24 @@ const initialState$3 = {
1700
1875
  desktopSharingFrameRate: 5,
1701
1876
  chatButtonUnreadCount: 0,
1702
1877
  enableNoiseReduction: true,
1703
- sdkPlatform: PLATFORM.WEB,
1878
+ sdkPlatform: SDK_PLATFORM.WEB,
1704
1879
  webOSName: "unknown",
1705
1880
  isMobileBrowser: false,
1706
1881
  visibleParticipants: {
1707
1882
  startIndex: 0,
1708
1883
  endIndex: 0
1884
+ },
1885
+ sidebarVisibleParticipants: {
1886
+ startIndex: 0,
1887
+ endIndex: 0
1709
1888
  }
1710
1889
  };
1711
- const useBaseStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.persist)((0, zustand_middleware.combine)(initialState$3, (set, get$1) => ({
1890
+ const useBaseStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.persist)((0, zustand_middleware.combine)(initialState$4, (set, get$1) => ({
1712
1891
  addSubscriptions: (subscriptions) => {
1713
1892
  useBaseStore.setState((state) => ({ subscriptions: [...state.subscriptions, ...subscriptions] }));
1714
1893
  },
1715
1894
  reset: () => set((state) => ({
1716
- ...initialState$3,
1895
+ ...initialState$4,
1717
1896
  audioInputDevice: state.audioInputDevice,
1718
1897
  audioOutputDevice: state.audioOutputDevice,
1719
1898
  videoInputDevice: state.videoInputDevice,
@@ -1724,11 +1903,11 @@ const useBaseStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithS
1724
1903
  toggleParticipantListVisible: () => set((state) => ({ participantListVisible: !state.participantListVisible })),
1725
1904
  incrementConnectionRetryCount: () => set((state) => ({ connectionRetryCount: state.connectionRetryCount + 1 })),
1726
1905
  isMobileSDK: () => {
1727
- const isMobileSDK = get$1().sdkPlatform === "android" || get$1().sdkPlatform === "ios";
1906
+ const isMobileSDK = get$1().sdkPlatform !== "web";
1728
1907
  return isMobileSDK;
1729
1908
  },
1730
1909
  isMobile: () => {
1731
- const isMobileSDK = get$1().sdkPlatform === "android" || get$1().sdkPlatform === "ios";
1910
+ const isMobileSDK = get$1().sdkPlatform !== "web";
1732
1911
  const isMobileBrowser = get$1().isMobileBrowser;
1733
1912
  return isMobileSDK || isMobileBrowser;
1734
1913
  },
@@ -1774,6 +1953,7 @@ const useBaseStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithS
1774
1953
  const toggleParticipantListVisible = useBaseStore.getState().toggleParticipantListVisible;
1775
1954
  const hideParticipantList = () => useBaseStore.setState({ participantListVisible: false });
1776
1955
  const showParticipantList = () => useBaseStore.setState({ participantListVisible: true });
1956
+ const toggleParticipantList = () => useBaseStore.setState((state) => ({ participantListVisible: !state.participantListVisible }));
1777
1957
  const toggleMoreMenuVisible = useBaseStore.getState().toggleMoreMenuVisible;
1778
1958
  const toggleAudioModeMenuVisible = () => {
1779
1959
  useBaseStore.setState((state) => ({ audioModeMenuVisible: !state.audioModeMenuVisible }));
@@ -1822,6 +2002,9 @@ const toggleEnableNoiseReduction = () => {
1822
2002
  const setChatButtonUnreadCount = (count) => {
1823
2003
  useBaseStore.setState({ chatButtonUnreadCount: count });
1824
2004
  };
2005
+ const setAudioMode = (mode) => {
2006
+ useBaseStore.setState({ selectedAudioModeType: mode });
2007
+ };
1825
2008
  const getLayout = () => {
1826
2009
  return useBaseStore.getState().layout;
1827
2010
  };
@@ -1944,13 +2127,13 @@ initBaseStoreSubscriptions();
1944
2127
 
1945
2128
  //#endregion
1946
2129
  //#region calls-sdk-core/store/connection.ts
1947
- const initialState$2 = {
2130
+ const initialState$3 = {
1948
2131
  connection: undefined,
1949
2132
  connectionStatus: "initial",
1950
2133
  error: undefined,
1951
2134
  timeEstablished: undefined
1952
2135
  };
1953
- const useConnectionStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$2, (set) => ({
2136
+ const useConnectionStore = (0, zustand.create)()((0, zustand_middleware.subscribeWithSelector)((0, zustand_middleware.combine)(initialState$3, (set) => ({
1954
2137
  connectionEstablished: (connection) => set({
1955
2138
  connection,
1956
2139
  connectionStatus: "connected",
@@ -1983,17 +2166,88 @@ const useConnectionStore = (0, zustand.create)()((0, zustand_middleware.subscrib
1983
2166
  eventBus.stopEmitting();
1984
2167
  await tryCatch(connection.disconnect());
1985
2168
  eventBus.publish({ type: EVENT_LISTENER_METHODS.SessionStatusListener.onConnectionClosed }, true);
1986
- set(initialState$2);
2169
+ set(initialState$3);
1987
2170
  }
1988
2171
  },
1989
- reset: () => set(initialState$2)
2172
+ reset: () => set(initialState$3)
1990
2173
  }))));
2174
+ function waitForConnection() {
2175
+ const { connectionStatus } = useConnectionStore.getState();
2176
+ if (connectionStatus === "connected") return Promise.resolve();
2177
+ return new Promise((resolve, reject) => {
2178
+ const timeout = setTimeout(() => {
2179
+ unsub();
2180
+ reject(new Error("Connection timed out after 3 seconds"));
2181
+ }, 3e3);
2182
+ const unsub = useConnectionStore.subscribe((s) => s.connectionStatus, (status) => {
2183
+ if (status === "connected") {
2184
+ clearTimeout(timeout);
2185
+ unsub();
2186
+ resolve();
2187
+ } else if (status === "error") {
2188
+ clearTimeout(timeout);
2189
+ unsub();
2190
+ reject(useConnectionStore.getState().error);
2191
+ }
2192
+ });
2193
+ });
2194
+ }
2195
+
2196
+ //#endregion
2197
+ //#region calls-sdk-core/store/toast.ts
2198
+ const MAX_TOASTS = 3;
2199
+ const initialState$2 = { toasts: [] };
2200
+ let counter = 0;
2201
+ const useToastStore = (0, zustand.create)((set) => ({
2202
+ ...initialState$2,
2203
+ addToast: (toast) => {
2204
+ if (!getIsConferenceJoined()) {
2205
+ return "";
2206
+ }
2207
+ if (!useConfigStore.getState().enableNotifications) {
2208
+ return "";
2209
+ }
2210
+ const id = `toast-${++counter}-${Date.now()}`;
2211
+ const newToast = {
2212
+ ...toast,
2213
+ id,
2214
+ createdAt: Date.now()
2215
+ };
2216
+ set((state) => {
2217
+ const updated = [...state.toasts, newToast];
2218
+ if (updated.length > MAX_TOASTS) {
2219
+ return { toasts: updated.slice(-MAX_TOASTS) };
2220
+ }
2221
+ return { toasts: updated };
2222
+ });
2223
+ return id;
2224
+ },
2225
+ removeToast: (id) => {
2226
+ set((state) => ({ toasts: state.toasts.filter((t) => t.id !== id) }));
2227
+ },
2228
+ clearAll: () => {
2229
+ set(initialState$2);
2230
+ },
2231
+ reset: () => {
2232
+ set(initialState$2);
2233
+ }
2234
+ }));
2235
+ function showToast(params) {
2236
+ return useToastStore.getState().addToast({
2237
+ message: params.message,
2238
+ type: params.type ?? "info",
2239
+ duration: params.duration ?? 3e3,
2240
+ position: params.position ?? "bottom",
2241
+ action: params.action
2242
+ });
2243
+ }
1991
2244
 
1992
2245
  //#endregion
1993
2246
  //#region calls-sdk-core/store/utils/hooks.ts
1994
2247
  const useHideMuteAudioButton = () => {
1995
2248
  const hideMuteAudioButton = useConfigStore((state) => state.hideToggleAudioButton);
1996
- return hideMuteAudioButton;
2249
+ const enableCompanionMode = useConfigStore((state) => state.enableCompanionMode);
2250
+ return hideMuteAudioButton || enableCompanionMode;
1997
2251
  };
1998
2252
  const useHideToggleVideoButton = () => {
1999
2253
  const hideToggleVideoButton = useConfigStore((state) => state.hideToggleVideoButton);
@@ -2015,7 +2269,7 @@ const useHideScreenSharingButton = () => {
2015
2269
  const useHideSwitchCameraButton = () => {
2016
2270
  const videoTrack = getLocalTrack(MEDIA_TYPE.VIDEO);
2017
2271
  const hideSwitchCameraButton = useConfigStore((state) => state.hideSwitchCameraButton);
2018
- return hideSwitchCameraButton || !videoTrack;
2272
+ return hideSwitchCameraButton || !videoTrack?.originalTrack;
2019
2273
  };
2020
2274
  const useHideChatButton = () => {
2021
2275
  const hideChatButton = useConfigStore((state) => state.hideChatButton);
@@ -2060,8 +2314,21 @@ const getMainParticipant = () => {
2060
2314
  const useIsReconnecting = () => {
2061
2315
  const connectionStatus = useConnectionStore((state) => state.connectionStatus);
2062
2316
  const conferenceStatus = useConferenceStore((state) => state.conferenceStatus);
2063
- const reconnecting = connectionStatus === "connected" && conferenceStatus === "interrupted";
2064
- return reconnecting;
2317
+ const isP2P = useConferenceStore((state) => state.p2p);
2318
+ const [isOnline, setIsOnline] = (0, react.useState)(true);
2319
+ (0, react.useEffect)(() => {
2320
+ if (typeof window === "undefined") return;
2321
+ const controller = new AbortController();
2322
+ const { signal } = controller;
2323
+ window.addEventListener("online", () => setIsOnline(true), { signal });
2324
+ window.addEventListener("offline", () => setIsOnline(false), { signal });
2325
+ return () => controller.abort();
2326
+ }, []);
2327
+ const interrupted = connectionStatus === "connected" && conferenceStatus === "interrupted";
2328
+ if (isP2P && interrupted && isOnline) {
2329
+ return false;
2330
+ }
2331
+ return interrupted;
2065
2332
  };
2066
2333
  const useHideRecordingButton = () => {
2067
2334
  const hideRecordingButton = useConfigStore((state) => state.hideRecordingButton);
@@ -2139,6 +2406,11 @@ const useIsVideoInputSelectionSupported = () => {
2139
2406
  const isVideoInputSelectionSupported = hasVideoPermission && videoInputDevices.length > 0;
2140
2407
  return isVideoInputSelectionSupported;
2141
2408
  };
2409
+ const useShouldMirrorLocalVideo = () => {
2410
+ const mirrorLocalVideo = useBaseStore((state) => state.mirrorLocalVideo);
2411
+ const cameraFacing = useBaseStore((state) => state.cameraFacing);
2412
+ return cameraFacing === "user" && mirrorLocalVideo;
2413
+ };
2142
2414
 
2143
2415
  //#endregion
2144
2416
  //#region calls-sdk-core/store/utils/switch-camera.ts
@@ -2187,8 +2459,10 @@ function setReceiverConstraintsInternal() {
2187
2459
  }
2188
2460
  });
2189
2461
  } else if (layout$1 === "SIDEBAR") {
2190
- const participants = useParticipantStore.getState().participants;
2191
- participants.forEach((participant) => {
2462
+ const { startIndex, endIndex } = useBaseStore.getState().sidebarVisibleParticipants;
2463
+ const allParticipants = getAllParticipants();
2464
+ const visibleSidebarParticipants = allParticipants.slice(startIndex, endIndex);
2465
+ visibleSidebarParticipants.forEach((participant) => {
2192
2466
  const videoSources$1 = participant.sources?.get("video");
2193
2467
  if (videoSources$1) {
2194
2468
  Array.from(videoSources$1.keys()).forEach((source) => {
@@ -2214,6 +2488,9 @@ const setReceiverConstraints = debounce(setReceiverConstraintsInternal, 200);
2214
2488
  useBaseStore.subscribe((state) => state.visibleParticipants, () => {
2215
2489
  setReceiverConstraints();
2216
2490
  });
2491
+ useBaseStore.subscribe((state) => state.sidebarVisibleParticipants, () => {
2492
+ setReceiverConstraints();
2493
+ });
2217
2494
  useBaseStore.subscribe((state) => state.layout, () => {
2218
2495
  setReceiverConstraints();
2219
2496
  });
@@ -2311,8 +2588,12 @@ var ConferenceListener = class {
2311
2588
  track.removeAllListeners(lib_jitsi_meet.default.events.track.NO_DATA_FROM_SOURCE);
2312
2589
  }
2313
2590
  onConferenceJoinInProgress() {}
2314
- onConferenceFailed(_conference, error, message) {
2315
- console.error("Conference failed:", error, message);
2591
+ onConferenceFailed(errorName, error, message) {
2592
+ if (errorName === lib_jitsi_meet.default.errors.conference.CONFERENCE_DESTROYED) {
2593
+ leaveSession({ forceLeave: true });
2594
+ return;
2595
+ }
2596
+ console.error("Conference failed:", errorName, error, message);
2316
2597
  useConferenceStore.setState({
2317
2598
  conferenceStatus: "error",
2318
2599
  conferenceJoined: false,
@@ -2347,6 +2628,7 @@ var ConferenceListener = class {
2347
2628
  }
2348
2629
  onConnectionEstablished() {
2349
2630
  useConferenceStore.setState({ conferenceStatus: "joined" });
2631
+ setTimeout(setReceiverConstraints, 500);
2350
2632
  }
2351
2633
  onConnectionInterrupted() {
2352
2634
  useConferenceStore.setState({ conferenceStatus: "interrupted" });
@@ -2358,17 +2640,19 @@ var ConferenceListener = class {
2358
2640
  useConferenceStore.setState({ p2p });
2359
2641
  }
2360
2642
  onTrackMuteChanged(track, participantThatMutedUs) {
2361
- if (participantThatMutedUs) {
2362
- useTracksStore.getState().updateTrack(track, { muted: track.isMuted() ? 1 : 0 });
2363
- const displayName = participantThatMutedUs.getDisplayName();
2364
- if (displayName) {
2365
- eventBus.publish({
2366
- type: INTERNAL_EVENTS.notification,
2367
- payload: {
2368
- type: "info",
2369
- message: `${displayName} has muted you.`
2370
- }
2371
- });
2643
+ if (track.isLocal()) {
2644
+ useTracksStore.getState().updateLocalTrack(track.getType(), { muted: track.isMuted() ? 1 : 0 });
2645
+ if (participantThatMutedUs) {
2646
+ const displayName = participantThatMutedUs.getDisplayName();
2647
+ if (displayName) {
2648
+ eventBus.publish({
2649
+ type: INTERNAL_EVENTS.notification,
2650
+ payload: {
2651
+ type: "info",
2652
+ message: `${displayName} has muted you.`
2653
+ }
2654
+ });
2655
+ }
2372
2656
  }
2373
2657
  }
2374
2658
  }
@@ -2423,6 +2707,24 @@ var ConferenceListener = class {
2423
2707
  useParticipantStore.getState().updateParticipant(participantId, { role: newRole });
2424
2708
  }
2425
2709
  }
2710
+ onTrackUnmuteRejected(track) {
2711
+ if (!track.isLocal()) {
2712
+ return;
2713
+ }
2714
+ const mediaType = track.getType();
2715
+ track.dispose().catch(() => {});
2716
+ useTracksStore.getState().updateLocalTrack(mediaType, {
2717
+ originalTrack: undefined,
2718
+ muted: 1
2719
+ });
2720
+ eventBus.publish({
2721
+ type: INTERNAL_EVENTS.notification,
2722
+ payload: {
2723
+ type: "info",
2724
+ message: `Your ${mediaType} unmute was rejected.`
2725
+ }
2726
+ });
2727
+ }
2426
2728
  onTalkWhileMuted() {}
2427
2729
  onConferenceError(error) {
2428
2730
  console.error("Conference error:", error);
@@ -2501,6 +2803,7 @@ function addConferenceListeners(conference) {
2501
2803
  conference.on(lib_jitsi_meet.default.events.conference.PARTICIPANT_PROPERTY_CHANGED, conferenceListener.onParticipantPropertyChanged);
2502
2804
  conference.on(lib_jitsi_meet.default.events.conference.USER_ROLE_CHANGED, conferenceListener.onUserRoleChanged);
2503
2805
  conference.on(lib_jitsi_meet.default.events.conference.TALK_WHILE_MUTED, conferenceListener.onTalkWhileMuted);
2806
+ conference.on(lib_jitsi_meet.default.events.conference.TRACK_UNMUTE_REJECTED, conferenceListener.onTrackUnmuteRejected);
2504
2807
  conference.on(lib_jitsi_meet.default.events.conference.TRACK_AUDIO_LEVEL_CHANGED, conferenceListener.onTrackAudioLevelChanged);
2505
2808
  conference.addCommandListener(CONFERENCE_COMMANDS.userInfo, (data, id) => {
2506
2809
  const vData = valibot.safeParse(UserInfoCommandSchema, safeParseJson(data.value));
@@ -2512,17 +2815,23 @@ function addConferenceListeners(conference) {
2512
2815
  }
2513
2816
  });
2514
2817
  }
2515
- async function createConference(connection, roomName) {
2818
+ async function _createConference() {
2819
+ const sessionId = useConfigStore.getState().sessionId;
2820
+ const connection = useConnectionStore.getState().connection;
2516
2821
  if (!connection) {
2517
2822
  throw new Error("No connection available");
2518
2823
  }
2824
+ const connectionStatus = useConnectionStore.getState().connectionStatus;
2825
+ if (connectionStatus !== "connected") {
2826
+ await waitForConnection();
2827
+ }
2519
2828
  const existingConference = useConferenceStore.getState().conference;
2520
2829
  if (existingConference) {
2521
2830
  console.log("Conference already exists, skipping creation");
2522
2831
  return;
2523
2832
  }
2524
2833
  const connectionConfig = useConnectionStore.getState().connectionConfig;
2525
- const conference = connection.initJitsiConference(roomName, connectionConfig);
2834
+ const conference = connection.initJitsiConference(sessionId, connectionConfig);
2526
2835
  const localAudioTrack = getLocalTrack(MEDIA_TYPE.AUDIO)?.originalTrack;
2527
2836
  const localVideoTrack = getLocalTrack(MEDIA_TYPE.VIDEO)?.originalTrack;
2528
2837
  if (localAudioTrack) {
@@ -2537,6 +2846,20 @@ async function createConference(connection, roomName) {
2537
2846
  conference.setDisplayName(useParticipantStore.getState().localParticipant.name);
2538
2847
  conference.join();
2539
2848
  }
2849
+ async function createConference() {
2850
+ const conference = useConferenceStore.getState().conference;
2851
+ if (!conference) {
2852
+ const result = await tryCatch(_createConference());
2853
+ if (result.error) {
2854
+ console.error("Error creating conference", result.error);
2855
+ useConferenceStore.setState({
2856
+ conferenceStatus: "error",
2857
+ conferenceJoined: false,
2858
+ conferenceError: result.error.message
2859
+ });
2860
+ }
2861
+ }
2862
+ }
2540
2863
  function muteParticipant(participantId) {
2541
2864
  const conference = useConferenceStore.getState().conference;
2542
2865
  conference?.muteParticipant(participantId, "audio");
@@ -2548,7 +2871,12 @@ function pauseParticipantVideo(participantId) {
2548
2871
 
2549
2872
  //#endregion
2550
2873
  //#region calls-sdk-core/handlers/connection.ts
2551
- function connect(roomName) {
2874
+ async function connect(autoJoinConference = true) {
2875
+ const existingConnection = useConnectionStore.getState().connection;
2876
+ if (existingConnection) {
2877
+ createConference();
2878
+ return;
2879
+ }
2552
2880
  const options = useConnectionStore.getState().connectionConfig;
2553
2881
  const jwt = useConnectionStore.getState().jwt;
2554
2882
  const iAmRecorder = useConfigStore.getState().iAmRecorder;
@@ -2564,15 +2892,8 @@ function connect(roomName) {
2564
2892
  async function onConnectionEstablished() {
2565
2893
  useConnectionStore.getState().connectionEstablished(connection);
2566
2894
  eventBus.publish({ type: INTERNAL_EVENTS.onConnectionEstablished });
2567
- const result = await tryCatch(createConference(connection, roomName));
2568
- if (result.error) {
2569
- console.error("Error creating conference", result.error);
2570
- useConferenceStore.setState({
2571
- conferenceStatus: "error",
2572
- conferenceJoined: false,
2573
- conferenceError: result.error.message
2574
- });
2575
- }
2895
+ if (!autoJoinConference) return;
2896
+ createConference();
2576
2897
  }
2577
2898
  function onConnectionFailed(err, message, ...args) {
2578
2899
  unsubscribe();
@@ -2739,6 +3060,7 @@ function resetAllStores() {
2739
3060
  useConfigStore.getState().reset();
2740
3061
  useConnectionStore.getState().reset();
2741
3062
  useParticipantStore.getState().reset();
3063
+ useToastStore.getState().reset();
2742
3064
  useTracksStore.getState().reset();
2743
3065
  }
2744
3066
 
@@ -2770,6 +3092,7 @@ var Mutex = class {
2770
3092
  //#region calls-sdk-core/handlers/init.ts
2771
3093
  function initializeLib() {
2772
3094
  lib_jitsi_meet.default.init();
3095
+ lib_jitsi_meet.default.setLogLevel(lib_jitsi_meet.default.logLevels.ERROR);
2773
3096
  console.log("JitsiMeetJS initialized successfully.");
2774
3097
  }
2775
3098
 
@@ -2778,6 +3101,7 @@ function initializeLib() {
2778
3101
  let isSessionStarted = false;
2779
3102
  let reconnectTimeoutId = null;
2780
3103
  const RECONNECT_DEBOUNCE_DELAY = 3e3;
3104
+ initializeLib();
2781
3105
  function startSession() {
2782
3106
  const sessionId = useConfigStore.getState().sessionId;
2783
3107
  if (!sessionId) {
@@ -2790,29 +3114,13 @@ function startSession() {
2790
3114
  }
2791
3115
  isSessionStarted = true;
2792
3116
  console.log(`Session started in room: ${sessionId}`);
2793
- initializeLib();
2794
- const audioInputDeviceId = useConfigStore.getState().audioInputDeviceId ?? useBaseStore.getState().audioInputDevice?.deviceId;
2795
- createLocalTrack("audio", audioInputDeviceId);
2796
- const sessionType = useConfigStore.getState().sessionType;
2797
- if (sessionType === SESSION_TYPE.VIDEO) {
2798
- const videoInputDeviceIdP1 = useConfigStore.getState().videoInputDeviceId;
2799
- const videoInputDeviceIdP2 = useBaseStore.getState().videoInputDevice?.deviceId;
2800
- const initialCameraFacingP1 = useConfigStore.getState().initialCameraFacing;
2801
- const initialCameraFacingP2 = useBaseStore.getState().cameraFacing;
2802
- if (videoInputDeviceIdP1) {
2803
- createLocalTrack("video", videoInputDeviceIdP1);
2804
- } else if (initialCameraFacingP1) {
2805
- createLocalTrack("video", null, initialCameraFacingP2);
2806
- } else {
2807
- createLocalTrack("video", videoInputDeviceIdP2, initialCameraFacingP2);
2808
- }
2809
- }
3117
+ createLocalTracks();
2810
3118
  const audioOutputDeviceId = useConfigStore.getState().audioOutputDeviceId ?? useBaseStore.getState().audioOutputDevice?.deviceId;
2811
3119
  if (audioOutputDeviceId) {
2812
3120
  updateAudioOutputDevice(audioOutputDeviceId);
2813
3121
  }
2814
3122
  eventBus.startEmitting();
2815
- const test = tryCatchSync(() => connect(sessionId));
3123
+ const test = tryCatchSync(() => connect());
2816
3124
  if (test.error) {
2817
3125
  console.error("Error connecting to session:", test.error);
2818
3126
  useConnectionStore.getState().connectionFailed(test.error.message);
@@ -2829,8 +3137,14 @@ async function _leaveSession() {
2829
3137
  await useConnectionStore.getState().disconnect();
2830
3138
  }
2831
3139
  const sessionMutex = new Mutex();
2832
- function leaveSession() {
3140
+ function leaveSession(options = {}) {
2833
3141
  return sessionMutex.run(async () => {
3142
+ const isPeerCall = useConfigStore.getState().isPeerCall;
3143
+ const shouldEnd = options.shouldEndSession || isPeerCall && !options.forceLeave;
3144
+ if (shouldEnd) {
3145
+ useConferenceStore.getState().endConference();
3146
+ return;
3147
+ }
2834
3148
  useBaseStore.getState().clearIdealTimeoutTimer();
2835
3149
  cancelPendingReconnect();
2836
3150
  await _leaveSession();
@@ -3298,6 +3612,10 @@ eventBus.subscribe(INTERNAL_EVENTS.lifecycle.componentDidMount, () => {
3298
3612
  });
3299
3613
  });
3300
3614
  useBaseStore.subscribe((state) => state.appState, (appState) => {
3615
+ const sessionType = useConfigStore.getState().sessionType;
3616
+ if (sessionType !== SESSION_TYPE.VIDEO) {
3617
+ return;
3618
+ }
3301
3619
  if (appState === "active") {
3302
3620
  resumeVideoTrack(VIDEO_PAUSE_AUTHORITY.BACKGROUND);
3303
3621
  } else {
@@ -3738,6 +4056,13 @@ const commonStyles = react_native.StyleSheet.create({
3738
4056
  borderDefault: { borderColor: colors.border.default },
3739
4057
  borderDark: { borderColor: colors.border.dark },
3740
4058
  borderHighlight: { borderColor: colors.border.highlight },
4059
+ absoluteFill: {
4060
+ position: "absolute",
4061
+ top: 0,
4062
+ bottom: 0,
4063
+ left: 0,
4064
+ right: 0
4065
+ },
3741
4066
  flex1: { flex: 1 },
3742
4067
  flexRow: { flexDirection: "row" },
3743
4068
  flexColumn: { flexDirection: "column" },
@@ -3927,10 +4252,16 @@ const PopupMenu = ({ visible, onClose, options, anchorLayout }) => {
3927
4252
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Modal, {
3928
4253
  transparent: true,
3929
4254
  animationType: "none",
4255
+ supportedOrientations: [
4256
+ "portrait",
4257
+ "landscape-left",
4258
+ "landscape-right"
4259
+ ],
3930
4260
  onRequestClose: onClose,
3931
4261
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Pressable, {
3932
4262
  style: styles$27.backdrop,
3933
4263
  onPress: onClose,
4264
+ testID: "cometchat-popup-menu-backdrop",
3934
4265
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
3935
4266
  style: [styles$27.menu, {
3936
4267
  [isBelowMiddle ? "bottom" : "top"]: isBelowMiddle ? callContainerDimension.height - (y - 4) : y + height + 4,
@@ -3951,6 +4282,7 @@ const PopupMenu = ({ visible, onClose, options, anchorLayout }) => {
3951
4282
  },
3952
4283
  activeOpacity: option.selected ? DISABLED_OPTION_OPACITY : .2,
3953
4284
  style: [styles$27.menuItem, option.selected ? styles$27.menuItemSelected : {}],
4285
+ testID: `cometchat-popup-menu-option-${index}`,
3954
4286
  children: [option.iconName && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
3955
4287
  name: option.iconName,
3956
4288
  size: 24,
@@ -4112,6 +4444,7 @@ const MoreOptionButton = ({ ruid }) => {
4112
4444
  ref: buttonRef,
4113
4445
  style: styles$4.moreButton,
4114
4446
  onPress: showMenu,
4447
+ testID: "cometchat-participant-more-options-button",
4115
4448
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
4116
4449
  name: "more",
4117
4450
  size: 20,
@@ -4251,7 +4584,11 @@ const VideoNative = ({ videoTrack, style, objectFit = "cover", mirror = false, m
4251
4584
  return null;
4252
4585
  }
4253
4586
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
4254
- style: [styles$25.videoContainer, { opacity: fadeAnim }],
4587
+ style: [
4588
+ commonStyles.absoluteFill,
4589
+ styles$25.videoContainer,
4590
+ { opacity: fadeAnim }
4591
+ ],
4255
4592
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_webrtc.RTCView, {
4256
4593
  streamURL: streamURL.toURL(),
4257
4594
  style: [styles$25.video, style],
@@ -4264,8 +4601,7 @@ const VideoNative = ({ videoTrack, style, objectFit = "cover", mirror = false, m
4264
4601
  const styles$25 = react_native.StyleSheet.create({
4265
4602
  videoContainer: {
4266
4603
  height: "100%",
4267
- width: "100%",
4268
- ...react_native.StyleSheet.absoluteFillObject
4604
+ width: "100%"
4269
4605
  },
4270
4606
  video: {
4271
4607
  width: "100%",
@@ -4281,6 +4617,7 @@ const Tile = ({ participant, style, zOrder, showLabel = true, disablePress = fal
4281
4617
  const videoTrack = useTrackByParticipantId(pid, type === "screen-share" ? MEDIA_TYPE.SCREENSHARE : MEDIA_TYPE.VIDEO)?.originalTrack;
4282
4618
  const videoMuted = useTrackMuted(type === "screen-share" ? MEDIA_TYPE.SCREENSHARE : MEDIA_TYPE.VIDEO, pid);
4283
4619
  const enableParticipantContextMenu = useEnableParticipantContextMenu();
4620
+ const shouldMirror = useShouldMirrorLocalVideo();
4284
4621
  const [size, fontSize] = react.default.useMemo(() => {
4285
4622
  const flatStyle = react_native.StyleSheet.flatten(style);
4286
4623
  const width$1 = flatStyle?.width;
@@ -4298,6 +4635,7 @@ const Tile = ({ participant, style, zOrder, showLabel = true, disablePress = fal
4298
4635
  activeOpacity: 1,
4299
4636
  disabled: disablePress,
4300
4637
  style: [styles$24.callScreen, style],
4638
+ testID: `cometchat-tile-${pid}`,
4301
4639
  children: [
4302
4640
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
4303
4641
  style: styles$24.tileAvatar,
@@ -4313,7 +4651,7 @@ const Tile = ({ participant, style, zOrder, showLabel = true, disablePress = fal
4313
4651
  objectFit: type === "screen-share" ? "contain" : "cover",
4314
4652
  muted: videoMuted,
4315
4653
  zOrder,
4316
- mirror: isLocal
4654
+ mirror: isLocal && type !== "screen-share" && shouldMirror
4317
4655
  }),
4318
4656
  showLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label_native_default, { participant }),
4319
4657
  enableParticipantContextMenu && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
@@ -4372,6 +4710,7 @@ const GroupAvatarTile = ({ startIndex = 4, style }) => {
4372
4710
  const overflowCount = Math.max(0, participantCount - startIndex - 3);
4373
4711
  const visible = participants.slice(startIndex, startIndex + (overflowCount === 1 ? 4 : 3));
4374
4712
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
4713
+ testID: "cometchat-group-avatar-tile",
4375
4714
  style: [styles$23.container, style],
4376
4715
  onPress: toggleParticipantListVisible,
4377
4716
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
@@ -4479,6 +4818,7 @@ function SidebarLayout() {
4479
4818
  const mainParticipant = useMainParticipant();
4480
4819
  const participants = allParticipants.length > 1 ? [mainParticipant].concat(allParticipants) : [mainParticipant];
4481
4820
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
4821
+ testID: "cometchat-sidebar-layout",
4482
4822
  style: styles$22.container,
4483
4823
  children: [
4484
4824
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
@@ -4615,23 +4955,26 @@ const Spotlight = () => {
4615
4955
  if (otherParticipant) {
4616
4956
  spotlightParticipants.push(otherParticipant);
4617
4957
  }
4618
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4619
- participant: spotlightParticipants[0],
4620
- disablePress: true
4621
- }, spotlightParticipants[0].ruid), spotlightParticipants[1] && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pan, {
4622
- disableDrag: !enableSpotlightDrag,
4623
- layout: {
4624
- width: mainAreaDimension.width,
4625
- height: mainAreaDimension.height
4626
- },
4627
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4628
- showLabel: false,
4629
- disablePress: !enableSpotlightSwap,
4630
- participant: spotlightParticipants[1],
4631
- style: styles$20.panTile,
4632
- zOrder: 1
4633
- }, spotlightParticipants[1].ruid)
4634
- })] });
4958
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
4959
+ testID: "cometchat-spotlight-layout",
4960
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4961
+ participant: spotlightParticipants[0],
4962
+ disablePress: true
4963
+ }, spotlightParticipants[0].ruid), spotlightParticipants[1] && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pan, {
4964
+ disableDrag: !enableSpotlightDrag,
4965
+ layout: {
4966
+ width: mainAreaDimension.width,
4967
+ height: mainAreaDimension.height
4968
+ },
4969
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4970
+ showLabel: false,
4971
+ disablePress: !enableSpotlightSwap,
4972
+ participant: spotlightParticipants[1],
4973
+ style: styles$20.panTile,
4974
+ zOrder: 1
4975
+ }, spotlightParticipants[1].ruid)
4976
+ })]
4977
+ });
4635
4978
  };
4636
4979
  const styles$20 = react_native.StyleSheet.create({ panTile: {
4637
4980
  borderColor: "#1A1A1A",
@@ -4664,6 +5007,7 @@ function TileLayout() {
4664
5007
  participantCount: isPIPLayoutEnabled ? 1 : participants.length
4665
5008
  });
4666
5009
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.FlatList, {
5010
+ testID: "cometchat-tile-layout",
4667
5011
  data: isPIPLayoutEnabled ? [mainParticipant] : participants,
4668
5012
  renderItem: ({ item }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tile_native_default, {
4669
5013
  participant: item,
@@ -4731,7 +5075,11 @@ function ProcessingOverlay({ message, visible = true, animated = false }) {
4731
5075
  return null;
4732
5076
  }
4733
5077
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Animated.View, {
4734
- style: [styles$18.overlay, { opacity }],
5078
+ style: [
5079
+ commonStyles.absoluteFill,
5080
+ styles$18.overlay,
5081
+ { opacity }
5082
+ ],
4735
5083
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.ActivityIndicator, {
4736
5084
  size: "large",
4737
5085
  color: "#fff"
@@ -4743,7 +5091,6 @@ function ProcessingOverlay({ message, visible = true, animated = false }) {
4743
5091
  }
4744
5092
  const styles$18 = react_native.StyleSheet.create({
4745
5093
  overlay: {
4746
- ...react_native.StyleSheet.absoluteFillObject,
4747
5094
  justifyContent: "center",
4748
5095
  alignItems: "center",
4749
5096
  backgroundColor: "#1A1A1A",
@@ -4921,7 +5268,6 @@ function showConfirmationDialog(title, description, confirmText, cancelText, onC
4921
5268
  const { width } = react_native.Dimensions.get("window");
4922
5269
  const styles$15 = react_native.StyleSheet.create({
4923
5270
  backdrop: {
4924
- ...react_native.StyleSheet.absoluteFillObject,
4925
5271
  backgroundColor: "rgba(0, 0, 0, 0.8)",
4926
5272
  justifyContent: "center",
4927
5273
  alignItems: "center",
@@ -5013,10 +5359,16 @@ function ConfirmationDialog() {
5013
5359
  visible,
5014
5360
  transparent: true,
5015
5361
  animationType: "fade",
5362
+ supportedOrientations: [
5363
+ "portrait",
5364
+ "landscape-left",
5365
+ "landscape-right"
5366
+ ],
5016
5367
  onRequestClose: handleBackdropPress,
5017
5368
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Pressable, {
5018
- style: styles$15.backdrop,
5369
+ style: [commonStyles.absoluteFill, styles$15.backdrop],
5019
5370
  onPress: handleBackdropPress,
5371
+ testID: "cometchat-confirmation-dialog-backdrop",
5020
5372
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
5021
5373
  style: styles$15.dialog,
5022
5374
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
@@ -5059,7 +5411,7 @@ function ConfirmationDialog() {
5059
5411
  //#endregion
5060
5412
  //#region src/ui/bottom-sheet/BottomSheet.native.tsx
5061
5413
  const SCREEN_HEIGHT = react_native.Dimensions.get("window").height;
5062
- const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT * .4 }) => {
5414
+ const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT * .4, testID }) => {
5063
5415
  const visibleTranslateY = SCREEN_HEIGHT - maxHeight;
5064
5416
  const hiddenTranslateY = (0, react.useRef)(SCREEN_HEIGHT).current;
5065
5417
  const animatedValue = (0, react.useRef)(new react_native.Animated.Value(hiddenTranslateY)).current;
@@ -5085,8 +5437,10 @@ const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT *
5085
5437
  const bottomSheetAnimation = { transform: [{ translateY: animatedValue }] };
5086
5438
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, {
5087
5439
  onPress: onClose,
5088
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: styles$14.backdrop })
5440
+ testID: "cometchat-bottom-sheet-backdrop",
5441
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: [commonStyles.absoluteFill, styles$14.backdrop] })
5089
5442
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Animated.View, {
5443
+ testID,
5090
5444
  style: [
5091
5445
  styles$14.bottomSheet,
5092
5446
  bottomSheetAnimation,
@@ -5100,7 +5454,6 @@ const BottomSheet = ({ children, isVisible, onClose, maxHeight = SCREEN_HEIGHT *
5100
5454
  };
5101
5455
  const styles$14 = react_native.StyleSheet.create({
5102
5456
  backdrop: {
5103
- ...react_native.StyleSheet.absoluteFillObject,
5104
5457
  backgroundColor: "rgba(0,0,0,0.5)",
5105
5458
  zIndex: 1
5106
5459
  },
@@ -5144,8 +5497,9 @@ var BottomSheet_native_default = BottomSheet;
5144
5497
 
5145
5498
  //#endregion
5146
5499
  //#region src/ui/control-pane/MenuItem.native.tsx
5147
- const MenuItem = ({ iconName, label, onPress, selected = false }) => {
5500
+ const MenuItem = ({ iconName, label, onPress, selected = false, testID }) => {
5148
5501
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
5502
+ testID,
5149
5503
  onPress: () => {
5150
5504
  hideAllBottomSheets();
5151
5505
  onPress();
@@ -5198,6 +5552,7 @@ const AudioModesMenu = ({ isVisible, onClose }) => {
5198
5552
  style: [commonStyles.bodyRegular, styles$12.noItemsText],
5199
5553
  children: "No audio modes available"
5200
5554
  }), audioModes.map((mode, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5555
+ testID: `cometchat-menu-item-audio-${mode.type.toLowerCase()}`,
5201
5556
  iconName: AUDIO_MODE_TYPE_ICON_MAP[mode.type],
5202
5557
  label: mode.type,
5203
5558
  selected: mode.selected,
@@ -5249,6 +5604,7 @@ const AudioModeButton = () => {
5249
5604
  style: controlPaneStyles.controlButton,
5250
5605
  onPress: toggleAudioModeMenuVisible,
5251
5606
  activeOpacity: .7,
5607
+ testID: "cometchat-audio-mode-button",
5252
5608
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5253
5609
  name: "speaker-fill",
5254
5610
  fill: "#FFF",
@@ -5274,6 +5630,7 @@ const AudioControl = () => {
5274
5630
  style: [controlPaneStyles.controlButton, muted && controlPaneStyles.toggledButton],
5275
5631
  onPress,
5276
5632
  activeOpacity: .7,
5633
+ testID: "cometchat-audio-toggle-button",
5277
5634
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5278
5635
  name: muted ? "mic-off-fill" : "mic-fill",
5279
5636
  fill: muted ? "#9F3032" : "#FFF",
@@ -5299,6 +5656,7 @@ const VideoControl = () => {
5299
5656
  style: [controlPaneStyles.controlButton, videoMuted && controlPaneStyles.toggledButton],
5300
5657
  onPress,
5301
5658
  activeOpacity: .7,
5659
+ testID: "cometchat-video-toggle-button",
5302
5660
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5303
5661
  name: videoMuted ? "video-off-fill" : "video-fill",
5304
5662
  fill: videoMuted ? "#9F3032" : "#FFF",
@@ -5323,6 +5681,7 @@ const LeaveSessionButton = () => {
5323
5681
  style: [controlPaneStyles.controlButton, controlPaneStyles.leaveSessionButton],
5324
5682
  onPress,
5325
5683
  activeOpacity: .7,
5684
+ testID: "cometchat-leave-session-button",
5326
5685
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5327
5686
  name: "call-end",
5328
5687
  fill: "#FFF",
@@ -5339,6 +5698,7 @@ const MoreMenuButton = () => {
5339
5698
  style: controlPaneStyles.controlButton,
5340
5699
  onPress: toggleMoreMenuVisible,
5341
5700
  activeOpacity: .7,
5701
+ testID: "cometchat-more-menu-button",
5342
5702
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5343
5703
  name: "more",
5344
5704
  fill: "#FFF",
@@ -5414,22 +5774,26 @@ const MoreMenu = ({ isVisible, onClose }) => {
5414
5774
  toggleParticipantListVisible();
5415
5775
  }, []);
5416
5776
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BottomSheet_native_default, {
5777
+ testID: "cometchat-more-menu-bottom-sheet",
5417
5778
  maxHeight: bottomSheetMaxHeight,
5418
5779
  isVisible,
5419
5780
  onClose,
5420
5781
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.ScrollView, { children: [
5421
5782
  numberOfVisibleItems === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5783
+ testID: "cometchat-more-menu-empty-state",
5422
5784
  style: [commonStyles.bodyRegular, styles$11.noItemsText],
5423
5785
  children: "No options available"
5424
5786
  }),
5425
5787
  !hideScreenSharingButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScreenShareButton_default, {}),
5426
5788
  !hideRaiseHandButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5789
+ testID: "cometchat-menu-item-raise-hand",
5427
5790
  iconName: "raise-hand-fill",
5428
5791
  label: raiseHandTimestamp ? "Lower Hand" : "Raise Hand",
5429
5792
  onPress: onRaiseHandPress,
5430
5793
  selected: Boolean(raiseHandTimestamp)
5431
5794
  }),
5432
5795
  !hideRecordingButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5796
+ testID: isRecording ? "cometchat-menu-item-stop-recording" : "cometchat-menu-item-start-recording",
5433
5797
  iconName: isRecording ? "record-stop-fill" : "record-fill",
5434
5798
  label: isRecording ? "Stop Recording" : "Start Recording",
5435
5799
  onPress: () => {
@@ -5440,6 +5804,7 @@ const MoreMenu = ({ isVisible, onClose }) => {
5440
5804
  }
5441
5805
  }),
5442
5806
  !hideParticipantListButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItem_native_default, {
5807
+ testID: "cometchat-menu-item-participants",
5443
5808
  iconName: "participants",
5444
5809
  label: "Participants",
5445
5810
  onPress: onParticipantListPress
@@ -5481,14 +5846,15 @@ const FullScreenDialog = ({ children, visible = false }) => {
5481
5846
  return null;
5482
5847
  }
5483
5848
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
5484
- style: [styles$10.container, { opacity: fadeAnim }],
5849
+ style: [
5850
+ commonStyles.absoluteFill,
5851
+ styles$10.container,
5852
+ { opacity: fadeAnim }
5853
+ ],
5485
5854
  children
5486
5855
  });
5487
5856
  };
5488
- const styles$10 = react_native.StyleSheet.create({ container: {
5489
- ...react_native.StyleSheet.absoluteFillObject,
5490
- zIndex: 1e3
5491
- } });
5857
+ const styles$10 = react_native.StyleSheet.create({ container: { zIndex: 1e3 } });
5492
5858
  var FullScreenDialog_native_default = FullScreenDialog;
5493
5859
 
5494
5860
  //#endregion
@@ -5566,6 +5932,7 @@ const ChangeLayout = () => {
5566
5932
  eventBus.publish({ type: EVENT_LISTENER_METHODS.ButtonClickListener.onChangeLayoutButtonClicked });
5567
5933
  showMenu();
5568
5934
  },
5935
+ testID: "cometchat-change-layout-button",
5569
5936
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5570
5937
  name: "tile-fill",
5571
5938
  fill: "#FFFFFF"
@@ -5618,6 +5985,7 @@ const ChatButton = () => {
5618
5985
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
5619
5986
  style: [styles$9.iconButton],
5620
5987
  onPress,
5988
+ testID: "cometchat-chat-button",
5621
5989
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
5622
5990
  name: "chat",
5623
5991
  fill: "#FFFFFF"
@@ -5674,6 +6042,7 @@ const SwitchCamera = () => {
5674
6042
  return null;
5675
6043
  }
5676
6044
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6045
+ testID: "cometchat-switch-camera-button",
5677
6046
  disabled,
5678
6047
  style: [styles$8.iconButton, disabled && styles$8.iconButtonDisabled],
5679
6048
  onPress,
@@ -5706,6 +6075,7 @@ const SessionTimer = () => {
5706
6075
  return null;
5707
6076
  }
5708
6077
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6078
+ testID: "cometchat-session-timer",
5709
6079
  style: [commonStyles.caption1Regular, styles$7.meetingTime],
5710
6080
  children: miliSecondsToMMSS(conferenceElapsedTime)
5711
6081
  });
@@ -5817,69 +6187,80 @@ const IdealTimeoutModal = ({ style = {} }) => {
5817
6187
  transparent: true,
5818
6188
  visible: idleTimeoutModalVisible,
5819
6189
  animationType: "none",
6190
+ supportedOrientations: [
6191
+ "portrait",
6192
+ "landscape-left",
6193
+ "landscape-right"
6194
+ ],
5820
6195
  statusBarTranslucent: true,
5821
6196
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, {
5822
6197
  onPress: handleOverlayPress,
6198
+ testID: "cometchat-idle-timeout-overlay",
5823
6199
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
5824
6200
  style: [styles$6.overlay, { opacity: fadeAnim }],
5825
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
5826
- style: [
5827
- styles$6.modal,
5828
- style,
5829
- {
5830
- opacity: fadeAnim,
5831
- transform: [{ scale: scaleAnim }]
5832
- }
5833
- ],
5834
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
5835
- style: styles$6.content,
5836
- children: [
5837
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
5838
- style: styles$6.timerIcon,
5839
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5840
- style: [commonStyles.heading3Bold, styles$6.timerText],
5841
- children: formattedTime
5842
- })
5843
- }),
5844
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
5845
- style: styles$6.textContent,
5846
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5847
- style: [commonStyles.heading2Medium, styles$6.title],
5848
- children: "Are you still there?"
5849
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Text, {
5850
- style: [commonStyles.bodyRegular, styles$6.subtitle],
5851
- children: [
5852
- "You are the only one here, so this call will end in less than ",
5853
- ceilMinutes,
5854
- " minute",
5855
- ceilMinutes > 1 ? "s" : "",
5856
- ". Do you want to stay in this call?"
5857
- ]
5858
- })]
5859
- }),
5860
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
5861
- style: styles$6.actions,
5862
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
5863
- style: [styles$6.button, styles$6.buttonSecondary],
5864
- onPress: onStayInCall,
5865
- activeOpacity: .8,
5866
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5867
- style: [commonStyles.bodyMedium, styles$6.buttonSecondaryText],
5868
- children: "Stay on the call"
5869
- })
5870
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
5871
- style: [styles$6.button, styles$6.buttonPrimary],
5872
- onPress: leaveSession,
5873
- activeOpacity: .8,
6201
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableWithoutFeedback, {
6202
+ testID: "cometchat-idle-timeout-modal",
6203
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, {
6204
+ style: [
6205
+ styles$6.modal,
6206
+ style,
6207
+ {
6208
+ opacity: fadeAnim,
6209
+ transform: [{ scale: scaleAnim }]
6210
+ }
6211
+ ],
6212
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
6213
+ style: styles$6.content,
6214
+ children: [
6215
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
6216
+ style: styles$6.timerIcon,
5874
6217
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
5875
- style: [commonStyles.bodyMedium, styles$6.buttonPrimaryText],
5876
- children: "Leave now"
6218
+ style: [commonStyles.heading3Bold, styles$6.timerText],
6219
+ children: formattedTime
5877
6220
  })
5878
- })]
5879
- })
5880
- ]
6221
+ }),
6222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
6223
+ style: styles$6.textContent,
6224
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6225
+ style: [commonStyles.heading2Medium, styles$6.title],
6226
+ children: "Are you still there?"
6227
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.Text, {
6228
+ style: [commonStyles.bodyRegular, styles$6.subtitle],
6229
+ children: [
6230
+ "You are the only one here, so this call will end in less than ",
6231
+ ceilMinutes,
6232
+ " minute",
6233
+ ceilMinutes > 1 ? "s" : "",
6234
+ ". Do you want to stay in this call?"
6235
+ ]
6236
+ })]
6237
+ }),
6238
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
6239
+ style: styles$6.actions,
6240
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6241
+ style: [styles$6.button, styles$6.buttonSecondary],
6242
+ onPress: onStayInCall,
6243
+ activeOpacity: .8,
6244
+ testID: "cometchat-idle-timeout-stay-button",
6245
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6246
+ style: [commonStyles.bodyMedium, styles$6.buttonSecondaryText],
6247
+ children: "Stay on the call"
6248
+ })
6249
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6250
+ style: [styles$6.button, styles$6.buttonPrimary],
6251
+ onPress: () => leaveSession(),
6252
+ activeOpacity: .8,
6253
+ testID: "cometchat-idle-timeout-leave-button",
6254
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6255
+ style: [commonStyles.bodyMedium, styles$6.buttonPrimaryText],
6256
+ children: "Leave now"
6257
+ })
6258
+ })]
6259
+ })
6260
+ ]
6261
+ })
5881
6262
  })
5882
- }) })
6263
+ })
5883
6264
  })
5884
6265
  })
5885
6266
  });
@@ -5898,6 +6279,7 @@ const styles$6 = react_native.StyleSheet.create({
5898
6279
  borderWidth: 1,
5899
6280
  borderColor: "#383838",
5900
6281
  width: "100%",
6282
+ maxWidth: 372,
5901
6283
  paddingTop: 32,
5902
6284
  paddingHorizontal: 20,
5903
6285
  paddingBottom: 20,
@@ -5976,6 +6358,7 @@ const ShareInviteButton = () => {
5976
6358
  style: styles$5.shareButtonContainer,
5977
6359
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
5978
6360
  style: styles$5.shareButton,
6361
+ testID: "cometchat-share-invite-button",
5979
6362
  onPress: () => {
5980
6363
  eventBus.publish({ type: "onShareInviteButtonClicked" });
5981
6364
  },
@@ -6112,6 +6495,7 @@ const ParticipantList = () => {
6112
6495
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
6113
6496
  onPress: toggleParticipantListVisible,
6114
6497
  accessibilityLabel: "Close participants list",
6498
+ testID: "cometchat-participant-list-close-button",
6115
6499
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon_native_default, {
6116
6500
  name: "close",
6117
6501
  size: 24,
@@ -6133,7 +6517,8 @@ const ParticipantList = () => {
6133
6517
  style: styles$3.searchInput,
6134
6518
  value: searchTerm,
6135
6519
  onChangeText: setSearchTerm,
6136
- placeholderTextColor: "#858585"
6520
+ placeholderTextColor: "#858585",
6521
+ testID: "cometchat-participant-search-input"
6137
6522
  })]
6138
6523
  })
6139
6524
  }),
@@ -6274,45 +6659,6 @@ const styles$2 = react_native.StyleSheet.create({
6274
6659
  }
6275
6660
  });
6276
6661
 
6277
- //#endregion
6278
- //#region src/ui/toast/toast-state.ts
6279
- const MAX_TOASTS = 3;
6280
- let counter = 0;
6281
- const useToastStore = (0, zustand.create)((set) => ({
6282
- toasts: [],
6283
- addToast: (toast) => {
6284
- const id = `toast-${++counter}-${Date.now()}`;
6285
- const newToast = {
6286
- ...toast,
6287
- id,
6288
- createdAt: Date.now()
6289
- };
6290
- set((state) => {
6291
- const updated = [...state.toasts, newToast];
6292
- if (updated.length > MAX_TOASTS) {
6293
- return { toasts: updated.slice(-MAX_TOASTS) };
6294
- }
6295
- return { toasts: updated };
6296
- });
6297
- return id;
6298
- },
6299
- removeToast: (id) => {
6300
- set((state) => ({ toasts: state.toasts.filter((t) => t.id !== id) }));
6301
- },
6302
- clearAll: () => {
6303
- set({ toasts: [] });
6304
- }
6305
- }));
6306
- function showToast(params) {
6307
- return useToastStore.getState().addToast({
6308
- message: params.message,
6309
- type: params.type ?? "info",
6310
- duration: params.duration ?? 3e3,
6311
- position: params.position ?? "bottom",
6312
- action: params.action
6313
- });
6314
- }
6315
-
6316
6662
  //#endregion
6317
6663
  //#region src/ui/toast/Toast.native.tsx
6318
6664
  const SLIDE_IN_DURATION = 300;
@@ -6387,6 +6733,7 @@ function ToastItemView({ toast, onDismiss }) {
6387
6733
  }), toast.action && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Pressable, {
6388
6734
  style: styles$2.actionButton,
6389
6735
  onPress: handleActionPress,
6736
+ testID: "cometchat-toast-action-button",
6390
6737
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
6391
6738
  style: styles$2.actionText,
6392
6739
  children: toast.action.label
@@ -6439,13 +6786,17 @@ function CallUI(props) {
6439
6786
  const isConferenceJoined = useIsConferenceJoined();
6440
6787
  (0, react.useLayoutEffect)(() => {
6441
6788
  eventBus.publish({ type: INTERNAL_EVENTS.lifecycle.componentDidMount });
6442
- updateConfig(props.callSettings);
6789
+ updateConfig(props.sessionSettings);
6443
6790
  return () => {
6444
6791
  eventBus.publish({ type: INTERNAL_EVENTS.lifecycle.componentWillUnmount }, true);
6445
6792
  };
6446
- }, [props.callSettings]);
6793
+ }, [props.sessionSettings]);
6447
6794
  (0, react.useEffect)(() => {
6448
- useBaseStore.setState({ sdkPlatform: react_native.Platform.OS });
6795
+ if (props.sessionSettings.sdkPlatform) {
6796
+ useBaseStore.setState({ sdkPlatform: props.sessionSettings.sdkPlatform });
6797
+ } else {
6798
+ useBaseStore.setState({ sdkPlatform: react_native.Platform.OS === "ios" ? "react-native-ios" : "react-native-android" });
6799
+ }
6449
6800
  startSession();
6450
6801
  }, []);
6451
6802
  (0, react.useEffect)(() => {
@@ -6460,13 +6811,13 @@ function CallUI(props) {
6460
6811
  (0, react.useEffect)(() => {
6461
6812
  if (react_native.Platform.OS === "android") {
6462
6813
  AudioModeModule_default.setMode(type === SESSION_TYPE.VOICE ? AudioModeModule_default.AUDIO_CALL : AudioModeModule_default.VIDEO_CALL);
6463
- if (props.callSettings.audioMode) {
6464
- AudioModeModule_default.setAudioDevice(props.callSettings.audioMode);
6814
+ if (props.sessionSettings.audioMode) {
6815
+ AudioModeModule_default.setAudioDevice(props.sessionSettings.audioMode);
6465
6816
  }
6466
6817
  } else if (react_native.Platform.OS === "ios") {
6467
6818
  AudioModeModule_default.updateDeviceList();
6468
6819
  }
6469
- }, [props.callSettings.audioMode, type]);
6820
+ }, [props.sessionSettings.audioMode, type]);
6470
6821
  if (isPIPLayoutEnabled) {
6471
6822
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PiPTile_default, {});
6472
6823
  }
@@ -6513,13 +6864,6 @@ const styles$1 = react_native.StyleSheet.create({
6513
6864
  alignItems: "center",
6514
6865
  gap: GRID_GAP,
6515
6866
  paddingHorizontal: 20
6516
- },
6517
- loadingContainer: {
6518
- ...react_native.StyleSheet.absoluteFillObject,
6519
- justifyContent: "center",
6520
- alignItems: "center",
6521
- backgroundColor: "#000",
6522
- zIndex: 1e3
6523
6867
  }
6524
6868
  });
6525
6869
  var index_native_default = CallUI;
@@ -6595,10 +6939,10 @@ const convertLegacyCallSettingsToV5Props = (callSettings) => {
6595
6939
  if (cs.defaultAudioMode === "BLUETOOTH" || cs.defaultAudioMode === "EARPIECE" || cs.defaultAudioMode === "HEADPHONES" || cs.defaultAudioMode === "SPEAKER") {
6596
6940
  v5Props.audioMode = cs.defaultAudioMode;
6597
6941
  }
6598
- if (cs.mode === "SPOTLIGHT") {
6599
- v5Props.layout = "SPOTLIGHT";
6600
- } else {
6601
- v5Props.layout = "SIDEBAR";
6942
+ if (typeof cs.layout === "string") {
6943
+ v5Props.layout = cs.layout;
6944
+ } else if (cs.mode === "SPOTLIGHT" || cs.mode === "SIDEBAR") {
6945
+ v5Props.layout = cs.mode;
6602
6946
  }
6603
6947
  if (cs.idleTimeoutPeriod) {
6604
6948
  v5Props.idleTimeoutPeriodAfterPrompt = 6e4;
@@ -6758,10 +7102,11 @@ async function callVerifyTokenAPI({ appId, region, calltoken, baseURL }) {
6758
7102
  }
6759
7103
 
6760
7104
  //#endregion
6761
- //#region src/AppRN.tsx
6762
- function App(props) {
7105
+ //#region src/AppReactNativeSDK.tsx
7106
+ function AppReactNativeSDK(props) {
6763
7107
  const [internalSettings, setInternalSettings] = react.default.useState(null);
6764
7108
  const [infoMessage, setInfoMessage] = react.default.useState(null);
7109
+ const sessionSettings = props.sessionSettings ?? props.callSettings ?? {};
6765
7110
  (0, react.useEffect)(() => {
6766
7111
  return eventBus.subscribe("onConnectionClosed", () => {
6767
7112
  setTimeout(() => {
@@ -6771,7 +7116,7 @@ function App(props) {
6771
7116
  }, []);
6772
7117
  (0, react.useEffect)(() => {
6773
7118
  const listeners = [];
6774
- const cs = props.callSettings ?? {};
7119
+ const cs = sessionSettings ?? {};
6775
7120
  if (cs.listener?.onUserJoined) {
6776
7121
  listeners.push(CometChatCalls.addEventListener("onParticipantJoined", cs.listener.onUserJoined));
6777
7122
  }
@@ -6809,7 +7154,7 @@ function App(props) {
6809
7154
  listener();
6810
7155
  });
6811
7156
  };
6812
- }, [props.callSettings]);
7157
+ }, [sessionSettings]);
6813
7158
  (0, react.useEffect)(() => {
6814
7159
  callVerifyTokenAPI({
6815
7160
  appId: CometChatCalls.appSettings?.appId || "",
@@ -6838,14 +7183,12 @@ function App(props) {
6838
7183
  visible: true
6839
7184
  });
6840
7185
  }
6841
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(index_native_default, { callSettings: {
6842
- ...props.callSettings,
6843
- ...convertLegacyCallSettingsToV5Props(props?.callSettings ?? {}),
7186
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(index_native_default, { sessionSettings: {
7187
+ ...sessionSettings,
7188
+ ...convertLegacyCallSettingsToV5Props(sessionSettings ?? {}),
6844
7189
  internalSettings
6845
7190
  } });
6846
7191
  }
6847
- var AppRN_default = App;
6848
- const AppComponent = App;
6849
7192
 
6850
7193
  //#endregion
6851
7194
  //#region src/v4/Constants.ts
@@ -10578,7 +10921,13 @@ var CometChatCalls = class extends SessionMethodsCore {
10578
10921
  static OngoingCallListener = OngoingCallListener;
10579
10922
  static CallSettingsBuilder = CallSettingsBuilder;
10580
10923
  static CallAppSettingsBuilder = CallAppSettingsBuilder;
10581
- static Component = AppComponent;
10924
+ static Component = AppReactNativeSDK;
10925
+ /**
10926
+ * Initializes the CometChat Calls SDK with the provided app settings.
10927
+ * Must be called before any other SDK methods.
10928
+ * @param appSettings - The application settings for configuring the SDK.
10929
+ * @returns An object indicating success or failure with error details.
10930
+ */
10582
10931
  static async init(appSettings) {
10583
10932
  const parsedAppSettings = valibot.safeParse(CallAppSettingsSchema, appSettings);
10584
10933
  if (!parsedAppSettings.success) {
@@ -10594,7 +10943,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10594
10943
  }
10595
10944
  this.appSettings = parsedAppSettings.output;
10596
10945
  this.isInitialized = true;
10597
- const savedUser = this.getSavedUser();
10946
+ const savedUser = await this.getSavedUser();
10598
10947
  if (savedUser) {
10599
10948
  let parsedUser;
10600
10949
  if (typeof savedUser === "string") {
@@ -10613,6 +10962,14 @@ var CometChatCalls = class extends SessionMethodsCore {
10613
10962
  error: null
10614
10963
  };
10615
10964
  }
10965
+ /**
10966
+ * Logs in a user with their UID and an optional auth key.
10967
+ * If no auth key is provided, the one from app settings is used.
10968
+ * @param uid - The unique identifier of the user.
10969
+ * @param authKey - The authentication key. Falls back to the key provided in app settings.
10970
+ * @returns A Promise that resolves to the logged-in User object.
10971
+ * @throws {CometChatException} If login fails or validation errors occur.
10972
+ */
10616
10973
  static async login(uid, authKey) {
10617
10974
  try {
10618
10975
  if (this.loginInProgress) {
@@ -10655,12 +11012,11 @@ var CometChatCalls = class extends SessionMethodsCore {
10655
11012
  if (this.loggedInUser && this.loggedInUser.uid !== uid) {
10656
11013
  await this.logoutInternal();
10657
11014
  }
10658
- console.log("Logging in user with UID:", uid);
10659
11015
  const authToken = await this.loginWithUID(uid, resolvedAuthKey);
10660
11016
  const user = await this.authenticateWithToken(authToken);
10661
11017
  this.loginInProgress = false;
10662
11018
  this.loggedInUser = user;
10663
- this.saveUser(user);
11019
+ await this.saveUser(user);
10664
11020
  this.notifyLoginSuccess(user);
10665
11021
  return user;
10666
11022
  } catch (error) {
@@ -10670,6 +11026,12 @@ var CometChatCalls = class extends SessionMethodsCore {
10670
11026
  throw cometChatError;
10671
11027
  }
10672
11028
  }
11029
+ /**
11030
+ * Logs in a user directly with an auth token.
11031
+ * @param authToken - The authentication token for the user.
11032
+ * @returns A Promise that resolves to the logged-in User object.
11033
+ * @throws {CometChatException} If login fails or the token is invalid.
11034
+ */
10673
11035
  static async loginWithAuthToken(authToken) {
10674
11036
  try {
10675
11037
  if (this.loginInProgress) {
@@ -10702,7 +11064,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10702
11064
  const user = await this.authenticateWithToken(authToken);
10703
11065
  this.loginInProgress = false;
10704
11066
  this.loggedInUser = user;
10705
- this.saveUser(user);
11067
+ await this.saveUser(user);
10706
11068
  this.notifyLoginSuccess(user);
10707
11069
  return user;
10708
11070
  } catch (error) {
@@ -10712,6 +11074,11 @@ var CometChatCalls = class extends SessionMethodsCore {
10712
11074
  throw cometChatError;
10713
11075
  }
10714
11076
  }
11077
+ /**
11078
+ * Logs out the currently logged-in user and clears local session data.
11079
+ * @returns A Promise that resolves to a success message string.
11080
+ * @throws {CometChatException} If no user is logged in or logout fails.
11081
+ */
10715
11082
  static async logout() {
10716
11083
  try {
10717
11084
  if (!this.loggedInUser) {
@@ -10729,24 +11096,53 @@ var CometChatCalls = class extends SessionMethodsCore {
10729
11096
  throw cometChatError;
10730
11097
  }
10731
11098
  }
11099
+ /**
11100
+ * Retrieves the currently logged-in user.
11101
+ * @returns The logged-in User object, or null if no user is logged in.
11102
+ */
10732
11103
  static getLoggedInUser() {
10733
11104
  if (this.loggedInUser && typeof this.loggedInUser === "string") {
10734
11105
  this.loggedInUser = JSON.parse(this.loggedInUser);
10735
11106
  }
10736
11107
  return this.loggedInUser;
10737
11108
  }
11109
+ /**
11110
+ * Retrieves the auth token of the currently logged-in user.
11111
+ * @returns The auth token string, or null if no user is logged in.
11112
+ */
10738
11113
  static getUserAuthToken() {
10739
11114
  return this.loggedInUser?.authToken || null;
10740
11115
  }
11116
+ /**
11117
+ * Checks whether a user is currently logged in.
11118
+ * @returns True if a user is logged in with a valid auth token, false otherwise.
11119
+ */
10741
11120
  static isUserLoggedIn() {
10742
11121
  return this.loggedInUser !== null && this.loggedInUser.authToken !== undefined;
10743
11122
  }
11123
+ /**
11124
+ * Registers a login listener to receive login/logout lifecycle callbacks.
11125
+ * @param listenerId - A unique identifier for the listener.
11126
+ * @param listener - The listener object with callback methods.
11127
+ */
10744
11128
  static addLoginListener(listenerId, listener) {
10745
11129
  this.loginListeners.set(listenerId, listener);
10746
11130
  }
11131
+ /**
11132
+ * Removes a previously registered login listener.
11133
+ * @param listenerId - The unique identifier of the listener to remove.
11134
+ */
10747
11135
  static removeLoginListener(listenerId) {
10748
11136
  this.loginListeners.delete(listenerId);
10749
11137
  }
11138
+ /**
11139
+ * Generates a call token for the given session.
11140
+ * Uses the provided auth token or falls back to the logged-in user's token.
11141
+ * @param sessionId - The session ID to generate a token for.
11142
+ * @param authToken - Optional auth token. If omitted, the logged-in user's token is used.
11143
+ * @returns A Promise that resolves to an object containing the generated token.
11144
+ * @throws {CometChatException} If the session ID is missing, no auth token is available, or the SDK is not initialized.
11145
+ */
10750
11146
  static async generateToken(sessionId, authToken) {
10751
11147
  try {
10752
11148
  if (!sessionId || sessionId.trim() === "") {
@@ -10801,7 +11197,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10801
11197
  appId
10802
11198
  },
10803
11199
  body: {
10804
- platform: "web",
11200
+ platform: "react-native",
10805
11201
  deviceId: this.generateDeviceId()
10806
11202
  }
10807
11203
  });
@@ -10822,7 +11218,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10822
11218
  appId
10823
11219
  },
10824
11220
  body: {
10825
- platform: "web",
11221
+ platform: "react-native",
10826
11222
  deviceId: this.generateDeviceId()
10827
11223
  }
10828
11224
  });
@@ -10862,7 +11258,7 @@ var CometChatCalls = class extends SessionMethodsCore {
10862
11258
  }
10863
11259
  }
10864
11260
  this.loggedInUser = null;
10865
- this.clearSavedUser();
11261
+ await this.clearSavedUser();
10866
11262
  }
10867
11263
  static async callGenerateTokenAPI(sessionId, authToken) {
10868
11264
  const appId = this.appSettings?.appId || "";
@@ -10890,9 +11286,11 @@ var CometChatCalls = class extends SessionMethodsCore {
10890
11286
  baseURL: this.getBaseURL()
10891
11287
  });
10892
11288
  }
10893
- static saveUser(user) {
11289
+ static getStorageKey() {
11290
+ return `${this.appSettings?.appId}:common_store/user`;
11291
+ }
11292
+ static async saveUser(user) {
10894
11293
  try {
10895
- const key = `${this.appSettings?.appId}:common_store/user`;
10896
11294
  const userWithDefaults = {
10897
11295
  hasBlockedMe: false,
10898
11296
  blockedByMe: false,
@@ -10901,31 +11299,28 @@ var CometChatCalls = class extends SessionMethodsCore {
10901
11299
  role: user.role || "default",
10902
11300
  wsChannel: user.wsChannel || { identity: `[${this.appSettings?.appId}]${user.uid}` }
10903
11301
  };
10904
- localStorage.setItem(key, JSON.stringify(userWithDefaults));
11302
+ await __react_native_async_storage_async_storage.default.setItem(this.getStorageKey(), JSON.stringify(userWithDefaults));
10905
11303
  } catch (error) {
10906
- console.warn("Failed to save user to localStorage:", error);
11304
+ console.warn("Failed to save user to AsyncStorage:", error);
10907
11305
  }
10908
11306
  }
10909
- static getSavedUser() {
11307
+ static async getSavedUser() {
10910
11308
  try {
10911
- const key = `${this.appSettings?.appId}:common_store/user`;
10912
- const savedUser = localStorage.getItem(key);
10913
- return savedUser ? savedUser : null;
11309
+ return await __react_native_async_storage_async_storage.default.getItem(this.getStorageKey());
10914
11310
  } catch (error) {
10915
- console.warn("Failed to get saved user from localStorage:", error);
11311
+ console.warn("Failed to get saved user from AsyncStorage:", error);
10916
11312
  return null;
10917
11313
  }
10918
11314
  }
10919
- static clearSavedUser() {
11315
+ static async clearSavedUser() {
10920
11316
  try {
10921
- const key = `${this.appSettings?.appId}:common_store/user`;
10922
- localStorage.removeItem(key);
11317
+ await __react_native_async_storage_async_storage.default.removeItem(this.getStorageKey());
10923
11318
  } catch (error) {
10924
- console.warn("Failed to clear saved user from localStorage:", error);
11319
+ console.warn("Failed to clear saved user from AsyncStorage:", error);
10925
11320
  }
10926
11321
  }
10927
11322
  static generateDeviceId() {
10928
- return "web_" + Math.random().toString(36).substr(2, 9);
11323
+ return "rn_" + Math.random().toString(36).substring(2, 11);
10929
11324
  }
10930
11325
  static createError(error) {
10931
11326
  if (error.errorCode && error.errorDescription) {
@@ -10980,11 +11375,36 @@ var CometChatCalls = class extends SessionMethodsCore {
10980
11375
  }
10981
11376
  });
10982
11377
  }
10983
- static addEventListener(eventType, listener) {
10984
- return eventBus.subscribe(eventType, listener);
11378
+ /**
11379
+ * Adds an event listener for SDK events.
11380
+ * @param eventType - The type of event to listen for.
11381
+ * @param listener - The callback function to invoke when the event fires.
11382
+ * @param options - Optional configuration including an AbortSignal for automatic cleanup.
11383
+ * @returns An unsubscribe function to remove the listener.
11384
+ */
11385
+ static addEventListener(eventType, listener, options) {
11386
+ return eventBus.subscribe(eventType, listener, options);
11387
+ }
11388
+ /**
11389
+ * Sets the audio output mode (mobile only).
11390
+ * @param mode - The audio mode to set (e.g., 'SPEAKER', 'EARPIECE', 'BLUETOOTH', 'HEADPHONES').
11391
+ */
11392
+ static setAudioMode(mode) {
11393
+ setAudioMode(mode);
11394
+ }
11395
+ /**
11396
+ * Enables Picture-in-Picture (PIP) layout during the call.
11397
+ */
11398
+ static enablePictureInPictureLayout() {
11399
+ enablePictureInPictureLayout();
11400
+ }
11401
+ /**
11402
+ * Disables Picture-in-Picture (PIP) layout.
11403
+ */
11404
+ static disablePictureInPictureLayout() {
11405
+ disablePictureInPictureLayout();
10985
11406
  }
10986
11407
  };
10987
11408
 
10988
11409
  //#endregion
10989
- exports.CometChatCalls = CometChatCalls;
10990
- //# sourceMappingURL=index.js.map
11410
+ exports.CometChatCalls = CometChatCalls;