@ethora/chat-component-rn 26.8.1 → 26.8.2
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 +96 -0
- package/README.md +43 -10
- package/lib/commonjs/assets/icons.js +7 -2
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/AuthForms/Login.js +4 -4
- package/lib/commonjs/components/AuthForms/Login.js.map +1 -1
- package/lib/commonjs/components/Header/HeaderRoomList.js +29 -8
- package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +9 -3
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +150 -14
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +34 -13
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/LoginWrapper.js +2 -1
- package/lib/commonjs/components/MainComponents/LoginWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +29 -9
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageContainer.js +5 -1
- package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +13 -5
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +14 -13
- package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +208 -35
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +317 -98
- package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +322 -110
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +546 -203
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +69 -27
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +2 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
- package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js +2 -1
- package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -106
- package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
- package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +563 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
- package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
- package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js +7 -21
- package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
- package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
- package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
- package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +21 -7
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +22 -3
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +17 -3
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +17 -3
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +6 -3
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/commonjs/components/styled/AudioMessage.js +2 -1
- package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +37 -9
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +80 -11
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledComponents.js +9 -3
- package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/commonjs/components/styled/UnsupportedType.js +14 -4
- package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +119 -61
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +184 -59
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/createMessageFromXml.js +19 -1
- package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
- package/lib/commonjs/helpers/ensureScopedChatCache.js +2 -2
- package/lib/commonjs/helpers/ensureScopedChatCache.js.map +1 -1
- package/lib/commonjs/helpers/getChatBackground.js +23 -0
- package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
- package/lib/commonjs/helpers/getDisplayFileName.js +79 -0
- package/lib/commonjs/helpers/getDisplayFileName.js.map +1 -0
- package/lib/commonjs/helpers/getServerReadTimestamp.js +188 -0
- package/lib/commonjs/helpers/getServerReadTimestamp.js.map +1 -0
- package/lib/commonjs/helpers/historyPreloadScheduler.js +65 -2
- package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/commonjs/helpers/initXmppRooms.js +14 -8
- package/lib/commonjs/helpers/initXmppRooms.js.map +1 -1
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js +51 -9
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/commonjs/helpers/isOwnMessage.js +75 -0
- package/lib/commonjs/helpers/isOwnMessage.js.map +1 -0
- package/lib/commonjs/helpers/keyboardLayout.js +12 -2
- package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
- package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
- package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
- package/lib/commonjs/helpers/mimeToExtension.js +6 -14
- package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
- package/lib/commonjs/helpers/msgSortableMs.js +37 -0
- package/lib/commonjs/helpers/msgSortableMs.js.map +1 -0
- package/lib/commonjs/helpers/persistCrypto.js +122 -0
- package/lib/commonjs/helpers/persistCrypto.js.map +1 -0
- package/lib/commonjs/helpers/pickImageAsset.js +68 -0
- package/lib/commonjs/helpers/pickImageAsset.js.map +1 -0
- package/lib/commonjs/helpers/pushPayload.js +71 -0
- package/lib/commonjs/helpers/pushPayload.js.map +1 -0
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js +130 -17
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/commonjs/helpers/secureFileUrl.js +101 -0
- package/lib/commonjs/helpers/secureFileUrl.js.map +1 -0
- package/lib/commonjs/helpers/secureKeyValue.js +83 -0
- package/lib/commonjs/helpers/secureKeyValue.js.map +1 -0
- package/lib/commonjs/helpers/secureStoreRuntime.js +59 -0
- package/lib/commonjs/helpers/secureStoreRuntime.js.map +1 -0
- package/lib/commonjs/helpers/secureUserStorage.js +75 -0
- package/lib/commonjs/helpers/secureUserStorage.js.map +1 -0
- package/lib/commonjs/helpers/shallowEqual.js +36 -0
- package/lib/commonjs/helpers/shallowEqual.js.map +1 -0
- package/lib/commonjs/helpers/sheetGestures.js +32 -0
- package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
- package/lib/commonjs/hooks/useChatRoomFocus.js +45 -12
- package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
- package/lib/commonjs/hooks/useChatWrapperInit.js +30 -10
- package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/commonjs/hooks/useComposing.js +27 -0
- package/lib/commonjs/hooks/useComposing.js.map +1 -1
- package/lib/commonjs/hooks/useFileToken.js +10 -0
- package/lib/commonjs/hooks/useFileToken.js.map +1 -0
- package/lib/commonjs/hooks/useLogout.js +23 -7
- package/lib/commonjs/hooks/useLogout.js.map +1 -1
- package/lib/commonjs/hooks/usePendingNotification.js +8 -11
- package/lib/commonjs/hooks/usePendingNotification.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +50 -14
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js +6 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/commonjs/i18n/strings.js +145 -37
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/main.js +44 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +134 -60
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/roomMembers.api.js +1 -1
- package/lib/commonjs/networking/api-requests/roomMembers.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/rooms.api.js +9 -9
- package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/user.api.js +68 -9
- package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
- package/lib/commonjs/networking/apiClient.js +62 -112
- package/lib/commonjs/networking/apiClient.js.map +1 -1
- package/lib/commonjs/networking/authRefresh.js +332 -0
- package/lib/commonjs/networking/authRefresh.js.map +1 -0
- package/lib/commonjs/networking/stanzaHandlers.js +41 -28
- package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +46 -8
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +8 -1
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
- package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +124 -8
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/chatSettingsSlice.js +26 -7
- package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/commonjs/roomStore/index.js +35 -2
- package/lib/commonjs/roomStore/index.js.map +1 -1
- package/lib/commonjs/roomStore/persistence.js +226 -23
- package/lib/commonjs/roomStore/persistence.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +151 -38
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/services/pushSubscriptionService.js +15 -13
- package/lib/commonjs/services/pushSubscriptionService.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/assets/icons.js +6 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/AuthForms/Login.js +4 -4
- package/lib/module/components/AuthForms/Login.js.map +1 -1
- package/lib/module/components/Header/HeaderRoomList.js +29 -8
- package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +9 -3
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +152 -16
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +35 -14
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/LoginWrapper.js +2 -1
- package/lib/module/components/MainComponents/LoginWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +30 -10
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MessageContainer.js +5 -1
- package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +13 -5
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +14 -13
- package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +207 -35
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/Menu/HeaderRoomListMenu.js +319 -101
- package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js +313 -113
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +549 -207
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +70 -28
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js +2 -1
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/module/components/Modals/Modal/Modal.js +9 -1
- package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/ModalContent.js +2 -1
- package/lib/module/components/Modals/NewChatModal/ModalContent.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -108
- package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
- package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +555 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
- package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
- package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/EditUserModal.js +9 -23
- package/lib/module/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
- package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
- package/lib/module/components/Modals/styledModalComponents.js +9 -2
- package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js +21 -7
- package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js +22 -3
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +17 -3
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +17 -3
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallSession.js +6 -3
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/module/components/styled/AudioMessage.js +2 -1
- package/lib/module/components/styled/AudioMessage.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +37 -9
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +81 -12
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledComponents.js +9 -3
- package/lib/module/components/styled/StyledComponents.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/module/components/styled/UnsupportedType.js +14 -4
- package/lib/module/components/styled/UnsupportedType.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +120 -62
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/xmppProvider.js +184 -60
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/createMessageFromXml.js +19 -1
- package/lib/module/helpers/createMessageFromXml.js.map +1 -1
- package/lib/module/helpers/ensureScopedChatCache.js +2 -2
- package/lib/module/helpers/ensureScopedChatCache.js.map +1 -1
- package/lib/module/helpers/getChatBackground.js +18 -0
- package/lib/module/helpers/getChatBackground.js.map +1 -0
- package/lib/module/helpers/getDisplayFileName.js +73 -0
- package/lib/module/helpers/getDisplayFileName.js.map +1 -0
- package/lib/module/helpers/getServerReadTimestamp.js +181 -0
- package/lib/module/helpers/getServerReadTimestamp.js.map +1 -0
- package/lib/module/helpers/historyPreloadScheduler.js +66 -3
- package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/module/helpers/initXmppRooms.js +14 -8
- package/lib/module/helpers/initXmppRooms.js.map +1 -1
- package/lib/module/helpers/insertMessageWithDelimiter.js +52 -9
- package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/module/helpers/isOwnMessage.js +70 -0
- package/lib/module/helpers/isOwnMessage.js.map +1 -0
- package/lib/module/helpers/keyboardLayout.js +12 -2
- package/lib/module/helpers/keyboardLayout.js.map +1 -1
- package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
- package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
- package/lib/module/helpers/mimeToExtension.js +6 -13
- package/lib/module/helpers/mimeToExtension.js.map +1 -1
- package/lib/module/helpers/msgSortableMs.js +32 -0
- package/lib/module/helpers/msgSortableMs.js.map +1 -0
- package/lib/module/helpers/persistCrypto.js +115 -0
- package/lib/module/helpers/persistCrypto.js.map +1 -0
- package/lib/module/helpers/pickImageAsset.js +63 -0
- package/lib/module/helpers/pickImageAsset.js.map +1 -0
- package/lib/module/helpers/pushPayload.js +63 -0
- package/lib/module/helpers/pushPayload.js.map +1 -0
- package/lib/module/helpers/resolveInitBeforeLoadUser.js +130 -16
- package/lib/module/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/module/helpers/secureFileUrl.js +91 -0
- package/lib/module/helpers/secureFileUrl.js.map +1 -0
- package/lib/module/helpers/secureKeyValue.js +75 -0
- package/lib/module/helpers/secureKeyValue.js.map +1 -0
- package/lib/module/helpers/secureStoreRuntime.js +52 -0
- package/lib/module/helpers/secureStoreRuntime.js.map +1 -0
- package/lib/module/helpers/secureUserStorage.js +72 -0
- package/lib/module/helpers/secureUserStorage.js.map +1 -0
- package/lib/module/helpers/shallowEqual.js +31 -0
- package/lib/module/helpers/shallowEqual.js.map +1 -0
- package/lib/module/helpers/sheetGestures.js +26 -0
- package/lib/module/helpers/sheetGestures.js.map +1 -0
- package/lib/module/hooks/useChatRoomFocus.js +46 -13
- package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
- package/lib/module/hooks/useChatWrapperInit.js +30 -10
- package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/module/hooks/useComposing.js +28 -1
- package/lib/module/hooks/useComposing.js.map +1 -1
- package/lib/module/hooks/useFileToken.js +5 -0
- package/lib/module/hooks/useFileToken.js.map +1 -0
- package/lib/module/hooks/useLogout.js +23 -7
- package/lib/module/hooks/useLogout.js.map +1 -1
- package/lib/module/hooks/usePendingNotification.js +8 -11
- package/lib/module/hooks/usePendingNotification.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +52 -16
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js +6 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/module/i18n/strings.js +145 -37
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/main.js +14 -2
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +131 -59
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/api-requests/roomMembers.api.js +1 -1
- package/lib/module/networking/api-requests/roomMembers.api.js.map +1 -1
- package/lib/module/networking/api-requests/rooms.api.js +9 -9
- package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/module/networking/api-requests/user.api.js +64 -7
- package/lib/module/networking/api-requests/user.api.js.map +1 -1
- package/lib/module/networking/apiClient.js +61 -113
- package/lib/module/networking/apiClient.js.map +1 -1
- package/lib/module/networking/authRefresh.js +321 -0
- package/lib/module/networking/authRefresh.js.map +1 -0
- package/lib/module/networking/stanzaHandlers.js +41 -28
- package/lib/module/networking/stanzaHandlers.js.map +1 -1
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +46 -8
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +8 -1
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
- package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
- package/lib/module/networking/xmppClient.js +124 -8
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/chatSettingsSlice.js +26 -7
- package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/module/roomStore/index.js +37 -4
- package/lib/module/roomStore/index.js.map +1 -1
- package/lib/module/roomStore/persistence.js +223 -22
- package/lib/module/roomStore/persistence.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +139 -34
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/services/pushSubscriptionService.js +15 -13
- package/lib/module/services/pushSubscriptionService.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/assets/icons.d.ts +16 -0
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/AuthForms/Login.d.ts.map +1 -1
- package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/LoginWrapper.d.ts.map +1 -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/MessageList.d.ts +10 -1
- package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomList.d.ts +7 -0
- package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +3 -0
- package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts +4 -2
- package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
- package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/UpdNewChatModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
- package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
- package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/EditUserModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
- package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
- package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts +14 -0
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts +8 -0
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
- package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
- package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
- package/lib/typescript/helpers/getDisplayFileName.d.ts +49 -0
- package/lib/typescript/helpers/getDisplayFileName.d.ts.map +1 -0
- package/lib/typescript/helpers/getServerReadTimestamp.d.ts +108 -0
- package/lib/typescript/helpers/getServerReadTimestamp.d.ts.map +1 -0
- package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
- package/lib/typescript/helpers/initXmppRooms.d.ts.map +1 -1
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts +1 -1
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
- package/lib/typescript/helpers/isOwnMessage.d.ts +36 -0
- package/lib/typescript/helpers/isOwnMessage.d.ts.map +1 -0
- package/lib/typescript/helpers/keyboardLayout.d.ts +5 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
- package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
- package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts +0 -15
- package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
- package/lib/typescript/helpers/msgSortableMs.d.ts +2 -0
- package/lib/typescript/helpers/msgSortableMs.d.ts.map +1 -0
- package/lib/typescript/helpers/persistCrypto.d.ts +13 -0
- package/lib/typescript/helpers/persistCrypto.d.ts.map +1 -0
- package/lib/typescript/helpers/pickImageAsset.d.ts +27 -0
- package/lib/typescript/helpers/pickImageAsset.d.ts.map +1 -0
- package/lib/typescript/helpers/pushPayload.d.ts +7 -0
- package/lib/typescript/helpers/pushPayload.d.ts.map +1 -0
- package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts.map +1 -1
- package/lib/typescript/helpers/secureFileUrl.d.ts +7 -0
- package/lib/typescript/helpers/secureFileUrl.d.ts.map +1 -0
- package/lib/typescript/helpers/secureKeyValue.d.ts +13 -0
- package/lib/typescript/helpers/secureKeyValue.d.ts.map +1 -0
- package/lib/typescript/helpers/secureStoreRuntime.d.ts +29 -0
- package/lib/typescript/helpers/secureStoreRuntime.d.ts.map +1 -0
- package/lib/typescript/helpers/secureUserStorage.d.ts +23 -0
- package/lib/typescript/helpers/secureUserStorage.d.ts.map +1 -0
- package/lib/typescript/helpers/shallowEqual.d.ts +11 -0
- package/lib/typescript/helpers/shallowEqual.d.ts.map +1 -0
- package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
- package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatRoomFocus.d.ts +4 -1
- package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
- package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
- package/lib/typescript/hooks/useComposing.d.ts.map +1 -1
- package/lib/typescript/hooks/useFileToken.d.ts +2 -0
- package/lib/typescript/hooks/useFileToken.d.ts.map +1 -0
- package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
- package/lib/typescript/hooks/usePendingNotification.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
- package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +9 -2
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
- package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
- package/lib/typescript/networking/apiClient.d.ts +12 -6
- package/lib/typescript/networking/apiClient.d.ts.map +1 -1
- package/lib/typescript/networking/authRefresh.d.ts +95 -0
- package/lib/typescript/networking/authRefresh.d.ts.map +1 -0
- package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +10 -2
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/subscribeToRoomMessages.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +14 -0
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts +16 -0
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/index.d.ts.map +1 -1
- package/lib/typescript/roomStore/persistence.d.ts +18 -1
- package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +43 -3
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/services/pushSubscriptionService.d.ts +1 -1
- package/lib/typescript/services/pushSubscriptionService.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +50 -5
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +41 -28
- package/src/assets/icons.tsx +48 -9
- package/src/components/AuthForms/Login.tsx +3 -3
- package/src/components/Header/HeaderRoomList.tsx +29 -7
- package/src/components/MainComponents/ChatHeader.tsx +9 -3
- package/src/components/MainComponents/ChatRoom.tsx +161 -15
- package/src/components/MainComponents/ChatWrapper.tsx +36 -20
- package/src/components/MainComponents/LoginWrapper.tsx +1 -0
- package/src/components/MainComponents/MediaMessage.tsx +26 -8
- package/src/components/MainComponents/MessageContainer.tsx +5 -1
- package/src/components/MainComponents/MessageList.tsx +23 -4
- package/src/components/MainComponents/ProfileImagePlaceholder.tsx +21 -14
- package/src/components/MainComponents/RoomList.tsx +236 -39
- package/src/components/Menu/HeaderRoomListMenu.tsx +328 -75
- package/src/components/Modals/AttachSheet/AttachSheet.tsx +333 -97
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +600 -282
- package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +79 -38
- package/src/components/Modals/FilePreviewModal/PdfView.tsx +2 -1
- package/src/components/Modals/Modal/Modal.tsx +7 -0
- package/src/components/Modals/NewChatModal/ModalContent.tsx +6 -3
- package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -119
- package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +12 -1
- package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +624 -0
- package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
- package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
- package/src/components/Modals/UserProfileModal/EditUserModal.tsx +9 -25
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
- package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
- package/src/components/Modals/styledModalComponents.tsx +9 -2
- package/src/components/RoomComponents/ChatRoomItem.tsx +18 -3
- package/src/components/RoomComponents/styled/LastMessageFile.tsx +28 -4
- package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +18 -3
- package/src/components/RoomComponents/styled/LastMessageVideo.tsx +18 -3
- package/src/components/VideoCalls/VideoCallSession.tsx +8 -3
- package/src/components/styled/AudioMessage.tsx +2 -1
- package/src/components/styled/MessageImage.tsx +53 -7
- package/src/components/styled/SendInput.tsx +83 -12
- package/src/components/styled/StyledComponents.ts +9 -3
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
- package/src/components/styled/UnsupportedType.tsx +14 -4
- package/src/components/styled/VideoMessage.tsx +131 -54
- package/src/context/xmppProvider.tsx +216 -57
- package/src/helpers/createMessageFromXml.ts +20 -1
- package/src/helpers/ensureScopedChatCache.ts +2 -2
- package/src/helpers/getChatBackground.ts +18 -0
- package/src/helpers/getDisplayFileName.ts +87 -0
- package/src/helpers/getServerReadTimestamp.ts +197 -0
- package/src/helpers/historyPreloadScheduler.ts +80 -3
- package/src/helpers/initXmppRooms.tsx +14 -10
- package/src/helpers/insertMessageWithDelimiter.ts +55 -19
- package/src/helpers/isOwnMessage.ts +90 -0
- package/src/helpers/keyboardLayout.ts +23 -2
- package/src/helpers/mediaLibraryRuntime.ts +25 -0
- package/src/helpers/mimeToExtension.ts +6 -22
- package/src/helpers/msgSortableMs.ts +25 -0
- package/src/helpers/persistCrypto.ts +127 -0
- package/src/helpers/pickImageAsset.ts +68 -0
- package/src/helpers/pushPayload.ts +62 -0
- package/src/helpers/resolveInitBeforeLoadUser.ts +125 -18
- package/src/helpers/secureFileUrl.ts +103 -0
- package/src/helpers/secureKeyValue.ts +80 -0
- package/src/helpers/secureStoreRuntime.ts +62 -0
- package/src/helpers/secureUserStorage.ts +80 -0
- package/src/helpers/shallowEqual.ts +33 -0
- package/src/helpers/sheetGestures.ts +25 -0
- package/src/hooks/useChatRoomFocus.ts +49 -9
- package/src/hooks/useChatWrapperInit.ts +30 -10
- package/src/hooks/useComposing.tsx +37 -1
- package/src/hooks/useFileToken.ts +7 -0
- package/src/hooks/useLogout.tsx +29 -9
- package/src/hooks/usePendingNotification.ts +5 -11
- package/src/hooks/useSendMessage.tsx +60 -15
- package/src/hooks/useUnreadMessagesCounter.ts +11 -0
- package/src/i18n/strings.ts +145 -37
- package/src/main.ts +26 -2
- package/src/networking/api-requests/auth.api.ts +156 -48
- package/src/networking/api-requests/roomMembers.api.ts +1 -1
- package/src/networking/api-requests/rooms.api.ts +9 -9
- package/src/networking/api-requests/user.api.ts +79 -7
- package/src/networking/apiClient.ts +68 -123
- package/src/networking/authRefresh.ts +451 -0
- package/src/networking/stanzaHandlers.ts +44 -28
- package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +71 -10
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +6 -1
- package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +12 -1
- package/src/networking/xmppClient.ts +141 -9
- package/src/roomStore/chatSettingsSlice.ts +34 -10
- package/src/roomStore/index.ts +40 -4
- package/src/roomStore/persistence.ts +234 -24
- package/src/roomStore/roomsSlice.ts +161 -29
- package/src/services/pushSubscriptionService.ts +18 -13
- package/src/types/types.ts +72 -5
- package/src/version.ts +1 -1
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { store } from '../roomStore';
|
|
3
3
|
|
|
4
|
-
import { logout
|
|
4
|
+
import { logout } from '../roomStore/chatSettingsSlice';
|
|
5
5
|
import { installAxiosCapture } from '../utils/devLogger';
|
|
6
|
+
import {
|
|
7
|
+
refreshAuthTokens,
|
|
8
|
+
isRefreshFatalError,
|
|
9
|
+
RefreshResult,
|
|
10
|
+
} from './authRefresh';
|
|
6
11
|
|
|
7
12
|
// Per product-code-policy: no compiled-in Ethora endpoints or tokens.
|
|
8
13
|
// Consumers must call `setBaseURL(baseUrl, appToken)` (or pass
|
|
@@ -21,10 +26,21 @@ const http = axios.create({
|
|
|
21
26
|
// `http` instance.
|
|
22
27
|
installAxiosCapture(http);
|
|
23
28
|
|
|
29
|
+
const stripApiVersion = (baseUrl: string): string =>
|
|
30
|
+
baseUrl.replace(/\/+$/, '').replace(/\/v\d+$/, '');
|
|
31
|
+
|
|
32
|
+
export const normalizeApiPath = (path?: string): string | undefined => {
|
|
33
|
+
if (!path) {return path;}
|
|
34
|
+
if (/^https?:\/\//i.test(path)) {return path;}
|
|
35
|
+
if (/^\/v\d+\//.test(path)) {return path;}
|
|
36
|
+
return `/v1${path.startsWith('/') ? '' : '/'}${path}`;
|
|
37
|
+
};
|
|
38
|
+
|
|
24
39
|
export function setBaseURL(baseUrl?: string, appToken?: string) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
const normalized = baseUrl ? stripApiVersion(baseUrl) : baseUrl;
|
|
41
|
+
if (normalized && normalized !== currentBaseURL) {
|
|
42
|
+
currentBaseURL = normalized;
|
|
43
|
+
http.defaults.baseURL = normalized;
|
|
28
44
|
}
|
|
29
45
|
if (appToken && appToken !== currentAppToken) {
|
|
30
46
|
currentAppToken = appToken;
|
|
@@ -39,149 +55,78 @@ export function getCurrentBaseURL() {
|
|
|
39
55
|
return currentBaseURL;
|
|
40
56
|
}
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)
|
|
54
|
-
.then((response) => {
|
|
55
|
-
store.dispatch(
|
|
56
|
-
refreshTokens({
|
|
57
|
-
token: response.data.token,
|
|
58
|
-
refreshToken: response.data.refreshToken,
|
|
59
|
-
})
|
|
60
|
-
);
|
|
61
|
-
// BUGFIX: previously the `.then` only dispatched and never
|
|
62
|
-
// resolved, so every `await refresh()` callsite hung forever
|
|
63
|
-
// on the happy path. Resolve with the axios response shape so
|
|
64
|
-
// the interceptor can read `tokens.data.token` to retry.
|
|
65
|
-
resolve(response);
|
|
66
|
-
})
|
|
67
|
-
.catch((error) => {
|
|
68
|
-
reject(error);
|
|
69
|
-
});
|
|
70
|
-
} catch (error) {
|
|
71
|
-
// BUGFIX: previously the outer-try catch dispatched logout but
|
|
72
|
-
// never rejected, so a synchronous throw from `http.post` (e.g.
|
|
73
|
-
// a bad URL) would hang the promise. Reject explicitly.
|
|
74
|
-
console.log('errr');
|
|
75
|
-
store.dispatch(logout());
|
|
76
|
-
reject(error);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
58
|
+
/**
|
|
59
|
+
* @deprecated Import `refreshAuthTokens` from `./authRefresh` instead.
|
|
60
|
+
*
|
|
61
|
+
* Kept as a thin forwarder so existing call sites keep working while
|
|
62
|
+
* they migrate. Declared as a function (not `const refresh =
|
|
63
|
+
* refreshAuthTokens`) on purpose: this module and `authRefresh` import
|
|
64
|
+
* each other, and a const would capture the binding before the other
|
|
65
|
+
* module finished evaluating.
|
|
66
|
+
*/
|
|
67
|
+
export function refresh(): Promise<RefreshResult> {
|
|
68
|
+
return refreshAuthTokens();
|
|
79
69
|
}
|
|
80
70
|
|
|
81
|
-
let isRefreshing = false;
|
|
82
|
-
let failedQueue: any[] = [];
|
|
83
|
-
|
|
84
|
-
const addRequestToQueue = (config: any) => {
|
|
85
|
-
return new Promise((resolve, reject) => {
|
|
86
|
-
failedQueue.push({ resolve, reject, config });
|
|
87
|
-
});
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const processQueue = (newAccessToken: string) => {
|
|
91
|
-
for (const request of failedQueue) {
|
|
92
|
-
if (newAccessToken) {
|
|
93
|
-
request.config.headers.Authorization = newAccessToken;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
request.resolve(http(request.config));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
failedQueue = [];
|
|
100
|
-
};
|
|
101
|
-
|
|
102
71
|
http.interceptors.response.use(
|
|
103
72
|
(response) => response,
|
|
104
73
|
async (error) => {
|
|
105
|
-
// BUGFIX: the original condition was `if (!enabled)` — inverted, so
|
|
106
|
-
// turning `refreshTokens.enabled: true` actually DISABLED the refresh
|
|
107
|
-
// path on 401. Use the correct sense.
|
|
108
|
-
if (!store.getState().chatSettingStore?.config?.refreshTokens?.enabled) {
|
|
109
|
-
// BUGFIX: previously this branch fell off the end of the async
|
|
110
|
-
// function and returned `undefined`, which axios treats as a
|
|
111
|
-
// resolved-with-undefined response. Callers expecting an error
|
|
112
|
-
// got `undefined` instead, silently swallowing every failure
|
|
113
|
-
// when the refresh path isn't configured. Re-reject so the
|
|
114
|
-
// original error reaches the caller.
|
|
115
|
-
return Promise.reject(error);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
74
|
const originalRequest = error.config;
|
|
119
75
|
const status = error.response?.status;
|
|
120
76
|
|
|
121
77
|
// Refresh paths only fire on 401. Anything else passes through.
|
|
122
|
-
if (!error.response || status !== 401) {
|
|
78
|
+
if (!error.response || status !== 401 || !originalRequest) {
|
|
123
79
|
return Promise.reject(error);
|
|
124
80
|
}
|
|
125
81
|
|
|
82
|
+
// Never retry twice, and never touch the auth endpoints themselves —
|
|
83
|
+
// both would recurse. (`_retry` was set but never checked before,
|
|
84
|
+
// so a request could bounce between 401 and replay indefinitely.)
|
|
126
85
|
if (
|
|
127
|
-
|
|
86
|
+
originalRequest._retry ||
|
|
87
|
+
originalRequest.url === '/v1/users/login/refresh' ||
|
|
88
|
+
originalRequest.url === '/v1/users/login'
|
|
128
89
|
) {
|
|
129
|
-
|
|
130
|
-
// tokens, retry the original request.
|
|
131
|
-
try {
|
|
132
|
-
const fn = store.getState().chatSettingStore?.config?.refreshTokens?.refreshFunction;
|
|
133
|
-
if (!fn) return Promise.reject(error);
|
|
134
|
-
const result = await fn();
|
|
135
|
-
const { refreshToken: newRefreshToken, accessToken } = result || { refreshToken: '', accessToken: '' };
|
|
136
|
-
store.dispatch(
|
|
137
|
-
refreshTokens({
|
|
138
|
-
token: accessToken,
|
|
139
|
-
refreshToken: newRefreshToken || '',
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
|
-
// BUGFIX: previously this branch returned `undefined` after
|
|
143
|
-
// dispatching, so the original request was never retried and
|
|
144
|
-
// the caller resolved with undefined. Stamp the new token on
|
|
145
|
-
// the original config and replay.
|
|
146
|
-
if (originalRequest?.headers) {
|
|
147
|
-
originalRequest.headers.Authorization = accessToken;
|
|
148
|
-
}
|
|
149
|
-
return http(originalRequest);
|
|
150
|
-
} catch (refreshErr) {
|
|
151
|
-
return Promise.reject(refreshErr);
|
|
152
|
-
}
|
|
90
|
+
return Promise.reject(error);
|
|
153
91
|
}
|
|
154
92
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
) {
|
|
93
|
+
const refreshConfig =
|
|
94
|
+
store.getState().chatSettingStore?.config?.refreshTokens;
|
|
95
|
+
|
|
96
|
+
// BUGFIX (kept): the original condition here was inverted, so
|
|
97
|
+
// `refreshTokens.enabled: true` actually DISABLED the refresh path.
|
|
98
|
+
if (!refreshConfig?.enabled) {
|
|
161
99
|
return Promise.reject(error);
|
|
162
100
|
}
|
|
163
101
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
102
|
+
// Nothing to rotate with — reject rather than firing a doomed
|
|
103
|
+
// refresh that would look like a bad-token event to the backend.
|
|
104
|
+
const hasRefreshableSession = Boolean(
|
|
105
|
+
refreshConfig.refreshFunction ||
|
|
106
|
+
store.getState().chatSettingStore.user?.refreshToken
|
|
107
|
+
);
|
|
108
|
+
if (!hasRefreshableSession) {
|
|
109
|
+
return Promise.reject(error);
|
|
169
110
|
}
|
|
170
111
|
|
|
171
|
-
|
|
112
|
+
originalRequest._retry = true;
|
|
113
|
+
|
|
172
114
|
try {
|
|
173
|
-
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
originalRequest.headers
|
|
178
|
-
|
|
115
|
+
// One shared rotation for every 401 in flight — `refreshAuthTokens`
|
|
116
|
+
// dedupes internally, which replaces the old isRefreshing/
|
|
117
|
+
// failedQueue machinery entirely.
|
|
118
|
+
const tokens = await refreshAuthTokens();
|
|
119
|
+
originalRequest.headers = originalRequest.headers || {};
|
|
120
|
+
originalRequest.headers.Authorization = tokens.token;
|
|
179
121
|
return http(originalRequest);
|
|
180
122
|
} catch (refreshErr) {
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
123
|
+
// Only a genuinely dead session logs the user out. A network
|
|
124
|
+
// blip, a 5xx, or a REFRESH_IN_PROGRESS race must leave the
|
|
125
|
+
// session alone — logging out on those is exactly the mass-logout
|
|
126
|
+
// failure mode the new backend scheme would otherwise cause.
|
|
127
|
+
if (isRefreshFatalError(refreshErr)) {
|
|
128
|
+
store.dispatch(logout());
|
|
129
|
+
}
|
|
185
130
|
return Promise.reject(refreshErr);
|
|
186
131
|
}
|
|
187
132
|
}
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import http from './apiClient';
|
|
2
|
+
import { store } from '../roomStore';
|
|
3
|
+
import { refreshTokens } from '../roomStore/chatSettingsSlice';
|
|
4
|
+
import { secureUserStorage } from '../helpers/secureUserStorage';
|
|
5
|
+
import { pushLog } from '../utils/devLogger';
|
|
6
|
+
import { User } from '../types/types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* THE single refresh-token rotation point for the SDK.
|
|
10
|
+
*
|
|
11
|
+
* The backend now runs refresh-token ROTATION with REUSE DETECTION:
|
|
12
|
+
* every successful `/users/login/refresh` burns the presented refresh
|
|
13
|
+
* token and issues a new one. Presenting an already-rotated token is
|
|
14
|
+
* indistinguishable, server-side, from a stolen token — so it is
|
|
15
|
+
* treated as theft and (once the backend leaves monitor mode and
|
|
16
|
+
* enables enforcing mode) kills the whole token family.
|
|
17
|
+
*
|
|
18
|
+
* That puts three hard obligations on the client:
|
|
19
|
+
*
|
|
20
|
+
* 1. Persist the NEW refreshToken from every response, immediately,
|
|
21
|
+
* before any other logic can throw and drop it on the floor.
|
|
22
|
+
* 2. Never rotate concurrently. Two parallel refreshes both start
|
|
23
|
+
* from the same token; the loser presents a burned one and looks
|
|
24
|
+
* like an attacker. React Native is single-process, so a shared
|
|
25
|
+
* in-flight promise is the whole lock — no Web Locks needed (the
|
|
26
|
+
* web build of this component does need them, see its own
|
|
27
|
+
* `authRefresh.ts`).
|
|
28
|
+
* 3. Route EVERY refresh path through here. One "side" refresh
|
|
29
|
+
* elsewhere in the codebase breaks the scheme for everyone.
|
|
30
|
+
*
|
|
31
|
+
* Callers must also stop treating 401 as "log out". Two of the four
|
|
32
|
+
* refresh error codes are race signals, not auth failures — see
|
|
33
|
+
* `RefreshErrorCode` below and `RefreshFatalError`.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export type RefreshErrorCode =
|
|
37
|
+
| 'REFRESH_IN_PROGRESS'
|
|
38
|
+
| 'REFRESH_TOKEN_ALREADY_ROTATED'
|
|
39
|
+
| 'REFRESH_TOKEN_REUSE_DETECTED'
|
|
40
|
+
| 'REFRESH_TOKEN_NOT_FOUND';
|
|
41
|
+
|
|
42
|
+
export interface RefreshResult {
|
|
43
|
+
token: string;
|
|
44
|
+
refreshToken: string;
|
|
45
|
+
/**
|
|
46
|
+
* Present in the backend response but not currently consumed
|
|
47
|
+
* anywhere in the SDK. Passed through so callers can use it without
|
|
48
|
+
* a second round trip.
|
|
49
|
+
* TODO(phase-7): decide whether to persist this on `User`.
|
|
50
|
+
*/
|
|
51
|
+
wsToken?: string;
|
|
52
|
+
xmppPassword?: string;
|
|
53
|
+
fileToken?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Thrown when the session is genuinely dead and the caller must do a
|
|
58
|
+
* hard logout (clear storage, drop XMPP, send the user to login).
|
|
59
|
+
*
|
|
60
|
+
* Anything else this module rejects with — network errors, 5xx, an
|
|
61
|
+
* unrecognised 401 — is NOT fatal and must NOT trigger a logout.
|
|
62
|
+
*/
|
|
63
|
+
export class RefreshFatalError extends Error {
|
|
64
|
+
code: RefreshErrorCode;
|
|
65
|
+
|
|
66
|
+
constructor(code: RefreshErrorCode, message?: string) {
|
|
67
|
+
super(message || `Refresh failed: ${code}`);
|
|
68
|
+
this.name = 'RefreshFatalError';
|
|
69
|
+
this.code = code;
|
|
70
|
+
// Required for `instanceof` to survive TS's ES5 class-extends-builtin
|
|
71
|
+
// downlevelling, which RN's babel preset still applies.
|
|
72
|
+
Object.setPrototypeOf(this, RefreshFatalError.prototype);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const isRefreshFatalError = (
|
|
77
|
+
error: unknown
|
|
78
|
+
): error is RefreshFatalError =>
|
|
79
|
+
error instanceof RefreshFatalError ||
|
|
80
|
+
(error as RefreshFatalError)?.name === 'RefreshFatalError';
|
|
81
|
+
|
|
82
|
+
const REFRESH_ENDPOINT = '/v1/users/login/refresh';
|
|
83
|
+
|
|
84
|
+
/** `REFRESH_IN_PROGRESS` retry budget, per backend guidance (~300ms x 2-3). */
|
|
85
|
+
const IN_PROGRESS_MAX_ATTEMPTS = 3;
|
|
86
|
+
const IN_PROGRESS_BASE_DELAY_MS = 300;
|
|
87
|
+
/**
|
|
88
|
+
* Jitter matters: after a network blip every client in the app retries
|
|
89
|
+
* on the same schedule and would hammer the rotation mutex in lockstep.
|
|
90
|
+
*/
|
|
91
|
+
const IN_PROGRESS_JITTER_MS = 150;
|
|
92
|
+
|
|
93
|
+
const KNOWN_CODES: RefreshErrorCode[] = [
|
|
94
|
+
'REFRESH_IN_PROGRESS',
|
|
95
|
+
'REFRESH_TOKEN_ALREADY_ROTATED',
|
|
96
|
+
'REFRESH_TOKEN_REUSE_DETECTED',
|
|
97
|
+
'REFRESH_TOKEN_NOT_FOUND',
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const sleep = (ms: number) =>
|
|
101
|
+
new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
102
|
+
|
|
103
|
+
const inProgressDelay = (attempt: number) =>
|
|
104
|
+
IN_PROGRESS_BASE_DELAY_MS * attempt +
|
|
105
|
+
Math.floor(Math.random() * IN_PROGRESS_JITTER_MS);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* All four codes come back as HTTP 401, so the status alone tells us
|
|
109
|
+
* nothing — the code in the body is the only signal.
|
|
110
|
+
*
|
|
111
|
+
* TODO(backend-confirm): the exact location of `code` in the payload is
|
|
112
|
+
* not documented yet. Until it is, probe every shape the API uses
|
|
113
|
+
* elsewhere and take the first hit. Once confirmed, collapse this to
|
|
114
|
+
* the single real path.
|
|
115
|
+
*/
|
|
116
|
+
export const parseRefreshErrorCode = (
|
|
117
|
+
error: unknown
|
|
118
|
+
): RefreshErrorCode | null => {
|
|
119
|
+
const response = (error as any)?.response;
|
|
120
|
+
if (!response) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const data = response.data;
|
|
125
|
+
const candidates = [
|
|
126
|
+
data?.code,
|
|
127
|
+
data?.error?.code,
|
|
128
|
+
data?.errors?.[0]?.code,
|
|
129
|
+
data?.error,
|
|
130
|
+
data?.message,
|
|
131
|
+
response.headers?.['x-error-code'],
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
for (const candidate of candidates) {
|
|
135
|
+
if (typeof candidate !== 'string') {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const match = KNOWN_CODES.find((code) => candidate.includes(code));
|
|
139
|
+
if (match) {
|
|
140
|
+
return match;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const getStoreUser = (): Partial<User> =>
|
|
148
|
+
(store.getState().chatSettingStore?.user as Partial<User>) || {};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The refresh token as of RIGHT NOW. Read at the moment of use, never
|
|
152
|
+
* captured ahead of time — that is the single-process equivalent of the
|
|
153
|
+
* web build's "re-read inside the lock".
|
|
154
|
+
*
|
|
155
|
+
* Redux is the source of truth in RN (one process, one store);
|
|
156
|
+
* AsyncStorage is only consulted as a cold-start fallback, before
|
|
157
|
+
* `resolveInitBeforeLoadUser` has hydrated the store.
|
|
158
|
+
*/
|
|
159
|
+
const readCurrentRefreshToken = async (): Promise<string> => {
|
|
160
|
+
const fromStore = getStoreUser().refreshToken;
|
|
161
|
+
if (fromStore) {
|
|
162
|
+
return fromStore;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const stored = await secureUserStorage().get();
|
|
166
|
+
return stored?.refreshToken || '';
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Persist BEFORE resolving. The dispatch updates redux (and, until
|
|
171
|
+
* phase 6 lands, fires its own best-effort AsyncStorage write); the
|
|
172
|
+
* awaited write below is the one that actually guarantees the rotated
|
|
173
|
+
* token survives the app being killed a moment later. Losing it means
|
|
174
|
+
* the next launch presents a burned token — i.e. looks like theft.
|
|
175
|
+
*/
|
|
176
|
+
const persistTokens = async (result: RefreshResult): Promise<void> => {
|
|
177
|
+
store.dispatch(
|
|
178
|
+
refreshTokens({
|
|
179
|
+
token: result.token,
|
|
180
|
+
refreshToken: result.refreshToken,
|
|
181
|
+
xmppPassword: result.xmppPassword,
|
|
182
|
+
fileToken: result.fileToken,
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
// Write the post-dispatch snapshot rather than a read-modify-write
|
|
188
|
+
// merge, so this can't race the reducer's own write back to a
|
|
189
|
+
// stale copy of the surrounding user fields.
|
|
190
|
+
await secureUserStorage().set(
|
|
191
|
+
store.getState().chatSettingStore.user as User
|
|
192
|
+
);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
pushLog('warn', 'authRefresh: failed to persist rotated tokens', error);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* A rotation that happened somewhere we didn't drive — currently only
|
|
200
|
+
* reachable via the ALREADY_ROTATED recovery path, kept separate so the
|
|
201
|
+
* web build and this one stay structurally identical.
|
|
202
|
+
*/
|
|
203
|
+
const adoptStoredTokens = async (): Promise<RefreshResult | null> => {
|
|
204
|
+
const stored = await secureUserStorage().get();
|
|
205
|
+
if (!stored?.refreshToken || !stored?.token) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const user = getStoreUser();
|
|
210
|
+
if (user.refreshToken !== stored.refreshToken) {
|
|
211
|
+
store.dispatch(
|
|
212
|
+
refreshTokens({
|
|
213
|
+
token: stored.token,
|
|
214
|
+
refreshToken: stored.refreshToken,
|
|
215
|
+
})
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
token: stored.token,
|
|
221
|
+
refreshToken: stored.refreshToken,
|
|
222
|
+
xmppPassword: stored.xmppPassword,
|
|
223
|
+
fileToken: stored.fileToken,
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/** Host-supplied rotation, mirrors `IConfig['refreshTokens']['refreshFunction']`. */
|
|
228
|
+
type ConsumerRefreshFn = () => Promise<{
|
|
229
|
+
accessToken: string;
|
|
230
|
+
refreshToken?: string;
|
|
231
|
+
xmppPassword?: string;
|
|
232
|
+
fileToken?: string;
|
|
233
|
+
} | null>;
|
|
234
|
+
|
|
235
|
+
const runConsumerRefresh = async (
|
|
236
|
+
refreshFunction: ConsumerRefreshFn
|
|
237
|
+
): Promise<RefreshResult> => {
|
|
238
|
+
const refreshed = await refreshFunction();
|
|
239
|
+
|
|
240
|
+
if (!refreshed?.accessToken) {
|
|
241
|
+
throw new Error('Custom refresh function did not return an access token');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!refreshed.refreshToken) {
|
|
245
|
+
// Not fatal — some hosts still run non-rotating backends — but on a
|
|
246
|
+
// rotating one this silently keeps a burned token around, which is
|
|
247
|
+
// exactly the failure the new scheme punishes.
|
|
248
|
+
pushLog(
|
|
249
|
+
'warn',
|
|
250
|
+
'authRefresh: custom refreshFunction returned no refreshToken; ' +
|
|
251
|
+
'keeping the existing one. On a rotating backend this will be ' +
|
|
252
|
+
'seen as token reuse.'
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const result: RefreshResult = {
|
|
257
|
+
token: refreshed.accessToken,
|
|
258
|
+
refreshToken:
|
|
259
|
+
refreshed.refreshToken || (await readCurrentRefreshToken()) || '',
|
|
260
|
+
xmppPassword: refreshed.xmppPassword,
|
|
261
|
+
fileToken: refreshed.fileToken,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
await persistTokens(result);
|
|
265
|
+
return result;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const requestRotation = async (
|
|
269
|
+
refreshToken: string
|
|
270
|
+
): Promise<RefreshResult> => {
|
|
271
|
+
const response = await http.post(
|
|
272
|
+
REFRESH_ENDPOINT,
|
|
273
|
+
{},
|
|
274
|
+
{ headers: { Authorization: refreshToken } }
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const result: RefreshResult = {
|
|
278
|
+
token: response?.data?.token || '',
|
|
279
|
+
refreshToken: response?.data?.refreshToken || '',
|
|
280
|
+
wsToken: response?.data?.wsToken,
|
|
281
|
+
xmppPassword: response?.data?.xmppPassword,
|
|
282
|
+
fileToken: response?.data?.fileToken,
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
if (!result.token || !result.refreshToken) {
|
|
286
|
+
throw new Error('Refresh response did not contain both tokens');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Persist first, resolve second. Every early return between here and
|
|
290
|
+
// the caller is a chance to lose the rotation.
|
|
291
|
+
await persistTokens(result);
|
|
292
|
+
return result;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const performRefresh = async (
|
|
296
|
+
overrideToken?: string
|
|
297
|
+
): Promise<RefreshResult> => {
|
|
298
|
+
const consumerRefresh =
|
|
299
|
+
store.getState().chatSettingStore?.config?.refreshTokens?.refreshFunction;
|
|
300
|
+
|
|
301
|
+
if (consumerRefresh) {
|
|
302
|
+
// A configured host function wins unconditionally — including over
|
|
303
|
+
// an explicit bootstrap token. Hosts that embed this SDK often own
|
|
304
|
+
// the Ethora refresh token themselves (their own storage, their own
|
|
305
|
+
// rotation) and only hand us a copy; rotating it here would burn
|
|
306
|
+
// THEIR token behind their back and leave them holding a dead one.
|
|
307
|
+
//
|
|
308
|
+
// It still has to be serialised — it hits the same backend mutex —
|
|
309
|
+
// hence running it inside the shared in-flight promise.
|
|
310
|
+
return runConsumerRefresh(consumerRefresh);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (let attempt = 1; attempt <= IN_PROGRESS_MAX_ATTEMPTS; attempt++) {
|
|
314
|
+
const refreshToken = overrideToken || (await readCurrentRefreshToken());
|
|
315
|
+
|
|
316
|
+
if (!refreshToken) {
|
|
317
|
+
// Deliberately NOT fatal: a missing token mid-bootstrap must not
|
|
318
|
+
// nuke a session that is still being hydrated.
|
|
319
|
+
throw new Error('Refresh token is missing');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
return await requestRotation(refreshToken);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
const code = parseRefreshErrorCode(error);
|
|
326
|
+
|
|
327
|
+
if (code === 'REFRESH_IN_PROGRESS') {
|
|
328
|
+
if (attempt < IN_PROGRESS_MAX_ATTEMPTS) {
|
|
329
|
+
await sleep(inProgressDelay(attempt));
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
// Budget spent. Whoever holds the mutex has very likely
|
|
333
|
+
// finished and written a newer token — take it if so. Skipped
|
|
334
|
+
// for an explicit token: it may belong to a different session
|
|
335
|
+
// than whatever is currently in storage.
|
|
336
|
+
const adopted = overrideToken ? null : await adoptStoredTokens();
|
|
337
|
+
if (adopted && adopted.refreshToken !== refreshToken) {
|
|
338
|
+
return adopted;
|
|
339
|
+
}
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (code === 'REFRESH_TOKEN_ALREADY_ROTATED') {
|
|
344
|
+
// Our copy is stale. If something already wrote a newer token,
|
|
345
|
+
// this is a benign race — use it. Otherwise the session really
|
|
346
|
+
// is unrecoverable.
|
|
347
|
+
const adopted = overrideToken ? null : await adoptStoredTokens();
|
|
348
|
+
if (adopted && adopted.refreshToken !== refreshToken) {
|
|
349
|
+
return adopted;
|
|
350
|
+
}
|
|
351
|
+
throw new RefreshFatalError(code);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (
|
|
355
|
+
code === 'REFRESH_TOKEN_REUSE_DETECTED' ||
|
|
356
|
+
code === 'REFRESH_TOKEN_NOT_FOUND'
|
|
357
|
+
) {
|
|
358
|
+
throw new RefreshFatalError(code);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Network error, 5xx, plain 401 without a code — pass through
|
|
362
|
+
// untouched. The caller must not log out on these.
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Unreachable: the loop either returns or throws.
|
|
368
|
+
throw new Error('Refresh attempts exhausted');
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export interface RefreshOptions {
|
|
372
|
+
/**
|
|
373
|
+
* Rotate THIS token instead of the one in the store/storage.
|
|
374
|
+
*
|
|
375
|
+
* Only for bootstrap, where the session being restored isn't in the
|
|
376
|
+
* store yet (a host-supplied `userLogin.user`, a persisted record).
|
|
377
|
+
* Everywhere else, omitting it is the correct and safer choice: the
|
|
378
|
+
* module then always presents the newest token it knows about.
|
|
379
|
+
*/
|
|
380
|
+
refreshToken?: string;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let inflight: Promise<RefreshResult> | null = null;
|
|
384
|
+
|
|
385
|
+
let lastRotationAt = 0;
|
|
386
|
+
const QUIET_ROTATION_MIN_INTERVAL_MS = 5 * 60 * 1000;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Rotate the tokens. Concurrent callers share ONE request — this is the
|
|
390
|
+
* lock the new backend scheme requires.
|
|
391
|
+
*
|
|
392
|
+
* Rejects with `RefreshFatalError` when the session is dead (caller
|
|
393
|
+
* should hard-logout) and with a plain error otherwise (caller should
|
|
394
|
+
* surface the failure and leave the session alone).
|
|
395
|
+
*/
|
|
396
|
+
export function refreshAuthTokens(
|
|
397
|
+
options?: RefreshOptions
|
|
398
|
+
): Promise<RefreshResult> {
|
|
399
|
+
if (inflight) {
|
|
400
|
+
// Whatever that rotation produces is at least as fresh as anything
|
|
401
|
+
// this caller could have asked for.
|
|
402
|
+
return inflight;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
inflight = performRefresh(options?.refreshToken)
|
|
406
|
+
.then((result) => {
|
|
407
|
+
lastRotationAt = Date.now();
|
|
408
|
+
return result;
|
|
409
|
+
})
|
|
410
|
+
.finally(() => {
|
|
411
|
+
inflight = null;
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
return inflight;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Fire-and-forget variant for call sites that only want "make sure the
|
|
419
|
+
* tokens are fresh" and have no meaningful error handling — chat
|
|
420
|
+
* bootstrap, XMPP reconnect. Never rejects.
|
|
421
|
+
*/
|
|
422
|
+
export interface QuietRefreshOptions {
|
|
423
|
+
force?: boolean;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export async function refreshAuthTokensQuietly(
|
|
427
|
+
options?: QuietRefreshOptions
|
|
428
|
+
): Promise<RefreshResult | null> {
|
|
429
|
+
if (
|
|
430
|
+
!options?.force &&
|
|
431
|
+
Date.now() - lastRotationAt < QUIET_ROTATION_MIN_INTERVAL_MS
|
|
432
|
+
) {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
try {
|
|
436
|
+
return await refreshAuthTokens();
|
|
437
|
+
} catch (error) {
|
|
438
|
+
pushLog(
|
|
439
|
+
isRefreshFatalError(error) ? 'error' : 'warn',
|
|
440
|
+
'authRefresh: background refresh failed',
|
|
441
|
+
error
|
|
442
|
+
);
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** Test seam — drops any shared in-flight promise between cases. */
|
|
448
|
+
export function __resetAuthRefreshStateForTests(): void {
|
|
449
|
+
inflight = null;
|
|
450
|
+
lastRotationAt = 0;
|
|
451
|
+
}
|