@ethora/chat-component-rn 26.10.9 → 26.10.11
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/CHANGELOG.md +17 -0
- package/README.md +126 -1
- package/lib/commonjs/booking/index.js +44 -0
- package/lib/commonjs/booking/index.js.map +1 -0
- package/lib/commonjs/booking/pendingScheduledCall.js +275 -0
- package/lib/commonjs/booking/pendingScheduledCall.js.map +1 -0
- package/lib/commonjs/booking/scheduleForm.js +91 -0
- package/lib/commonjs/booking/scheduleForm.js.map +1 -0
- package/lib/commonjs/booking/scheduledCall.js +141 -0
- package/lib/commonjs/booking/scheduledCall.js.map +1 -0
- package/lib/commonjs/booking/scheduledCallActions.js +128 -0
- package/lib/commonjs/booking/scheduledCallActions.js.map +1 -0
- package/lib/commonjs/booking/scheduledCallLink.js +143 -0
- package/lib/commonjs/booking/scheduledCallLink.js.map +1 -0
- package/lib/commonjs/booking/scheduledCallStore.js +64 -0
- package/lib/commonjs/booking/scheduledCallStore.js.map +1 -0
- package/lib/commonjs/booking/startRoomCall.js +84 -0
- package/lib/commonjs/booking/startRoomCall.js.map +1 -0
- package/lib/commonjs/calls/callBusy.js +18 -0
- package/lib/commonjs/calls/callBusy.js.map +1 -0
- package/lib/commonjs/calls/callDisplay.js +73 -0
- package/lib/commonjs/calls/callDisplay.js.map +1 -0
- package/lib/commonjs/calls/callMode.js +175 -0
- package/lib/commonjs/calls/callMode.js.map +1 -0
- package/lib/commonjs/calls/declineReport.js +20 -0
- package/lib/commonjs/calls/declineReport.js.map +1 -0
- package/lib/commonjs/calls/p2p/P2PCallController.js +724 -0
- package/lib/commonjs/calls/p2p/P2PCallController.js.map +1 -0
- package/lib/commonjs/calls/p2p/icePolicy.js +107 -0
- package/lib/commonjs/calls/p2p/icePolicy.js.map +1 -0
- package/lib/commonjs/calls/p2p/negotiator.js +202 -0
- package/lib/commonjs/calls/p2p/negotiator.js.map +1 -0
- package/lib/commonjs/calls/p2p/p2pRuntime.js +147 -0
- package/lib/commonjs/calls/p2p/p2pRuntime.js.map +1 -0
- package/lib/commonjs/calls/p2p/signalInbox.js +98 -0
- package/lib/commonjs/calls/p2p/signalInbox.js.map +1 -0
- package/lib/commonjs/calls/p2p/signalStanza.js +141 -0
- package/lib/commonjs/calls/p2p/signalStanza.js.map +1 -0
- package/lib/commonjs/calls/p2p/webrtcRuntime.js +53 -0
- package/lib/commonjs/calls/p2p/webrtcRuntime.js.map +1 -0
- package/lib/commonjs/calls/senderTrust.js +43 -0
- package/lib/commonjs/calls/senderTrust.js.map +1 -0
- package/lib/commonjs/calls/startCall.js +51 -0
- package/lib/commonjs/calls/startCall.js.map +1 -0
- package/lib/commonjs/components/Booking/BookingIcons.js +55 -0
- package/lib/commonjs/components/Booking/BookingIcons.js.map +1 -0
- package/lib/commonjs/components/Booking/ScheduleCallButton.js +64 -0
- package/lib/commonjs/components/Booking/ScheduleCallButton.js.map +1 -0
- package/lib/commonjs/components/Booking/ScheduleCallSheet.js +351 -0
- package/lib/commonjs/components/Booking/ScheduleCallSheet.js.map +1 -0
- package/lib/commonjs/components/Booking/ScheduledCallCard.js +203 -0
- package/lib/commonjs/components/Booking/ScheduledCallCard.js.map +1 -0
- package/lib/commonjs/components/Booking/ScheduledCallHost.js +23 -0
- package/lib/commonjs/components/Booking/ScheduledCallHost.js.map +1 -0
- package/lib/commonjs/components/Booking/ScheduledCallMessage.js +55 -0
- package/lib/commonjs/components/Booking/ScheduledCallMessage.js.map +1 -0
- package/lib/commonjs/components/Booking/ScheduledCallPreJoin.js +235 -0
- package/lib/commonjs/components/Booking/ScheduledCallPreJoin.js.map +1 -0
- package/lib/commonjs/components/Booking/bookingShared.js +305 -0
- package/lib/commonjs/components/Booking/bookingShared.js.map +1 -0
- package/lib/commonjs/components/MainComponents/AlbumGrid.js +6 -2
- package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +18 -12
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js +5 -2
- package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js.map +1 -1
- package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js +6 -3
- package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +13 -0
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageContainer.js +13 -0
- package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ReduxWrapper.js +10 -0
- package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +7 -16
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js +27 -1
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatMediaGrid.js +159 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatMediaGrid.js.map +1 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +203 -134
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/LeaveChatModal.js +180 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/LeaveChatModal.js.map +1 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +19 -15
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +100 -162
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/MediaViewer.js +824 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/MediaViewer.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/useSaveFile.js +179 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/useSaveFile.js.map +1 -0
- package/lib/commonjs/components/Modals/MessageSearchModal/MessageSearchModal.js +22 -5
- package/lib/commonjs/components/Modals/MessageSearchModal/MessageSearchModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +15 -8
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js +1 -1
- package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +3 -2
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/CallButtons.js +19 -11
- package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/CallControlBar.js +119 -0
- package/lib/commonjs/components/VideoCalls/CallControlBar.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/CallVideo.js +49 -0
- package/lib/commonjs/components/VideoCalls/CallVideo.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/GroupCallView.js +281 -0
- package/lib/commonjs/components/VideoCalls/GroupCallView.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/P2PCallRunner.js +151 -0
- package/lib/commonjs/components/VideoCalls/P2PCallRunner.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +38 -14
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +57 -128
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callActions.js +3 -0
- package/lib/commonjs/components/VideoCalls/callActions.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callElapsed.js +38 -0
- package/lib/commonjs/components/VideoCalls/callElapsed.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/callLive.js +15 -0
- package/lib/commonjs/components/VideoCalls/callLive.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/callSessionController.js +81 -24
- package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callSessionTypes.js +41 -0
- package/lib/commonjs/components/VideoCalls/callSessionTypes.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/groupLayout.js +43 -0
- package/lib/commonjs/components/VideoCalls/groupLayout.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/p2pCallSession.js +272 -0
- package/lib/commonjs/components/VideoCalls/p2pCallSession.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/useCallKeep.js +7 -2
- package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js +2 -1
- package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +4 -1
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +5 -1
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/MediaSourceContext.js +18 -0
- package/lib/commonjs/context/MediaSourceContext.js.map +1 -0
- package/lib/commonjs/context/xmppProvider.js +2 -1
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/callPush.js +3 -1
- package/lib/commonjs/helpers/callPush.js.map +1 -1
- package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js +3 -1
- package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
- package/lib/commonjs/helpers/constants/MODAL_TYPES.js +2 -0
- package/lib/commonjs/helpers/constants/MODAL_TYPES.js.map +1 -1
- package/lib/commonjs/helpers/incomingCallFromPush.js +63 -7
- package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -1
- package/lib/commonjs/helpers/publicChatsEntry.js +8 -6
- package/lib/commonjs/helpers/publicChatsEntry.js.map +1 -1
- package/lib/commonjs/helpers/pushPayload.js +5 -0
- package/lib/commonjs/helpers/pushPayload.js.map +1 -1
- package/lib/commonjs/helpers/reportRoom.js +76 -0
- package/lib/commonjs/helpers/reportRoom.js.map +1 -0
- package/lib/commonjs/helpers/roomMedia.js +118 -0
- package/lib/commonjs/helpers/roomMedia.js.map +1 -0
- package/lib/commonjs/i18n/strings.js +480 -0
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/main.js +93 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/callState.api.js +75 -0
- package/lib/commonjs/networking/api-requests/callState.api.js.map +1 -0
- package/lib/commonjs/networking/api-requests/push.api.js +29 -6
- package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/rooms.api.js +17 -15
- package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/scheduledCalls.api.js +141 -0
- package/lib/commonjs/networking/api-requests/scheduledCalls.api.js.map +1 -0
- package/lib/commonjs/networking/callTokenStanza.js +210 -50
- package/lib/commonjs/networking/callTokenStanza.js.map +1 -1
- package/lib/commonjs/roomStore/callSlice.js +59 -4
- package/lib/commonjs/roomStore/callSlice.js.map +1 -1
- package/lib/commonjs/services/appBadge.js +80 -0
- package/lib/commonjs/services/appBadge.js.map +1 -0
- package/lib/commonjs/services/languageSettings.js +47 -15
- package/lib/commonjs/services/languageSettings.js.map +1 -1
- package/lib/commonjs/services/pushRegistration.js +21 -5
- package/lib/commonjs/services/pushRegistration.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/module/booking/index.js +5 -0
- package/lib/module/booking/index.js.map +1 -0
- package/lib/module/booking/pendingScheduledCall.js +261 -0
- package/lib/module/booking/pendingScheduledCall.js.map +1 -0
- package/lib/module/booking/scheduleForm.js +79 -0
- package/lib/module/booking/scheduleForm.js.map +1 -0
- package/lib/module/booking/scheduledCall.js +129 -0
- package/lib/module/booking/scheduledCall.js.map +1 -0
- package/lib/module/booking/scheduledCallActions.js +118 -0
- package/lib/module/booking/scheduledCallActions.js.map +1 -0
- package/lib/module/booking/scheduledCallLink.js +136 -0
- package/lib/module/booking/scheduledCallLink.js.map +1 -0
- package/lib/module/booking/scheduledCallStore.js +60 -0
- package/lib/module/booking/scheduledCallStore.js.map +1 -0
- package/lib/module/booking/startRoomCall.js +80 -0
- package/lib/module/booking/startRoomCall.js.map +1 -0
- package/lib/module/calls/callBusy.js +13 -0
- package/lib/module/calls/callBusy.js.map +1 -0
- package/lib/module/calls/callDisplay.js +65 -0
- package/lib/module/calls/callDisplay.js.map +1 -0
- package/lib/module/calls/callMode.js +168 -0
- package/lib/module/calls/callMode.js.map +1 -0
- package/lib/module/calls/declineReport.js +16 -0
- package/lib/module/calls/declineReport.js.map +1 -0
- package/lib/module/calls/p2p/P2PCallController.js +718 -0
- package/lib/module/calls/p2p/P2PCallController.js.map +1 -0
- package/lib/module/calls/p2p/icePolicy.js +102 -0
- package/lib/module/calls/p2p/icePolicy.js.map +1 -0
- package/lib/module/calls/p2p/negotiator.js +197 -0
- package/lib/module/calls/p2p/negotiator.js.map +1 -0
- package/lib/module/calls/p2p/p2pRuntime.js +137 -0
- package/lib/module/calls/p2p/p2pRuntime.js.map +1 -0
- package/lib/module/calls/p2p/signalInbox.js +93 -0
- package/lib/module/calls/p2p/signalInbox.js.map +1 -0
- package/lib/module/calls/p2p/signalStanza.js +135 -0
- package/lib/module/calls/p2p/signalStanza.js.map +1 -0
- package/lib/module/calls/p2p/webrtcRuntime.js +46 -0
- package/lib/module/calls/p2p/webrtcRuntime.js.map +1 -0
- package/lib/module/calls/senderTrust.js +38 -0
- package/lib/module/calls/senderTrust.js.map +1 -0
- package/lib/module/calls/startCall.js +47 -0
- package/lib/module/calls/startCall.js.map +1 -0
- package/lib/module/components/Booking/BookingIcons.js +48 -0
- package/lib/module/components/Booking/BookingIcons.js.map +1 -0
- package/lib/module/components/Booking/ScheduleCallButton.js +59 -0
- package/lib/module/components/Booking/ScheduleCallButton.js.map +1 -0
- package/lib/module/components/Booking/ScheduleCallSheet.js +345 -0
- package/lib/module/components/Booking/ScheduleCallSheet.js.map +1 -0
- package/lib/module/components/Booking/ScheduledCallCard.js +197 -0
- package/lib/module/components/Booking/ScheduledCallCard.js.map +1 -0
- package/lib/module/components/Booking/ScheduledCallHost.js +18 -0
- package/lib/module/components/Booking/ScheduledCallHost.js.map +1 -0
- package/lib/module/components/Booking/ScheduledCallMessage.js +48 -0
- package/lib/module/components/Booking/ScheduledCallMessage.js.map +1 -0
- package/lib/module/components/Booking/ScheduledCallPreJoin.js +229 -0
- package/lib/module/components/Booking/ScheduledCallPreJoin.js.map +1 -0
- package/lib/module/components/Booking/bookingShared.js +291 -0
- package/lib/module/components/Booking/bookingShared.js.map +1 -0
- package/lib/module/components/MainComponents/AlbumGrid.js +6 -2
- package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +20 -14
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/LanguageSelectorButton.js +5 -2
- package/lib/module/components/MainComponents/LanguageSelectorButton.js.map +1 -1
- package/lib/module/components/MainComponents/LanguageSelectorModal.js +7 -4
- package/lib/module/components/MainComponents/LanguageSelectorModal.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +13 -0
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MessageContainer.js +13 -0
- package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/module/components/MainComponents/ReduxWrapper.js +10 -0
- package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +7 -16
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/MessageBubble/Message.js +27 -1
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatMediaGrid.js +154 -0
- package/lib/module/components/Modals/ChatProfileModal/ChatMediaGrid.js.map +1 -0
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +204 -136
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/LeaveChatModal.js +175 -0
- package/lib/module/components/Modals/ChatProfileModal/LeaveChatModal.js.map +1 -0
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +21 -15
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +100 -163
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/MediaViewer.js +819 -0
- package/lib/module/components/Modals/FilePreviewModal/MediaViewer.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/useSaveFile.js +172 -0
- package/lib/module/components/Modals/FilePreviewModal/useSaveFile.js.map +1 -0
- package/lib/module/components/Modals/MessageSearchModal/MessageSearchModal.js +20 -4
- package/lib/module/components/Modals/MessageSearchModal/MessageSearchModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +17 -10
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js +1 -1
- package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -1
- package/lib/module/components/VideoCalls/ActiveCallBar.js +3 -2
- package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -1
- package/lib/module/components/VideoCalls/CallButtons.js +19 -11
- package/lib/module/components/VideoCalls/CallButtons.js.map +1 -1
- package/lib/module/components/VideoCalls/CallControlBar.js +113 -0
- package/lib/module/components/VideoCalls/CallControlBar.js.map +1 -0
- package/lib/module/components/VideoCalls/CallVideo.js +43 -0
- package/lib/module/components/VideoCalls/CallVideo.js.map +1 -0
- package/lib/module/components/VideoCalls/GroupCallView.js +275 -0
- package/lib/module/components/VideoCalls/GroupCallView.js.map +1 -0
- package/lib/module/components/VideoCalls/P2PCallRunner.js +147 -0
- package/lib/module/components/VideoCalls/P2PCallRunner.js.map +1 -0
- package/lib/module/components/VideoCalls/VideoCallOverlay.js +38 -14
- package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallSession.js +46 -127
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/module/components/VideoCalls/callActions.js +3 -0
- package/lib/module/components/VideoCalls/callActions.js.map +1 -1
- package/lib/module/components/VideoCalls/callElapsed.js +33 -0
- package/lib/module/components/VideoCalls/callElapsed.js.map +1 -0
- package/lib/module/components/VideoCalls/callLive.js +10 -0
- package/lib/module/components/VideoCalls/callLive.js.map +1 -0
- package/lib/module/components/VideoCalls/callSessionController.js +80 -24
- package/lib/module/components/VideoCalls/callSessionController.js.map +1 -1
- package/lib/module/components/VideoCalls/callSessionTypes.js +37 -0
- package/lib/module/components/VideoCalls/callSessionTypes.js.map +1 -0
- package/lib/module/components/VideoCalls/groupLayout.js +36 -0
- package/lib/module/components/VideoCalls/groupLayout.js.map +1 -0
- package/lib/module/components/VideoCalls/p2pCallSession.js +256 -0
- package/lib/module/components/VideoCalls/p2pCallSession.js.map +1 -0
- package/lib/module/components/VideoCalls/useCallKeep.js +8 -2
- package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -1
- package/lib/module/components/VideoCalls/useOngoingCallNotification.js +2 -1
- package/lib/module/components/VideoCalls/useOngoingCallNotification.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +4 -1
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +5 -1
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/MediaSourceContext.js +13 -0
- package/lib/module/context/MediaSourceContext.js.map +1 -0
- package/lib/module/context/xmppProvider.js +2 -1
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/callPush.js +3 -1
- package/lib/module/helpers/callPush.js.map +1 -1
- package/lib/module/helpers/constants/MODAL_COMPONENTS.js +2 -1
- package/lib/module/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
- package/lib/module/helpers/constants/MODAL_TYPES.js +2 -0
- package/lib/module/helpers/constants/MODAL_TYPES.js.map +1 -1
- package/lib/module/helpers/incomingCallFromPush.js +63 -7
- package/lib/module/helpers/incomingCallFromPush.js.map +1 -1
- package/lib/module/helpers/publicChatsEntry.js +8 -6
- package/lib/module/helpers/publicChatsEntry.js.map +1 -1
- package/lib/module/helpers/pushPayload.js +5 -0
- package/lib/module/helpers/pushPayload.js.map +1 -1
- package/lib/module/helpers/reportRoom.js +70 -0
- package/lib/module/helpers/reportRoom.js.map +1 -0
- package/lib/module/helpers/roomMedia.js +112 -0
- package/lib/module/helpers/roomMedia.js.map +1 -0
- package/lib/module/i18n/strings.js +480 -0
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/main.js +5 -0
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/callState.api.js +66 -0
- package/lib/module/networking/api-requests/callState.api.js.map +1 -0
- package/lib/module/networking/api-requests/push.api.js +29 -6
- package/lib/module/networking/api-requests/push.api.js.map +1 -1
- package/lib/module/networking/api-requests/rooms.api.js +17 -15
- package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/module/networking/api-requests/scheduledCalls.api.js +130 -0
- package/lib/module/networking/api-requests/scheduledCalls.api.js.map +1 -0
- package/lib/module/networking/callTokenStanza.js +210 -50
- package/lib/module/networking/callTokenStanza.js.map +1 -1
- package/lib/module/roomStore/callSlice.js +57 -3
- package/lib/module/roomStore/callSlice.js.map +1 -1
- package/lib/module/services/appBadge.js +74 -0
- package/lib/module/services/appBadge.js.map +1 -0
- package/lib/module/services/languageSettings.js +44 -13
- package/lib/module/services/languageSettings.js.map +1 -1
- package/lib/module/services/pushRegistration.js +21 -5
- package/lib/module/services/pushRegistration.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/booking/index.d.ts +3 -0
- package/lib/typescript/booking/index.d.ts.map +1 -0
- package/lib/typescript/booking/pendingScheduledCall.d.ts +80 -0
- package/lib/typescript/booking/pendingScheduledCall.d.ts.map +1 -0
- package/lib/typescript/booking/scheduleForm.d.ts +28 -0
- package/lib/typescript/booking/scheduleForm.d.ts.map +1 -0
- package/lib/typescript/booking/scheduledCall.d.ts +52 -0
- package/lib/typescript/booking/scheduledCall.d.ts.map +1 -0
- package/lib/typescript/booking/scheduledCallActions.d.ts +22 -0
- package/lib/typescript/booking/scheduledCallActions.d.ts.map +1 -0
- package/lib/typescript/booking/scheduledCallLink.d.ts +37 -0
- package/lib/typescript/booking/scheduledCallLink.d.ts.map +1 -0
- package/lib/typescript/booking/scheduledCallStore.d.ts +47 -0
- package/lib/typescript/booking/scheduledCallStore.d.ts.map +1 -0
- package/lib/typescript/booking/startRoomCall.d.ts +12 -0
- package/lib/typescript/booking/startRoomCall.d.ts.map +1 -0
- package/lib/typescript/calls/callBusy.d.ts +9 -0
- package/lib/typescript/calls/callBusy.d.ts.map +1 -0
- package/lib/typescript/calls/callDisplay.d.ts +23 -0
- package/lib/typescript/calls/callDisplay.d.ts.map +1 -0
- package/lib/typescript/calls/callMode.d.ts +106 -0
- package/lib/typescript/calls/callMode.d.ts.map +1 -0
- package/lib/typescript/calls/declineReport.d.ts +11 -0
- package/lib/typescript/calls/declineReport.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/P2PCallController.d.ts +150 -0
- package/lib/typescript/calls/p2p/P2PCallController.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/icePolicy.d.ts +37 -0
- package/lib/typescript/calls/p2p/icePolicy.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/negotiator.d.ts +57 -0
- package/lib/typescript/calls/p2p/negotiator.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/p2pRuntime.d.ts +41 -0
- package/lib/typescript/calls/p2p/p2pRuntime.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/signalInbox.d.ts +35 -0
- package/lib/typescript/calls/p2p/signalInbox.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/signalStanza.d.ts +52 -0
- package/lib/typescript/calls/p2p/signalStanza.d.ts.map +1 -0
- package/lib/typescript/calls/p2p/webrtcRuntime.d.ts +32 -0
- package/lib/typescript/calls/p2p/webrtcRuntime.d.ts.map +1 -0
- package/lib/typescript/calls/senderTrust.d.ts +8 -0
- package/lib/typescript/calls/senderTrust.d.ts.map +1 -0
- package/lib/typescript/calls/startCall.d.ts +17 -0
- package/lib/typescript/calls/startCall.d.ts.map +1 -0
- package/lib/typescript/components/Booking/BookingIcons.d.ts +9 -0
- package/lib/typescript/components/Booking/BookingIcons.d.ts.map +1 -0
- package/lib/typescript/components/Booking/ScheduleCallButton.d.ts +11 -0
- package/lib/typescript/components/Booking/ScheduleCallButton.d.ts.map +1 -0
- package/lib/typescript/components/Booking/ScheduleCallSheet.d.ts +4 -0
- package/lib/typescript/components/Booking/ScheduleCallSheet.d.ts.map +1 -0
- package/lib/typescript/components/Booking/ScheduledCallCard.d.ts +14 -0
- package/lib/typescript/components/Booking/ScheduledCallCard.d.ts.map +1 -0
- package/lib/typescript/components/Booking/ScheduledCallHost.d.ts +10 -0
- package/lib/typescript/components/Booking/ScheduledCallHost.d.ts.map +1 -0
- package/lib/typescript/components/Booking/ScheduledCallMessage.d.ts +20 -0
- package/lib/typescript/components/Booking/ScheduledCallMessage.d.ts.map +1 -0
- package/lib/typescript/components/Booking/ScheduledCallPreJoin.d.ts +8 -0
- package/lib/typescript/components/Booking/ScheduledCallPreJoin.d.ts.map +1 -0
- package/lib/typescript/components/Booking/bookingShared.d.ts +199 -0
- package/lib/typescript/components/Booking/bookingShared.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts +3 -1
- package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts +3 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatMediaGrid.d.ts +16 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ChatMediaGrid.d.ts.map +1 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/LeaveChatModal.d.ts +18 -0
- package/lib/typescript/components/Modals/ChatProfileModal/LeaveChatModal.d.ts.map +1 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +16 -0
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/MediaViewer.d.ts +27 -0
- package/lib/typescript/components/Modals/FilePreviewModal/MediaViewer.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/useSaveFile.d.ts +9 -0
- package/lib/typescript/components/Modals/FilePreviewModal/useSaveFile.d.ts.map +1 -0
- package/lib/typescript/components/Modals/MessageSearchModal/MessageSearchModal.d.ts +8 -0
- package/lib/typescript/components/Modals/MessageSearchModal/MessageSearchModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserSettingsModal/LanguageCard.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/CallButtons.d.ts +2 -1
- package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/CallControlBar.d.ts +17 -0
- package/lib/typescript/components/VideoCalls/CallControlBar.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/CallVideo.d.ts +23 -0
- package/lib/typescript/components/VideoCalls/CallVideo.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/GroupCallView.d.ts +22 -0
- package/lib/typescript/components/VideoCalls/GroupCallView.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/P2PCallRunner.d.ts +2 -0
- package/lib/typescript/components/VideoCalls/P2PCallRunner.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +10 -12
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callActions.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callElapsed.d.ts +8 -0
- package/lib/typescript/components/VideoCalls/callElapsed.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/callLive.d.ts +9 -0
- package/lib/typescript/components/VideoCalls/callLive.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts +10 -31
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callSessionTypes.d.ts +60 -0
- package/lib/typescript/components/VideoCalls/callSessionTypes.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/groupLayout.d.ts +23 -0
- package/lib/typescript/components/VideoCalls/groupLayout.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/p2pCallSession.d.ts +31 -0
- package/lib/typescript/components/VideoCalls/p2pCallSession.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/MediaSourceContext.d.ts +4 -0
- package/lib/typescript/context/MediaSourceContext.d.ts.map +1 -0
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/callPush.d.ts +11 -1
- package/lib/typescript/helpers/callPush.d.ts.map +1 -1
- package/lib/typescript/helpers/constants/MODAL_COMPONENTS.d.ts.map +1 -1
- package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts +2 -0
- package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts.map +1 -1
- package/lib/typescript/helpers/incomingCallFromPush.d.ts.map +1 -1
- package/lib/typescript/helpers/publicChatsEntry.d.ts +7 -5
- package/lib/typescript/helpers/publicChatsEntry.d.ts.map +1 -1
- package/lib/typescript/helpers/pushPayload.d.ts +1 -1
- package/lib/typescript/helpers/pushPayload.d.ts.map +1 -1
- package/lib/typescript/helpers/reportRoom.d.ts +19 -0
- package/lib/typescript/helpers/reportRoom.d.ts.map +1 -0
- package/lib/typescript/helpers/roomMedia.d.ts +26 -0
- package/lib/typescript/helpers/roomMedia.d.ts.map +1 -0
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +6 -1
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/callState.api.d.ts +25 -0
- package/lib/typescript/networking/api-requests/callState.api.d.ts.map +1 -0
- package/lib/typescript/networking/api-requests/push.api.d.ts +9 -2
- package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/rooms.api.d.ts +8 -6
- package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/scheduledCalls.api.d.ts +86 -0
- package/lib/typescript/networking/api-requests/scheduledCalls.api.d.ts.map +1 -0
- package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -1
- package/lib/typescript/roomStore/callSlice.d.ts +23 -1
- package/lib/typescript/roomStore/callSlice.d.ts.map +1 -1
- package/lib/typescript/services/appBadge.d.ts +3 -0
- package/lib/typescript/services/appBadge.d.ts.map +1 -0
- package/lib/typescript/services/languageSettings.d.ts +7 -0
- package/lib/typescript/services/languageSettings.d.ts.map +1 -1
- package/lib/typescript/services/pushRegistration.d.ts.map +1 -1
- package/lib/typescript/types/models/modal.model.d.ts +18 -0
- package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +85 -4
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/lib/typescript/version.d.ts.map +1 -1
- package/package.json +9 -2
- package/src/booking/index.ts +10 -0
- package/src/booking/pendingScheduledCall.ts +272 -0
- package/src/booking/scheduleForm.ts +84 -0
- package/src/booking/scheduledCall.ts +163 -0
- package/src/booking/scheduledCallActions.ts +141 -0
- package/src/booking/scheduledCallLink.ts +145 -0
- package/src/booking/scheduledCallStore.ts +69 -0
- package/src/booking/startRoomCall.ts +103 -0
- package/src/calls/callBusy.ts +10 -0
- package/src/calls/callDisplay.ts +74 -0
- package/src/calls/callMode.ts +286 -0
- package/src/calls/declineReport.ts +16 -0
- package/src/calls/p2p/P2PCallController.ts +813 -0
- package/src/calls/p2p/icePolicy.ts +99 -0
- package/src/calls/p2p/negotiator.ts +186 -0
- package/src/calls/p2p/p2pRuntime.ts +164 -0
- package/src/calls/p2p/signalInbox.ts +117 -0
- package/src/calls/p2p/signalStanza.ts +205 -0
- package/src/calls/p2p/webrtcRuntime.ts +60 -0
- package/src/calls/senderTrust.ts +40 -0
- package/src/calls/startCall.ts +56 -0
- package/src/components/Booking/BookingIcons.tsx +44 -0
- package/src/components/Booking/ScheduleCallButton.tsx +66 -0
- package/src/components/Booking/ScheduleCallSheet.tsx +380 -0
- package/src/components/Booking/ScheduledCallCard.tsx +216 -0
- package/src/components/Booking/ScheduledCallHost.tsx +18 -0
- package/src/components/Booking/ScheduledCallMessage.tsx +62 -0
- package/src/components/Booking/ScheduledCallPreJoin.tsx +230 -0
- package/src/components/Booking/bookingShared.tsx +295 -0
- package/src/components/MainComponents/AlbumGrid.tsx +5 -1
- package/src/components/MainComponents/ChatHeader.tsx +18 -11
- package/src/components/MainComponents/LanguageSelectorButton.tsx +9 -2
- package/src/components/MainComponents/LanguageSelectorModal.tsx +10 -6
- package/src/components/MainComponents/MediaMessage.tsx +13 -2
- package/src/components/MainComponents/MessageContainer.tsx +15 -0
- package/src/components/MainComponents/ReduxWrapper.tsx +10 -0
- package/src/components/MainComponents/RoomList.tsx +8 -19
- package/src/components/MessageBubble/Message.tsx +24 -1
- package/src/components/Modals/ChatProfileModal/ChatMediaGrid.tsx +174 -0
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +119 -48
- package/src/components/Modals/ChatProfileModal/LeaveChatModal.tsx +191 -0
- package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +22 -22
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +115 -185
- package/src/components/Modals/FilePreviewModal/MediaViewer.tsx +880 -0
- package/src/components/Modals/FilePreviewModal/useSaveFile.ts +207 -0
- package/src/components/Modals/MessageSearchModal/MessageSearchModal.tsx +56 -30
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +28 -9
- package/src/components/Modals/UserSettingsModal/LanguageCard.tsx +9 -7
- package/src/components/VideoCalls/ActiveCallBar.tsx +6 -5
- package/src/components/VideoCalls/CallButtons.tsx +23 -12
- package/src/components/VideoCalls/CallControlBar.tsx +131 -0
- package/src/components/VideoCalls/CallVideo.tsx +59 -0
- package/src/components/VideoCalls/GroupCallView.tsx +324 -0
- package/src/components/VideoCalls/P2PCallRunner.tsx +192 -0
- package/src/components/VideoCalls/VideoCallOverlay.tsx +62 -17
- package/src/components/VideoCalls/VideoCallSession.tsx +55 -133
- package/src/components/VideoCalls/callActions.ts +3 -0
- package/src/components/VideoCalls/callElapsed.ts +27 -0
- package/src/components/VideoCalls/callLive.ts +13 -0
- package/src/components/VideoCalls/callSessionController.ts +130 -55
- package/src/components/VideoCalls/callSessionTypes.ts +80 -0
- package/src/components/VideoCalls/groupLayout.ts +48 -0
- package/src/components/VideoCalls/p2pCallSession.ts +291 -0
- package/src/components/VideoCalls/useCallKeep.ts +9 -2
- package/src/components/VideoCalls/useOngoingCallNotification.ts +2 -2
- package/src/components/styled/MessageImage.tsx +3 -1
- package/src/components/styled/VideoMessage.tsx +5 -1
- package/src/context/MediaSourceContext.tsx +14 -0
- package/src/context/xmppProvider.tsx +3 -0
- package/src/helpers/callPush.ts +13 -1
- package/src/helpers/constants/MODAL_COMPONENTS.tsx +4 -1
- package/src/helpers/constants/MODAL_TYPES.ts +2 -0
- package/src/helpers/incomingCallFromPush.ts +65 -7
- package/src/helpers/publicChatsEntry.ts +8 -7
- package/src/helpers/pushPayload.ts +9 -1
- package/src/helpers/reportRoom.ts +93 -0
- package/src/helpers/roomMedia.ts +126 -0
- package/src/i18n/strings.ts +480 -0
- package/src/main.ts +33 -0
- package/src/networking/api-requests/callState.api.ts +83 -0
- package/src/networking/api-requests/push.api.ts +28 -3
- package/src/networking/api-requests/rooms.api.ts +25 -15
- package/src/networking/api-requests/scheduledCalls.api.ts +232 -0
- package/src/networking/callTokenStanza.ts +247 -50
- package/src/roomStore/callSlice.ts +86 -2
- package/src/services/appBadge.ts +85 -0
- package/src/services/languageSettings.ts +43 -8
- package/src/services/pushRegistration.ts +34 -3
- package/src/types/models/modal.model.ts +16 -0
- package/src/types/types.ts +86 -4
- package/src/version.ts +1 -1
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { store } from '../roomStore';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Deep links for scheduled calls.
|
|
5
|
+
*
|
|
6
|
+
* https://<host>/call/<slug> universal / app link, <host> must be a known host
|
|
7
|
+
* <scheme>://call/<slug> the app's own URL scheme
|
|
8
|
+
*
|
|
9
|
+
* The slug is the secret in the link; this only extracts it. Whether the
|
|
10
|
+
* signed-in user may see the call is the server's answer to
|
|
11
|
+
* `GET /v1/chats/calls/scheduled/:slug`.
|
|
12
|
+
*
|
|
13
|
+
* Known hosts and schemes come from `config.scheduledCalls` and from
|
|
14
|
+
* `configureScheduledCallLinks()`, which a host calls at startup so a link
|
|
15
|
+
* that opens the app before `<Chat>` is mounted can already be recognised.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** The hosted web app: always accepted. */
|
|
19
|
+
export const DEFAULT_SCHEDULED_CALL_HOSTS = ['app.chat.ethora.com'];
|
|
20
|
+
|
|
21
|
+
export interface ScheduledCallLinkOptions {
|
|
22
|
+
/** Hosts whose `https://<host>/call/<slug>` links open the app. */
|
|
23
|
+
hosts?: string[];
|
|
24
|
+
/** Custom URL schemes, without `://` (e.g. `ethorachat`). */
|
|
25
|
+
schemes?: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let configured: Required<ScheduledCallLinkOptions> = { hosts: [], schemes: [] };
|
|
29
|
+
|
|
30
|
+
const clean = (value: string): string =>
|
|
31
|
+
String(value || '')
|
|
32
|
+
.trim()
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.replace(/:\/\/.*$/, '')
|
|
35
|
+
.replace(/:$/, '');
|
|
36
|
+
|
|
37
|
+
const cleanHost = (value: string): string =>
|
|
38
|
+
String(value || '')
|
|
39
|
+
.trim()
|
|
40
|
+
.toLowerCase()
|
|
41
|
+
.replace(/^https?:\/\//, '')
|
|
42
|
+
.replace(/\/.*$/, '')
|
|
43
|
+
.replace(/:\d+$/, '');
|
|
44
|
+
|
|
45
|
+
/** Replaces the host list and schemes set by a previous call. */
|
|
46
|
+
export const configureScheduledCallLinks = (
|
|
47
|
+
options: ScheduledCallLinkOptions
|
|
48
|
+
): void => {
|
|
49
|
+
configured = {
|
|
50
|
+
hosts: (options.hosts || []).map(cleanHost).filter(Boolean),
|
|
51
|
+
schemes: (options.schemes || []).map(clean).filter(Boolean),
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const __resetScheduledCallLinksForTests = (): void => {
|
|
56
|
+
configured = { hosts: [], schemes: [] };
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const fromStore = (): ScheduledCallLinkOptions => {
|
|
60
|
+
try {
|
|
61
|
+
return store.getState().chatSettingStore?.config?.scheduledCalls || {};
|
|
62
|
+
} catch {
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/** Every host and scheme in force right now. */
|
|
68
|
+
export const getScheduledCallLinkTargets = (): Required<ScheduledCallLinkOptions> => {
|
|
69
|
+
const fromConfig = fromStore();
|
|
70
|
+
const hosts = new Set<string>([
|
|
71
|
+
...DEFAULT_SCHEDULED_CALL_HOSTS,
|
|
72
|
+
...configured.hosts,
|
|
73
|
+
...(fromConfig.hosts || []).map(cleanHost),
|
|
74
|
+
]);
|
|
75
|
+
const schemes = new Set<string>([
|
|
76
|
+
...configured.schemes,
|
|
77
|
+
...(fromConfig.schemes || []).map(clean),
|
|
78
|
+
]);
|
|
79
|
+
hosts.delete('');
|
|
80
|
+
schemes.delete('');
|
|
81
|
+
return { hosts: [...hosts], schemes: [...schemes] };
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// 22+ url-safe characters per the contract; accept a little shorter so a
|
|
85
|
+
// backend that trims its encoding does not break every link.
|
|
86
|
+
const SLUG = /^[A-Za-z0-9_-]{16,128}$/;
|
|
87
|
+
const URL_SHAPE = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]*)([^?#]*)(?:\?[^#]*)?(?:#.*)?$/i;
|
|
88
|
+
const NEVER_SCHEMES = new Set(['javascript', 'data', 'file', 'blob', 'about', 'vbscript']);
|
|
89
|
+
|
|
90
|
+
const slugFromPath = (path: string, prefix: '/call/' | '/'): string | null => {
|
|
91
|
+
if (!path.startsWith(prefix)) {return null;}
|
|
92
|
+
const rest = path.slice(prefix.length).replace(/\/+$/, '');
|
|
93
|
+
if (rest.includes('/')) {return null;}
|
|
94
|
+
let slug = rest;
|
|
95
|
+
try {
|
|
96
|
+
slug = decodeURIComponent(rest);
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return SLUG.test(slug) ? slug : null;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The slug of a scheduled-call link, or null when the URL is anything else.
|
|
105
|
+
*
|
|
106
|
+
* `https://app.chat.ethora.com/call/<slug>` (and any other configured host)
|
|
107
|
+
* and `<scheme>://call/<slug>` qualify. With no scheme configured any custom
|
|
108
|
+
* scheme is accepted (only `http(s)` and a few script-like ones never are);
|
|
109
|
+
* once schemes are configured only those are.
|
|
110
|
+
*/
|
|
111
|
+
export const parseScheduledCallLink = (
|
|
112
|
+
url: string | null | undefined,
|
|
113
|
+
options?: ScheduledCallLinkOptions
|
|
114
|
+
): string | null => {
|
|
115
|
+
if (typeof url !== 'string') {return null;}
|
|
116
|
+
const match = URL_SHAPE.exec(url.trim());
|
|
117
|
+
if (!match) {return null;}
|
|
118
|
+
const scheme = match[1].toLowerCase();
|
|
119
|
+
const authority = match[2];
|
|
120
|
+
const path = match[3] || '';
|
|
121
|
+
|
|
122
|
+
const targets = getScheduledCallLinkTargets();
|
|
123
|
+
const hosts = options?.hosts?.length
|
|
124
|
+
? options.hosts.map(cleanHost)
|
|
125
|
+
: targets.hosts;
|
|
126
|
+
const schemes = options?.schemes?.length
|
|
127
|
+
? options.schemes.map(clean)
|
|
128
|
+
: targets.schemes;
|
|
129
|
+
|
|
130
|
+
if (scheme === 'https' || scheme === 'http') {
|
|
131
|
+
// Universal links are https only; a plain http link is never trusted.
|
|
132
|
+
if (scheme !== 'https') {return null;}
|
|
133
|
+
if (authority.includes('@')) {return null;}
|
|
134
|
+
const host = cleanHost(authority);
|
|
135
|
+
if (!host || !hosts.includes(host)) {return null;}
|
|
136
|
+
return slugFromPath(path, '/call/');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (NEVER_SCHEMES.has(scheme)) {return null;}
|
|
140
|
+
if (schemes.length > 0 && !schemes.includes(scheme)) {return null;}
|
|
141
|
+
// <scheme>://call/<slug>; some launchers hand over <scheme>:///call/<slug>.
|
|
142
|
+
if (authority.toLowerCase() === 'call') {return slugFromPath(path, '/');}
|
|
143
|
+
if (authority === '') {return slugFromPath(path, '/call/');}
|
|
144
|
+
return null;
|
|
145
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
import type {
|
|
3
|
+
ScheduledCallDetail,
|
|
4
|
+
} from '../networking/api-requests/scheduledCalls.api';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* UI state of the scheduled-call flow: the pre-join sheet (a call opened from
|
|
8
|
+
* a card or a link) and the editor (schedule a new call / edit one). Kept
|
|
9
|
+
* outside redux because it is transient and has no business in persistence,
|
|
10
|
+
* the same way the call overlay's own UI state is (VideoCalls/callUiStore).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export type PreJoinErrorReason =
|
|
14
|
+
| 'not-a-member'
|
|
15
|
+
| 'not-found'
|
|
16
|
+
| 'cancelled'
|
|
17
|
+
| 'network';
|
|
18
|
+
|
|
19
|
+
export type PreJoinState =
|
|
20
|
+
| { phase: 'loading'; slug: string }
|
|
21
|
+
| { phase: 'ready'; slug: string; detail: ScheduledCallDetail }
|
|
22
|
+
| {
|
|
23
|
+
phase: 'error';
|
|
24
|
+
slug: string;
|
|
25
|
+
reason: PreJoinErrorReason;
|
|
26
|
+
/** The call's title when the server told us (cancelled). */
|
|
27
|
+
title?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type EditorState =
|
|
31
|
+
| { mode: 'create'; roomJid: string }
|
|
32
|
+
| { mode: 'edit'; roomJid: string; detail: ScheduledCallDetail };
|
|
33
|
+
|
|
34
|
+
interface ScheduledCallUiState {
|
|
35
|
+
preJoin: PreJoinState | null;
|
|
36
|
+
editor: EditorState | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let state: ScheduledCallUiState = { preJoin: null, editor: null };
|
|
40
|
+
const listeners = new Set<() => void>();
|
|
41
|
+
|
|
42
|
+
const emit = (patch: Partial<ScheduledCallUiState>) => {
|
|
43
|
+
state = { ...state, ...patch };
|
|
44
|
+
listeners.forEach((listener) => listener());
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const scheduledCallUi = {
|
|
48
|
+
getState: (): ScheduledCallUiState => state,
|
|
49
|
+
subscribe: (listener: () => void): (() => void) => {
|
|
50
|
+
listeners.add(listener);
|
|
51
|
+
return () => {
|
|
52
|
+
listeners.delete(listener);
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
showPreJoin: (preJoin: PreJoinState) => emit({ preJoin }),
|
|
56
|
+
closePreJoin: () => emit({ preJoin: null }),
|
|
57
|
+
openCreate: (roomJid: string) => emit({ editor: { mode: 'create', roomJid } }),
|
|
58
|
+
openEdit: (roomJid: string, detail: ScheduledCallDetail) =>
|
|
59
|
+
emit({ editor: { mode: 'edit', roomJid, detail } }),
|
|
60
|
+
closeEditor: () => emit({ editor: null }),
|
|
61
|
+
reset: () => emit({ preJoin: null, editor: null }),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const useScheduledCallUi = (): ScheduledCallUiState =>
|
|
65
|
+
useSyncExternalStore(
|
|
66
|
+
scheduledCallUi.subscribe,
|
|
67
|
+
scheduledCallUi.getState,
|
|
68
|
+
scheduledCallUi.getState
|
|
69
|
+
);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { store } from '../roomStore';
|
|
2
|
+
import {
|
|
3
|
+
acceptIncomingCall,
|
|
4
|
+
setCallError,
|
|
5
|
+
startOutgoingCall,
|
|
6
|
+
} from '../roomStore/callSlice';
|
|
7
|
+
import { sendCallInviteSignal } from '../networking/callTokenStanza';
|
|
8
|
+
import { requestOutgoingCall } from '../calls/startCall';
|
|
9
|
+
import { chatNameOfRoom } from './scheduledCall';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Joining a scheduled call is the ordinary call start for that room, taken
|
|
13
|
+
* on a user tap: a private room starts (or answers) its call, a group or
|
|
14
|
+
* public room starts or joins the room call. This file is the ONE place the
|
|
15
|
+
* booking flow reaches into the call path, so when the call transport
|
|
16
|
+
* changes only this function follows (it mirrors CallButtons.placeCall and
|
|
17
|
+
* hands the request to the shared requestOutgoingCall, so a private room
|
|
18
|
+
* gets the p2p call and a group room the LiveKit one, as the server decides).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export type StartRoomCallOutcome =
|
|
22
|
+
| 'started'
|
|
23
|
+
| 'answered'
|
|
24
|
+
| 'busy'
|
|
25
|
+
| 'disabled'
|
|
26
|
+
| 'no-room'
|
|
27
|
+
| 'failed';
|
|
28
|
+
|
|
29
|
+
const BAD_TITLES = ['deleted', 'deleted user', 'unknown', 'null'];
|
|
30
|
+
|
|
31
|
+
export const startRoomCall = async (
|
|
32
|
+
roomJid: string,
|
|
33
|
+
kind: 'audio' | 'video'
|
|
34
|
+
): Promise<StartRoomCallOutcome> => {
|
|
35
|
+
const state = store.getState();
|
|
36
|
+
if (state.chatSettingStore.config?.videoCalls?.enabled !== true) {
|
|
37
|
+
return 'disabled';
|
|
38
|
+
}
|
|
39
|
+
const chatName = chatNameOfRoom(roomJid);
|
|
40
|
+
if (!chatName) {return 'no-room';}
|
|
41
|
+
|
|
42
|
+
const room = Object.values(state.rooms.rooms || {}).find(
|
|
43
|
+
(r: any) => chatNameOfRoom(r?.jid || '') === chatName
|
|
44
|
+
) as any;
|
|
45
|
+
const fullJid: string = room?.jid || roomJid;
|
|
46
|
+
if (!fullJid.includes('@')) {return 'no-room';}
|
|
47
|
+
|
|
48
|
+
const call = state.call;
|
|
49
|
+
if (call.phase !== 'idle') {
|
|
50
|
+
// The same room is already ringing us: joining means answering it.
|
|
51
|
+
if (
|
|
52
|
+
call.phase === 'ringing-incoming' &&
|
|
53
|
+
call.roomBareName === chatName
|
|
54
|
+
) {
|
|
55
|
+
store.dispatch(acceptIncomingCall());
|
|
56
|
+
return 'answered';
|
|
57
|
+
}
|
|
58
|
+
return 'busy';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const selfLocal = String(
|
|
62
|
+
state.chatSettingStore.user?.xmppUsername || ''
|
|
63
|
+
).split('@')[0];
|
|
64
|
+
const isGroup = room?.type === 'group';
|
|
65
|
+
const peer =
|
|
66
|
+
room?.type === 'private'
|
|
67
|
+
? (room?.members || []).find((member: any) => {
|
|
68
|
+
const local = String(member?.xmppUsername || '').split('@')[0];
|
|
69
|
+
return local && local !== selfLocal;
|
|
70
|
+
})
|
|
71
|
+
: undefined;
|
|
72
|
+
const peerXmppUsername: string | null = peer?.xmppUsername || null;
|
|
73
|
+
|
|
74
|
+
const rawTitle = String(room?.title || room?.name || '').trim();
|
|
75
|
+
const peerDisplay = peer
|
|
76
|
+
? `${peer.firstName || ''} ${peer.lastName || ''}`.trim() || peer.name || ''
|
|
77
|
+
: '';
|
|
78
|
+
const bad = !rawTitle || BAD_TITLES.includes(rawTitle.toLowerCase());
|
|
79
|
+
const dialName = (bad ? peerDisplay : rawTitle) || peerDisplay || chatName;
|
|
80
|
+
|
|
81
|
+
store.dispatch(
|
|
82
|
+
startOutgoingCall({
|
|
83
|
+
roomJid: fullJid,
|
|
84
|
+
roomName: dialName,
|
|
85
|
+
roomBareName: chatName,
|
|
86
|
+
kind,
|
|
87
|
+
peerXmppUsername,
|
|
88
|
+
isGroup,
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
if (peerXmppUsername) {
|
|
92
|
+
sendCallInviteSignal(kind, { peerXmppUsername, roomBareName: chatName });
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
await requestOutgoingCall({ chatName, kind, peerXmppUsername });
|
|
96
|
+
return 'started';
|
|
97
|
+
} catch (error) {
|
|
98
|
+
store.dispatch(
|
|
99
|
+
setCallError(error instanceof Error ? error.message : 'call failed')
|
|
100
|
+
);
|
|
101
|
+
return 'failed';
|
|
102
|
+
}
|
|
103
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BusyCallSnapshot } from './callMode';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The call slice as `decideIncomingWhileBusy` should see it. A call that
|
|
5
|
+
* failed (phase 'error') only has its error card left on screen, waiting to
|
|
6
|
+
* be dismissed; it must not make the phone refuse the next incoming call as
|
|
7
|
+
* busy.
|
|
8
|
+
*/
|
|
9
|
+
export const busySnapshot = (call: BusyCallSnapshot): BusyCallSnapshot =>
|
|
10
|
+
call.phase === 'error' ? { ...call, phase: 'idle' } : call;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Display-name hygiene for the call UI. Names reach the ring screen from
|
|
2
|
+
// several places (a call-token attribute, a JWT claim, a room title, a push
|
|
3
|
+
// payload); this keeps raw identifiers and hostile text from ever being shown
|
|
4
|
+
// as a person's name.
|
|
5
|
+
|
|
6
|
+
/** Shown on the ring screen when no human-readable name is known. */
|
|
7
|
+
export const NEUTRAL_INCOMING_CALL_LABEL = 'Incoming call';
|
|
8
|
+
|
|
9
|
+
const MAX_CALL_NAME_LENGTH = 80;
|
|
10
|
+
|
|
11
|
+
const HEX24 = '[0-9a-fA-F]{24}';
|
|
12
|
+
// A user JID local part: <appId>_<userId>, optionally with an @domain.
|
|
13
|
+
const USER_ID = `${HEX24}_${HEX24}(?:@[A-Za-z0-9.]+)?`;
|
|
14
|
+
|
|
15
|
+
// A 1:1 chat is named "<jidA>-<jidB>" (two user ids joined by a hyphen).
|
|
16
|
+
const ONE_TO_ONE_ROOM = new RegExp(`^${USER_ID}(?:-${USER_ID})*$`);
|
|
17
|
+
// A group chat is named "<appId>_<uuid>".
|
|
18
|
+
const GROUP_ROOM = new RegExp(
|
|
19
|
+
`^${HEX24}_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`
|
|
20
|
+
);
|
|
21
|
+
// Anything long that is nothing but hex, underscores and hyphens is an id.
|
|
22
|
+
const OPAQUE_ID = /^[0-9a-f_-]{16,}$/i;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* True for strings that are a chat's internal name or an id rather than
|
|
26
|
+
* something a person would be called: two user JIDs joined (the private chat
|
|
27
|
+
* name), a lone user id, an `<appId>_<uuid>` group name, or any long run of
|
|
28
|
+
* hex / underscore / hyphen.
|
|
29
|
+
*/
|
|
30
|
+
export const looksLikeRawRoomName = (value: unknown): boolean => {
|
|
31
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
32
|
+
if (!text) return false;
|
|
33
|
+
return (
|
|
34
|
+
ONE_TO_ONE_ROOM.test(text) ||
|
|
35
|
+
GROUP_ROOM.test(text) ||
|
|
36
|
+
OPAQUE_ID.test(text)
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// C0/C1 controls, bidi overrides/isolates and zero-width characters: none of
|
|
41
|
+
// them belong in a name, and the bidi ones can make text read backwards.
|
|
42
|
+
// eslint-disable-next-line no-control-regex
|
|
43
|
+
const UNWANTED_CHARS = /[\u0000-\u001F\u007F-\u009F----]/g;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Plain-text, display-safe version of a name: control characters stripped,
|
|
47
|
+
* whitespace collapsed and trimmed, capped at about 80 characters. Returns ''
|
|
48
|
+
* when nothing usable is left or the value is a raw chat name / id.
|
|
49
|
+
*/
|
|
50
|
+
export const sanitizeCallName = (value: unknown): string => {
|
|
51
|
+
if (typeof value !== 'string') return '';
|
|
52
|
+
const cleaned = value
|
|
53
|
+
.replace(UNWANTED_CHARS, ' ')
|
|
54
|
+
.replace(/\s+/g, ' ')
|
|
55
|
+
.trim();
|
|
56
|
+
if (!cleaned) return '';
|
|
57
|
+
// Cap by code point so a surrogate pair is never cut in half.
|
|
58
|
+
const capped = Array.from(cleaned).slice(0, MAX_CALL_NAME_LENGTH).join('').trim();
|
|
59
|
+
return looksLikeRawRoomName(capped) ? '' : capped;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** sanitizeCallName with null instead of '' (state-friendly). */
|
|
63
|
+
export const safeCallName = (value: unknown): string | null =>
|
|
64
|
+
sanitizeCallName(value) || null;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* An xmppUsername from a stanza attribute, or null when it is not shaped like
|
|
68
|
+
* one (it is only ever used for lookups and routing, never shown).
|
|
69
|
+
*/
|
|
70
|
+
export const sanitizeXmppUsername = (value: unknown): string | null => {
|
|
71
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
72
|
+
const local = text.split('/')[0];
|
|
73
|
+
return /^[A-Za-z0-9_-]{1,128}(?:@[A-Za-z0-9.-]+)?$/.test(local) ? local : null;
|
|
74
|
+
};
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// Pure helpers that decide HOW a call is carried, shared by the dialer
|
|
2
|
+
// (ChatHeader), the stanza handler (callTokenStanza) and the overlay.
|
|
3
|
+
//
|
|
4
|
+
// Three kinds of call exist:
|
|
5
|
+
// - 1:1 over our own WebRTC peer connection ("p2p"): chosen by the server,
|
|
6
|
+
// only for private chats and only when the install has P2P enabled;
|
|
7
|
+
// - 1:1 over LiveKit: the fallback when the server answers `livekit`;
|
|
8
|
+
// - group over LiveKit: any non-private chat, always `livekit`.
|
|
9
|
+
// The client never picks the transport, it follows the server's `mode`.
|
|
10
|
+
|
|
11
|
+
import { sanitizeCallName, sanitizeXmppUsername } from './callDisplay';
|
|
12
|
+
|
|
13
|
+
export type CallMode = 'livekit' | 'p2p';
|
|
14
|
+
export type CallKindName = 'audio' | 'video';
|
|
15
|
+
export type CallRoomType = 'private' | 'group';
|
|
16
|
+
|
|
17
|
+
/** Serializable subset of RTCIceServer (kept free of DOM types for redux). */
|
|
18
|
+
export interface IceServerConfig {
|
|
19
|
+
urls: string | string[];
|
|
20
|
+
username?: string;
|
|
21
|
+
credential?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ICE_URL_RE = /^(stun|stuns|turn|turns):/i;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Accepts an array, an `{ iceServers }` envelope or a JSON string of either
|
|
28
|
+
* (the call-token stanza carries the list as a JSON attribute) and returns
|
|
29
|
+
* only well formed stun/turn entries. Anything else is dropped, never thrown.
|
|
30
|
+
*/
|
|
31
|
+
export const normalizeIceServers = (raw: unknown): IceServerConfig[] => {
|
|
32
|
+
let value: unknown = raw;
|
|
33
|
+
if (typeof value === 'string') {
|
|
34
|
+
const text = value.trim();
|
|
35
|
+
if (!text) return [];
|
|
36
|
+
try {
|
|
37
|
+
value = JSON.parse(text);
|
|
38
|
+
} catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (
|
|
43
|
+
value &&
|
|
44
|
+
!Array.isArray(value) &&
|
|
45
|
+
typeof value === 'object' &&
|
|
46
|
+
Array.isArray((value as { iceServers?: unknown }).iceServers)
|
|
47
|
+
) {
|
|
48
|
+
value = (value as { iceServers: unknown[] }).iceServers;
|
|
49
|
+
}
|
|
50
|
+
if (!Array.isArray(value)) return [];
|
|
51
|
+
|
|
52
|
+
const out: IceServerConfig[] = [];
|
|
53
|
+
for (const entry of value) {
|
|
54
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
55
|
+
const e = entry as Record<string, unknown>;
|
|
56
|
+
const rawUrls = e.urls ?? e.url;
|
|
57
|
+
const candidates: unknown[] = Array.isArray(rawUrls) ? rawUrls : [rawUrls];
|
|
58
|
+
const list = candidates
|
|
59
|
+
.filter((u): u is string => typeof u === 'string')
|
|
60
|
+
.map((u) => u.trim())
|
|
61
|
+
.filter((u) => ICE_URL_RE.test(u));
|
|
62
|
+
if (list.length === 0) continue;
|
|
63
|
+
const server: IceServerConfig = {
|
|
64
|
+
urls: typeof rawUrls === 'string' ? list[0] : list,
|
|
65
|
+
};
|
|
66
|
+
if (typeof e.username === 'string' && e.username) {
|
|
67
|
+
server.username = e.username;
|
|
68
|
+
}
|
|
69
|
+
if (typeof e.credential === 'string' && e.credential) {
|
|
70
|
+
server.credential = e.credential;
|
|
71
|
+
}
|
|
72
|
+
out.push(server);
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A LiveKit server URL as the backend publishes it. Only websocket / http(s)
|
|
79
|
+
* URLs are accepted: the value ends up as the connect target of the media
|
|
80
|
+
* session, so anything else (javascript:, data:, garbage) is treated as unset.
|
|
81
|
+
*/
|
|
82
|
+
export const normalizeLivekitUrl = (raw: unknown): string | null => {
|
|
83
|
+
const text = typeof raw === 'string' ? raw.trim() : '';
|
|
84
|
+
return /^(wss?|https?):\/\/[^\s]+$/i.test(text) ? text : null;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const isTrueish = (value: unknown): boolean => {
|
|
88
|
+
const text = String(value ?? '')
|
|
89
|
+
.trim()
|
|
90
|
+
.toLowerCase();
|
|
91
|
+
return text === 'true' || text === '1';
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** Attributes of a `<data type="call-token">` element, defensively read. */
|
|
95
|
+
export interface ParsedCallTokenAttrs {
|
|
96
|
+
token: string;
|
|
97
|
+
room: string;
|
|
98
|
+
/** Raw `callId` attribute, null when absent (the JWT may still carry it). */
|
|
99
|
+
callId: string | null;
|
|
100
|
+
/** Valid `kind` attribute, null when absent or unrecognised. */
|
|
101
|
+
kind: CallKindName | null;
|
|
102
|
+
mode: CallMode;
|
|
103
|
+
group: boolean;
|
|
104
|
+
/** Callee's ICE servers for `mode=p2p`, null when absent or unparseable. */
|
|
105
|
+
iceServers: IceServerConfig[] | null;
|
|
106
|
+
/**
|
|
107
|
+
* Public LiveKit wss URL for `mode=livekit`, null when the server did not
|
|
108
|
+
* send one (older backends), it is empty, or it is not a usable URL.
|
|
109
|
+
*/
|
|
110
|
+
livekitUrl: string | null;
|
|
111
|
+
/**
|
|
112
|
+
* Caller's display name as plain text (control characters stripped, capped,
|
|
113
|
+
* raw chat names refused); '' when absent. Only trustworthy from the system
|
|
114
|
+
* account, see calls/senderTrust.
|
|
115
|
+
*/
|
|
116
|
+
callerName: string;
|
|
117
|
+
/** Caller's xmppUsername when well formed, else null. Same trust rule. */
|
|
118
|
+
caller: string | null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Tolerant reader for the call-token stanza. A server that sends neither
|
|
123
|
+
* `mode` nor `group` (every server before P2P / group calls) yields
|
|
124
|
+
* `mode: 'livekit'`, `group: false`, i.e. exactly the legacy behaviour.
|
|
125
|
+
*/
|
|
126
|
+
export const parseCallTokenAttrs = (
|
|
127
|
+
attrs: Record<string, any> | undefined | null
|
|
128
|
+
): ParsedCallTokenAttrs => {
|
|
129
|
+
const a = attrs || {};
|
|
130
|
+
const kindRaw = String(a.kind || '')
|
|
131
|
+
.trim()
|
|
132
|
+
.toLowerCase();
|
|
133
|
+
const mode: CallMode =
|
|
134
|
+
String(a.mode || '')
|
|
135
|
+
.trim()
|
|
136
|
+
.toLowerCase() === 'p2p'
|
|
137
|
+
? 'p2p'
|
|
138
|
+
: 'livekit';
|
|
139
|
+
const iceList = mode === 'p2p' ? normalizeIceServers(a.ice) : [];
|
|
140
|
+
return {
|
|
141
|
+
token: String(a.token || '').trim(),
|
|
142
|
+
room: String(a.room || '').trim(),
|
|
143
|
+
callId: String(a.callId || a.callid || '').trim() || null,
|
|
144
|
+
kind: kindRaw === 'audio' || kindRaw === 'video' ? kindRaw : null,
|
|
145
|
+
mode,
|
|
146
|
+
// A p2p call is 1:1 by construction; never let a stray attribute flip it.
|
|
147
|
+
group: mode === 'livekit' && isTrueish(a.group),
|
|
148
|
+
iceServers: mode === 'p2p' && iceList.length > 0 ? iceList : null,
|
|
149
|
+
livekitUrl: mode === 'livekit' ? normalizeLivekitUrl(a.livekitUrl) : null,
|
|
150
|
+
callerName: sanitizeCallName(a.callerName),
|
|
151
|
+
caller: sanitizeXmppUsername(a.caller),
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/** Normalised `POST /v1/chats/call/create/:chatName` response. */
|
|
156
|
+
export interface CallCreateResult {
|
|
157
|
+
callId: string | null;
|
|
158
|
+
mode: CallMode;
|
|
159
|
+
kind: CallKindName;
|
|
160
|
+
/** Server-reported group flag, null when the server did not say. */
|
|
161
|
+
group: boolean | null;
|
|
162
|
+
/** Public LiveKit wss URL when the server knows it. */
|
|
163
|
+
livekitUrl: string | null;
|
|
164
|
+
iceServers: IceServerConfig[];
|
|
165
|
+
ttlSeconds: number | null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Reads the create response. Old servers answer with no `mode`, which maps to
|
|
170
|
+
* `livekit` (the caller then waits for its own call-token as before). A p2p
|
|
171
|
+
* answer without a callId is unusable (no way to correlate signalling) and
|
|
172
|
+
* throws.
|
|
173
|
+
*/
|
|
174
|
+
export const parseCallCreateResponse = (
|
|
175
|
+
data: unknown,
|
|
176
|
+
fallbackKind: CallKindName
|
|
177
|
+
): CallCreateResult => {
|
|
178
|
+
const root = (data && typeof data === 'object' ? data : {}) as Record<
|
|
179
|
+
string,
|
|
180
|
+
any
|
|
181
|
+
>;
|
|
182
|
+
const d =
|
|
183
|
+
root.result && typeof root.result === 'object' && !root.mode
|
|
184
|
+
? (root.result as Record<string, any>)
|
|
185
|
+
: root;
|
|
186
|
+
const mode: CallMode =
|
|
187
|
+
String(d.mode || '')
|
|
188
|
+
.trim()
|
|
189
|
+
.toLowerCase() === 'p2p'
|
|
190
|
+
? 'p2p'
|
|
191
|
+
: 'livekit';
|
|
192
|
+
const kindRaw = String(d.kind || '')
|
|
193
|
+
.trim()
|
|
194
|
+
.toLowerCase();
|
|
195
|
+
const callId = String(d.callId || d.callid || '').trim() || null;
|
|
196
|
+
if (mode === 'p2p' && !callId) {
|
|
197
|
+
throw new Error('Call response is missing callId');
|
|
198
|
+
}
|
|
199
|
+
const ttl = Number(d.ttlSeconds);
|
|
200
|
+
const livekitUrl = normalizeLivekitUrl(d.livekitUrl);
|
|
201
|
+
return {
|
|
202
|
+
callId,
|
|
203
|
+
mode,
|
|
204
|
+
kind:
|
|
205
|
+
kindRaw === 'audio' || kindRaw === 'video'
|
|
206
|
+
? (kindRaw as CallKindName)
|
|
207
|
+
: fallbackKind,
|
|
208
|
+
group: typeof d.group === 'boolean' ? d.group : null,
|
|
209
|
+
livekitUrl,
|
|
210
|
+
iceServers: mode === 'p2p' ? normalizeIceServers(d.iceServers) : [],
|
|
211
|
+
ttlSeconds: Number.isFinite(ttl) && ttl > 0 ? ttl : null,
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Which room types may start / receive calls. Hosts that never set
|
|
217
|
+
* `allowedRoomTypes` get 1:1 and group chats; an explicit list is respected
|
|
218
|
+
* as written (so `['private']` keeps a host on 1:1 only).
|
|
219
|
+
*/
|
|
220
|
+
export const DEFAULT_CALL_ROOM_TYPES: CallRoomType[] = ['private', 'group'];
|
|
221
|
+
|
|
222
|
+
export const isCallRoomTypeAllowed = (
|
|
223
|
+
roomType: string | undefined | null,
|
|
224
|
+
allowedRoomTypes?: CallRoomType[] | null
|
|
225
|
+
): boolean => {
|
|
226
|
+
if (roomType !== 'private' && roomType !== 'group') return false;
|
|
227
|
+
const allowed = allowedRoomTypes || DEFAULT_CALL_ROOM_TYPES;
|
|
228
|
+
return allowed.includes(roomType);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export interface BusyCallSnapshot {
|
|
232
|
+
phase: string;
|
|
233
|
+
direction: 'incoming' | 'outgoing' | null;
|
|
234
|
+
mode: CallMode;
|
|
235
|
+
callId: string | null;
|
|
236
|
+
roomBareName: string | null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* What to do with an incoming call-token while another call may be active.
|
|
241
|
+
* - accept: nothing active, ring.
|
|
242
|
+
* - duplicate: same callId as the active call (server re-delivery), ignore.
|
|
243
|
+
* - replace: legacy LiveKit behaviour (a new token overwrites the old
|
|
244
|
+
* call), kept exactly for livekit-vs-livekit.
|
|
245
|
+
* - glare-yield: both sides dialled each other; the lexicographically smaller
|
|
246
|
+
* callId wins on BOTH ends, and this is the loser: drop our
|
|
247
|
+
* outgoing call and ring for theirs.
|
|
248
|
+
* - glare-keep: same race, we hold the winning callId, ignore theirs (the
|
|
249
|
+
* other side yields).
|
|
250
|
+
* - busy: a different call is in progress, decline the newcomer.
|
|
251
|
+
*/
|
|
252
|
+
export type IncomingWhileBusyDecision =
|
|
253
|
+
| 'accept'
|
|
254
|
+
| 'duplicate'
|
|
255
|
+
| 'replace'
|
|
256
|
+
| 'glare-yield'
|
|
257
|
+
| 'glare-keep'
|
|
258
|
+
| 'busy';
|
|
259
|
+
|
|
260
|
+
export const decideIncomingWhileBusy = (
|
|
261
|
+
current: BusyCallSnapshot,
|
|
262
|
+
incoming: {
|
|
263
|
+
mode: CallMode;
|
|
264
|
+
callId: string | null;
|
|
265
|
+
roomBareName: string | null;
|
|
266
|
+
}
|
|
267
|
+
): IncomingWhileBusyDecision => {
|
|
268
|
+
if (current.phase === 'idle') return 'accept';
|
|
269
|
+
if (incoming.callId && current.callId === incoming.callId) return 'duplicate';
|
|
270
|
+
if (current.mode !== 'p2p' && incoming.mode !== 'p2p') return 'replace';
|
|
271
|
+
|
|
272
|
+
const sameRoom =
|
|
273
|
+
!!incoming.roomBareName && current.roomBareName === incoming.roomBareName;
|
|
274
|
+
if (
|
|
275
|
+
sameRoom &&
|
|
276
|
+
current.direction === 'outgoing' &&
|
|
277
|
+
current.phase === 'requesting' &&
|
|
278
|
+
incoming.mode === 'p2p' &&
|
|
279
|
+
current.mode === 'p2p' &&
|
|
280
|
+
current.callId &&
|
|
281
|
+
incoming.callId
|
|
282
|
+
) {
|
|
283
|
+
return incoming.callId < current.callId ? 'glare-yield' : 'glare-keep';
|
|
284
|
+
}
|
|
285
|
+
return 'busy';
|
|
286
|
+
};
|