@ethora/chat-component-rn 26.10.4 → 26.10.6
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 +8 -0
- package/README.md +15 -0
- package/app.plugin.js +2 -0
- package/lib/commonjs/assets/icons.js +2 -2
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/MainComponents/AlbumGrid.js +152 -0
- package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -0
- package/lib/commonjs/components/MainComponents/ChatRoom.js +2 -2
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +199 -123
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js +109 -0
- package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js.map +1 -0
- package/lib/commonjs/components/MessageBubble/MediaCaption.js +51 -0
- package/lib/commonjs/components/MessageBubble/MediaCaption.js.map +1 -0
- package/lib/commonjs/components/MessageBubble/Message.js +40 -1
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +2 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/LastMessageItem.js +20 -4
- package/lib/commonjs/components/RoomComponents/LastMessageItem.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/commonjs/components/Thread/ThreadWrapper.js +3 -2
- package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +61 -16
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/CallIcons.js +41 -16
- package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +183 -9
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +40 -15
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callSessionController.js +49 -26
- package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callUiStore.js +33 -4
- package/lib/commonjs/components/VideoCalls/callUiStore.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js +9 -1
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/useCallKeep.js +197 -28
- package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js +88 -0
- package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/usePipTile.js +232 -0
- package/lib/commonjs/components/VideoCalls/usePipTile.js.map +1 -0
- package/lib/commonjs/components/styled/MediaFilePreview.js +60 -47
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +16 -6
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +99 -68
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +24 -10
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +46 -0
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/e2ee/fileEnvelope.js +6 -0
- package/lib/commonjs/e2ee/fileEnvelope.js.map +1 -1
- package/lib/commonjs/e2ee/sealedBody.js +32 -2
- package/lib/commonjs/e2ee/sealedBody.js.map +1 -1
- package/lib/commonjs/helpers/albumLayout.js +150 -0
- package/lib/commonjs/helpers/albumLayout.js.map +1 -0
- package/lib/commonjs/helpers/attachments.js +255 -0
- package/lib/commonjs/helpers/attachments.js.map +1 -0
- package/lib/commonjs/helpers/caption.js +214 -0
- package/lib/commonjs/helpers/caption.js.map +1 -0
- package/lib/commonjs/helpers/createMainMessageForThread.js +5 -1
- package/lib/commonjs/helpers/createMainMessageForThread.js.map +1 -1
- package/lib/commonjs/helpers/createMessageFromXml.js +19 -5
- package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
- package/lib/commonjs/helpers/fileKind.js +40 -0
- package/lib/commonjs/helpers/fileKind.js.map +1 -0
- package/lib/commonjs/helpers/getDataFromXml.js +6 -1
- package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
- package/lib/commonjs/helpers/mapWithConcurrency.js +41 -0
- package/lib/commonjs/helpers/mapWithConcurrency.js.map +1 -0
- package/lib/commonjs/helpers/mediaLimits.js +33 -0
- package/lib/commonjs/helpers/mediaLimits.js.map +1 -0
- package/lib/commonjs/helpers/mediaSendRetry.js +64 -0
- package/lib/commonjs/helpers/mediaSendRetry.js.map +1 -0
- package/lib/commonjs/helpers/mediaWireData.js +62 -0
- package/lib/commonjs/helpers/mediaWireData.js.map +1 -0
- package/lib/commonjs/helpers/mentionSpans.js +19 -0
- package/lib/commonjs/helpers/mentionSpans.js.map +1 -0
- package/lib/commonjs/helpers/mimeToExtension.js +45 -0
- package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
- package/lib/commonjs/helpers/readReceipts.js +173 -0
- package/lib/commonjs/helpers/readReceipts.js.map +1 -0
- package/lib/commonjs/helpers/repairFilenameEncoding.js +79 -0
- package/lib/commonjs/helpers/repairFilenameEncoding.js.map +1 -0
- package/lib/commonjs/helpers/safeJson.js +18 -0
- package/lib/commonjs/helpers/safeJson.js.map +1 -0
- package/lib/commonjs/helpers/updateMessagesTillLast.js +3 -1
- package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +384 -193
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/i18n/strings.js +144 -0
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +62 -3
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/stanzaHandlers.js +100 -3
- package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -2
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js +28 -0
- package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
- package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
- package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js +28 -0
- package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
- package/lib/commonjs/networking/xmppClient.js +64 -0
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/persistence.js +78 -5
- package/lib/commonjs/roomStore/persistence.js.map +1 -1
- package/lib/commonjs/roomStore/roomHeapSlice.js +4 -0
- package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +114 -1
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/types/models/attachment.model.js +2 -0
- package/lib/commonjs/types/models/attachment.model.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/assets/icons.js +1 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/MainComponents/AlbumGrid.js +146 -0
- package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -0
- package/lib/module/components/MainComponents/ChatRoom.js +2 -2
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +200 -124
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MediaUploadOverlay.js +104 -0
- package/lib/module/components/MainComponents/MediaUploadOverlay.js.map +1 -0
- package/lib/module/components/MessageBubble/MediaCaption.js +46 -0
- package/lib/module/components/MessageBubble/MediaCaption.js.map +1 -0
- package/lib/module/components/MessageBubble/Message.js +44 -5
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +2 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/RoomComponents/LastMessageItem.js +20 -4
- package/lib/module/components/RoomComponents/LastMessageItem.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastAudioMessage.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/module/components/Thread/ThreadWrapper.js +3 -2
- package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
- package/lib/module/components/VideoCalls/ActiveCallBar.js +63 -18
- package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -1
- package/lib/module/components/VideoCalls/CallIcons.js +38 -15
- package/lib/module/components/VideoCalls/CallIcons.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallOverlay.js +185 -11
- package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallSession.js +41 -16
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/module/components/VideoCalls/callSessionController.js +46 -24
- package/lib/module/components/VideoCalls/callSessionController.js.map +1 -1
- package/lib/module/components/VideoCalls/callUiStore.js +30 -3
- package/lib/module/components/VideoCalls/callUiStore.js.map +1 -1
- package/lib/module/components/VideoCalls/livekitRuntime.js +9 -1
- package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -1
- package/lib/module/components/VideoCalls/useCallKeep.js +198 -29
- package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -1
- package/lib/module/components/VideoCalls/useOngoingCallNotification.js +84 -0
- package/lib/module/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
- package/lib/module/components/VideoCalls/usePipTile.js +228 -0
- package/lib/module/components/VideoCalls/usePipTile.js.map +1 -0
- package/lib/module/components/styled/MediaFilePreview.js +61 -48
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +16 -6
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +99 -68
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +24 -10
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/xmppProvider.js +46 -0
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/e2ee/fileEnvelope.js +1 -1
- package/lib/module/e2ee/fileEnvelope.js.map +1 -1
- package/lib/module/e2ee/sealedBody.js +32 -2
- package/lib/module/e2ee/sealedBody.js.map +1 -1
- package/lib/module/helpers/albumLayout.js +143 -0
- package/lib/module/helpers/albumLayout.js.map +1 -0
- package/lib/module/helpers/attachments.js +245 -0
- package/lib/module/helpers/attachments.js.map +1 -0
- package/lib/module/helpers/caption.js +207 -0
- package/lib/module/helpers/caption.js.map +1 -0
- package/lib/module/helpers/createMainMessageForThread.js +5 -1
- package/lib/module/helpers/createMainMessageForThread.js.map +1 -1
- package/lib/module/helpers/createMessageFromXml.js +20 -6
- package/lib/module/helpers/createMessageFromXml.js.map +1 -1
- package/lib/module/helpers/fileKind.js +34 -0
- package/lib/module/helpers/fileKind.js.map +1 -0
- package/lib/module/helpers/getDataFromXml.js +6 -1
- package/lib/module/helpers/getDataFromXml.js.map +1 -1
- package/lib/module/helpers/mapWithConcurrency.js +37 -0
- package/lib/module/helpers/mapWithConcurrency.js.map +1 -0
- package/lib/module/helpers/mediaLimits.js +27 -0
- package/lib/module/helpers/mediaLimits.js.map +1 -0
- package/lib/module/helpers/mediaSendRetry.js +55 -0
- package/lib/module/helpers/mediaSendRetry.js.map +1 -0
- package/lib/module/helpers/mediaWireData.js +58 -0
- package/lib/module/helpers/mediaWireData.js.map +1 -0
- package/lib/module/helpers/mentionSpans.js +14 -0
- package/lib/module/helpers/mentionSpans.js.map +1 -0
- package/lib/module/helpers/mimeToExtension.js +43 -0
- package/lib/module/helpers/mimeToExtension.js.map +1 -1
- package/lib/module/helpers/readReceipts.js +160 -0
- package/lib/module/helpers/readReceipts.js.map +1 -0
- package/lib/module/helpers/repairFilenameEncoding.js +74 -0
- package/lib/module/helpers/repairFilenameEncoding.js.map +1 -0
- package/lib/module/helpers/safeJson.js +13 -0
- package/lib/module/helpers/safeJson.js.map +1 -0
- package/lib/module/helpers/updateMessagesTillLast.js +3 -1
- package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +387 -195
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/i18n/strings.js +144 -0
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +62 -3
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/stanzaHandlers.js +97 -4
- package/lib/module/networking/stanzaHandlers.js.map +1 -1
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js +5 -3
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js +25 -0
- package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
- package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
- package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js +25 -0
- package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
- package/lib/module/networking/xmppClient.js +64 -0
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/persistence.js +78 -5
- package/lib/module/roomStore/persistence.js.map +1 -1
- package/lib/module/roomStore/roomHeapSlice.js +4 -0
- package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +109 -0
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/types/models/attachment.model.js +2 -0
- package/lib/module/types/models/attachment.model.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/assets/icons.d.ts +6 -1
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/AlbumGrid.d.ts +21 -0
- package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts +17 -0
- package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble/MediaCaption.d.ts +12 -0
- package/lib/typescript/components/MessageBubble/MediaCaption.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/LastMessageItem.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
- package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts +9 -3
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/CallIcons.d.ts +9 -0
- package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts +7 -0
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callUiStore.d.ts +13 -0
- package/lib/typescript/components/VideoCalls/callUiStore.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +5 -0
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +12 -0
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts +10 -0
- package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/usePipTile.d.ts +46 -0
- package/lib/typescript/components/VideoCalls/usePipTile.d.ts.map +1 -0
- package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts +10 -0
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts +7 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts +7 -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/e2ee/fileEnvelope.d.ts +1 -1
- package/lib/typescript/e2ee/fileEnvelope.d.ts.map +1 -1
- package/lib/typescript/e2ee/sealedBody.d.ts +16 -0
- package/lib/typescript/e2ee/sealedBody.d.ts.map +1 -1
- package/lib/typescript/helpers/albumLayout.d.ts +66 -0
- package/lib/typescript/helpers/albumLayout.d.ts.map +1 -0
- package/lib/typescript/helpers/attachments.d.ts +55 -0
- package/lib/typescript/helpers/attachments.d.ts.map +1 -0
- package/lib/typescript/helpers/caption.d.ts +64 -0
- package/lib/typescript/helpers/caption.d.ts.map +1 -0
- package/lib/typescript/helpers/createMainMessageForThread.d.ts.map +1 -1
- package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
- package/lib/typescript/helpers/fileKind.d.ts +20 -0
- package/lib/typescript/helpers/fileKind.d.ts.map +1 -0
- package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
- package/lib/typescript/helpers/mapWithConcurrency.d.ts +9 -0
- package/lib/typescript/helpers/mapWithConcurrency.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaLimits.d.ts +13 -0
- package/lib/typescript/helpers/mediaLimits.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaSendRetry.d.ts +26 -0
- package/lib/typescript/helpers/mediaSendRetry.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaWireData.d.ts +16 -0
- package/lib/typescript/helpers/mediaWireData.d.ts.map +1 -0
- package/lib/typescript/helpers/mentionSpans.d.ts +8 -0
- package/lib/typescript/helpers/mentionSpans.d.ts.map +1 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts +7 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
- package/lib/typescript/helpers/readReceipts.d.ts +82 -0
- package/lib/typescript/helpers/readReceipts.d.ts.map +1 -0
- package/lib/typescript/helpers/repairFilenameEncoding.d.ts +12 -0
- package/lib/typescript/helpers/repairFilenameEncoding.d.ts.map +1 -0
- package/lib/typescript/helpers/safeJson.d.ts +2 -0
- package/lib/typescript/helpers/safeJson.d.ts.map +1 -0
- package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +1 -1
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +2 -0
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/stanzaHandlers.d.ts +7 -3
- package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +3 -0
- package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts.map +1 -0
- package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts +12 -0
- package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +3 -0
- package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts.map +1 -0
- package/lib/typescript/networking/xmppClient.d.ts +15 -0
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +67 -3
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/models/attachment.model.d.ts +52 -0
- package/lib/typescript/types/models/attachment.model.d.ts.map +1 -0
- package/lib/typescript/types/models/message.model.d.ts +26 -0
- package/lib/typescript/types/models/message.model.d.ts.map +1 -1
- package/lib/typescript/types/models/modal.model.d.ts +7 -0
- package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
- package/lib/typescript/types/models/room.model.d.ts +2 -0
- package/lib/typescript/types/models/room.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +69 -1
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +4 -1
- package/plugins/notification-service/Info.plist +31 -0
- package/plugins/notification-service/NotificationService.swift +82 -0
- package/plugins/withNotificationServiceExtension.js +137 -0
- package/src/assets/icons.tsx +20 -2
- package/src/components/MainComponents/AlbumGrid.tsx +183 -0
- package/src/components/MainComponents/ChatRoom.tsx +4 -2
- package/src/components/MainComponents/MediaMessage.tsx +246 -130
- package/src/components/MainComponents/MediaUploadOverlay.tsx +102 -0
- package/src/components/MessageBubble/MediaCaption.tsx +45 -0
- package/src/components/MessageBubble/Message.tsx +71 -3
- package/src/components/MessageBubble/MessageInteractions.tsx +2 -1
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +64 -0
- package/src/components/RoomComponents/LastMessageItem.tsx +15 -4
- package/src/components/RoomComponents/styled/LastAudioMessage.tsx +6 -3
- package/src/components/RoomComponents/styled/LastMessageFile.tsx +6 -2
- package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +6 -2
- package/src/components/RoomComponents/styled/LastMessageVideo.tsx +6 -2
- package/src/components/Thread/ThreadWrapper.tsx +5 -9
- package/src/components/VideoCalls/ActiveCallBar.tsx +56 -10
- package/src/components/VideoCalls/CallIcons.tsx +36 -12
- package/src/components/VideoCalls/VideoCallOverlay.tsx +205 -8
- package/src/components/VideoCalls/VideoCallSession.tsx +45 -13
- package/src/components/VideoCalls/callSessionController.ts +51 -20
- package/src/components/VideoCalls/callUiStore.ts +33 -3
- package/src/components/VideoCalls/livekitRuntime.ts +13 -0
- package/src/components/VideoCalls/useCallKeep.ts +204 -33
- package/src/components/VideoCalls/useOngoingCallNotification.ts +113 -0
- package/src/components/VideoCalls/usePipTile.ts +214 -0
- package/src/components/styled/MediaFilePreview.tsx +49 -34
- package/src/components/styled/MessageImage.tsx +21 -5
- package/src/components/styled/SendInput.tsx +101 -87
- package/src/components/styled/VideoMessage.tsx +34 -9
- package/src/context/xmppProvider.tsx +32 -0
- package/src/e2ee/fileEnvelope.ts +1 -1
- package/src/e2ee/sealedBody.ts +44 -5
- package/src/helpers/albumLayout.ts +207 -0
- package/src/helpers/attachments.ts +316 -0
- package/src/helpers/caption.ts +283 -0
- package/src/helpers/createMainMessageForThread.ts +6 -1
- package/src/helpers/createMessageFromXml.ts +21 -5
- package/src/helpers/fileKind.ts +38 -0
- package/src/helpers/getDataFromXml.ts +5 -1
- package/src/helpers/mapWithConcurrency.ts +32 -0
- package/src/helpers/mediaLimits.ts +27 -0
- package/src/helpers/mediaSendRetry.ts +59 -0
- package/src/helpers/mediaWireData.ts +57 -0
- package/src/helpers/mentionSpans.ts +17 -0
- package/src/helpers/mimeToExtension.ts +51 -0
- package/src/helpers/readReceipts.ts +219 -0
- package/src/helpers/repairFilenameEncoding.ts +82 -0
- package/src/helpers/safeJson.ts +11 -0
- package/src/helpers/updateMessagesTillLast.tsx +2 -1
- package/src/hooks/useSendMessage.tsx +448 -249
- package/src/i18n/strings.ts +144 -0
- package/src/main.ts +3 -0
- package/src/networking/api-requests/auth.api.ts +60 -3
- package/src/networking/stanzaHandlers.ts +91 -2
- package/src/networking/xmpp/handleStanzas.xmpp.ts +6 -2
- package/src/networking/xmpp/sendDisplayedMarker.xmpp.ts +31 -0
- package/src/networking/xmpp/sendMediaMessage.xmpp.ts +60 -3
- package/src/networking/xmpp/sendReceivedReceipt.xmpp.ts +31 -0
- package/src/networking/xmppClient.ts +48 -0
- package/src/roomStore/persistence.ts +94 -3
- package/src/roomStore/roomHeapSlice.ts +23 -1
- package/src/roomStore/roomsSlice.ts +112 -1
- package/src/types/models/attachment.model.ts +51 -0
- package/src/types/models/message.model.ts +29 -0
- package/src/types/models/modal.model.ts +7 -0
- package/src/types/models/room.model.ts +2 -0
- package/src/types/types.ts +83 -1
- package/src/version.ts +1 -1
- package/lib/commonjs/components/VideoCalls/useDraggable.js +0 -59
- package/lib/commonjs/components/VideoCalls/useDraggable.js.map +0 -1
- package/lib/module/components/VideoCalls/useDraggable.js +0 -55
- package/lib/module/components/VideoCalls/useDraggable.js.map +0 -1
- package/lib/typescript/components/VideoCalls/useDraggable.d.ts +0 -19
- package/lib/typescript/components/VideoCalls/useDraggable.d.ts.map +0 -1
- package/src/components/VideoCalls/useDraggable.ts +0 -46
|
@@ -18,6 +18,12 @@ var _clientRegistry = require("../utils/clientRegistry");
|
|
|
18
18
|
var _useEventHandlers = require("./useEventHandlers");
|
|
19
19
|
var _e2ee = require("../e2ee");
|
|
20
20
|
var _send = require("../e2ee/send");
|
|
21
|
+
var _limits = require("../e2ee/limits");
|
|
22
|
+
var _mapWithConcurrency = require("../helpers/mapWithConcurrency");
|
|
23
|
+
var _caption = require("../helpers/caption");
|
|
24
|
+
var _attachments = require("../helpers/attachments");
|
|
25
|
+
var _mediaLimits = require("../helpers/mediaLimits");
|
|
26
|
+
var _mediaSendRetry = require("../helpers/mediaSendRetry");
|
|
21
27
|
// Watchdog: if a message stays "pending" (no server echo) for this
|
|
22
28
|
// long after the optimistic dispatch, mark it failed so the bubble
|
|
23
29
|
// flips out of the "sending..." state. Covers the silent-failure
|
|
@@ -50,10 +56,48 @@ const MEDIA_PENDING_WATCHDOG_MS = 30_000;
|
|
|
50
56
|
let __sendIdSeq = 0;
|
|
51
57
|
const nextStanzaId = prefix => `${prefix}-${Date.now()}-${__sendIdSeq = __sendIdSeq + 1 >>> 0}`;
|
|
52
58
|
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
const
|
|
59
|
+
// Uploads in flight per send. A sealed (e2ee) file is encrypted on the device
|
|
60
|
+
// before it goes up, which is slow, so an e2ee send runs fewer at once.
|
|
61
|
+
const MEDIA_UPLOAD_CONCURRENCY = 4;
|
|
62
|
+
const MEDIA_E2EE_UPLOAD_CONCURRENCY = 2;
|
|
63
|
+
|
|
64
|
+
/** The local id of a tile until the upload gives it the server's `_id`. */
|
|
65
|
+
const localAttachmentId = (messageId, index) => `${messageId}:${index}`;
|
|
66
|
+
|
|
67
|
+
/** A tile without its local upload state (the file itself is unchanged). */
|
|
68
|
+
const withoutUploadState = attachment => {
|
|
69
|
+
const copy = {
|
|
70
|
+
...attachment
|
|
71
|
+
};
|
|
72
|
+
delete copy.uploadStatus;
|
|
73
|
+
delete copy.uploadProgress;
|
|
74
|
+
return copy;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** A picker uri as a plain file uri (iOS asset-library scheme rewritten). */
|
|
78
|
+
const normalizeFileUri = uri => typeof uri === 'string' ? uri.replace(/^assets-library:\/\//, 'file://') : '';
|
|
79
|
+
|
|
80
|
+
/** The file's own uri when it is on this device, for the sender's preview. */
|
|
81
|
+
const localPreviewUrl = uri => {
|
|
82
|
+
const normalized = normalizeFileUri(uri);
|
|
83
|
+
return /^(file|content):\/\//.test(normalized) ? normalized : undefined;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** One file as a failed send keeps it: plain fields only, so it persists. */
|
|
87
|
+
const toFailedFile = (file, fallbackType) => ({
|
|
88
|
+
uri: typeof file?.uri === 'string' ? file.uri : undefined,
|
|
89
|
+
type: file?.type || file?.mimeType || fallbackType || undefined,
|
|
90
|
+
name: file?.name || file?.fileName || undefined,
|
|
91
|
+
...(typeof file?.size === 'number' ? {
|
|
92
|
+
size: file.size
|
|
93
|
+
} : {}),
|
|
94
|
+
...(typeof file?.duration === 'number' ? {
|
|
95
|
+
duration: file.duration
|
|
96
|
+
} : {}),
|
|
97
|
+
...(typeof file?.waveForm === 'string' ? {
|
|
98
|
+
waveForm: file.waveForm
|
|
99
|
+
} : {})
|
|
100
|
+
});
|
|
57
101
|
const useSendMessage = _configOverride => {
|
|
58
102
|
const {
|
|
59
103
|
client
|
|
@@ -304,47 +348,91 @@ const useSendMessage = _configOverride => {
|
|
|
304
348
|
});
|
|
305
349
|
}
|
|
306
350
|
}, [editAction, client, user, langSource, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed, reduxStore]);
|
|
307
|
-
const sendMedia = (0, _react.useCallback)(async (data, type, activeRoomJID, isReply = false, isChecked = false, mainMessage = '', existingId) => {
|
|
351
|
+
const sendMedia = (0, _react.useCallback)(async (data, type, activeRoomJID, isReply = false, isChecked = false, mainMessage = '', existingId, caption) => {
|
|
308
352
|
if (!(0, _e2ee.canSendMediaToRoom)(activeRoomJID)) {
|
|
309
353
|
console.warn('media not sent: room is end-to-end encrypted');
|
|
310
|
-
return;
|
|
354
|
+
return false;
|
|
311
355
|
}
|
|
312
356
|
client?.onCriticalSend?.(activeRoomJID);
|
|
313
357
|
|
|
314
|
-
//
|
|
358
|
+
// One send = one message, whatever the caller handed us: a single file,
|
|
359
|
+
// the composer's array, or the saved list on a retry. Extra files past
|
|
360
|
+
// the cap are dropped here as well as in the composer.
|
|
361
|
+
const files = (Array.isArray(data) ? data : [data]).filter(file => !!file && typeof file === 'object').slice(0, (0, _mediaLimits.mediaFileCap)(config));
|
|
362
|
+
if (files.length === 0) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
const first = files[0];
|
|
366
|
+
const isE2ee = (0, _send.shouldEncrypt)(activeRoomJID);
|
|
367
|
+
const sizeLimit = (0, _mediaLimits.mediaSizeLimit)(config, isE2ee ? _limits.MAX_SEAL_BYTES : undefined);
|
|
368
|
+
const captionFields = (0, _caption.normalizeCaptionInput)(caption);
|
|
369
|
+
const id = existingId || `send-media-message:${(0, _uuid.v4)()}`;
|
|
370
|
+
|
|
371
|
+
// Everything a retry needs to replay this send, in selection order.
|
|
372
|
+
const failedPayload = () => ({
|
|
373
|
+
kind: 'media',
|
|
374
|
+
id,
|
|
375
|
+
roomJID: activeRoomJID,
|
|
376
|
+
data: toFailedFile(first, type),
|
|
377
|
+
type,
|
|
378
|
+
isReply,
|
|
379
|
+
isChecked,
|
|
380
|
+
mainMessage,
|
|
381
|
+
files: files.map(file => toFailedFile(file, type)),
|
|
382
|
+
...(captionFields ? {
|
|
383
|
+
caption: captionFields.caption,
|
|
384
|
+
...(captionFields.mentions ? {
|
|
385
|
+
captionMentions: captionFields.mentions
|
|
386
|
+
} : {})
|
|
387
|
+
} : {})
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Defensive size guard on every send path (the composer blocks it at
|
|
315
391
|
// pick time, but retries replay the saved payload straight here).
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
392
|
+
const oversize = files.find(file => typeof file?.size === 'number' && file.size > sizeLimit);
|
|
393
|
+
if (oversize) {
|
|
394
|
+
console.warn('media exceeds the size cap - not uploading', {
|
|
395
|
+
name: oversize?.name,
|
|
396
|
+
size: oversize?.size
|
|
320
397
|
});
|
|
398
|
+
const error = new Error(`File exceeds the ${Math.round(sizeLimit / (1024 * 1024))} MB upload limit`);
|
|
321
399
|
if (existingId) {
|
|
322
|
-
dispatch((0, _roomHeapSlice.markMessageFailed)(
|
|
323
|
-
kind: 'media',
|
|
324
|
-
id: existingId,
|
|
325
|
-
roomJID: activeRoomJID,
|
|
326
|
-
data,
|
|
327
|
-
type,
|
|
328
|
-
isReply,
|
|
329
|
-
isChecked,
|
|
330
|
-
mainMessage
|
|
331
|
-
}));
|
|
400
|
+
dispatch((0, _roomHeapSlice.markMessageFailed)(failedPayload()));
|
|
332
401
|
}
|
|
333
402
|
handleMessageFailed({
|
|
334
403
|
message: 'media',
|
|
335
404
|
roomJID: activeRoomJID,
|
|
336
|
-
error
|
|
405
|
+
error,
|
|
337
406
|
messageType: 'media'
|
|
338
407
|
});
|
|
339
|
-
return;
|
|
408
|
+
return false;
|
|
340
409
|
}
|
|
341
|
-
const id = existingId || `send-media-message:${(0, _uuid.v4)()}`;
|
|
342
410
|
const optimisticTimestamp = Date.now();
|
|
343
411
|
const optimisticDate = new Date(optimisticTimestamp).toISOString();
|
|
344
412
|
const selfId = user?.xmppUsername || user?.walletAddress || '';
|
|
345
413
|
const displayName = `${user?.firstName || ''} ${user?.lastName || ''}`.trim() || selfId;
|
|
346
|
-
const
|
|
347
|
-
const
|
|
414
|
+
const normalizedFileUri = normalizeFileUri(first?.uri);
|
|
415
|
+
const fileSizeStr = first?.size != null ? String(first.size) : '';
|
|
416
|
+
|
|
417
|
+
// One tile per file, in selection order. A tile's id is local until the
|
|
418
|
+
// upload returns the server's `_id`; the tile's upload state is keyed on it.
|
|
419
|
+
const tiles = files.map((file, index) => {
|
|
420
|
+
const localUrl = localPreviewUrl(file?.uri);
|
|
421
|
+
return {
|
|
422
|
+
attachmentId: localAttachmentId(id, index),
|
|
423
|
+
location: '',
|
|
424
|
+
mimetype: file?.type || file?.mimeType || type,
|
|
425
|
+
originalName: file?.name,
|
|
426
|
+
fileName: file?.name,
|
|
427
|
+
size: file?.size != null ? String(file.size) : undefined,
|
|
428
|
+
duration: file?.duration != null ? String(file.duration) : undefined,
|
|
429
|
+
...(localUrl ? {
|
|
430
|
+
localUrl
|
|
431
|
+
} : {}),
|
|
432
|
+
uploadStatus: 'uploading',
|
|
433
|
+
uploadProgress: 0
|
|
434
|
+
};
|
|
435
|
+
});
|
|
348
436
|
if (!config?.disableSentLogic && !existingId) {
|
|
349
437
|
dispatch((0, _roomsSlice.addRoomMessage)({
|
|
350
438
|
roomJID: activeRoomJID,
|
|
@@ -364,17 +452,22 @@ const useSendMessage = _configOverride => {
|
|
|
364
452
|
xmppId: id,
|
|
365
453
|
xmppFrom: `${activeRoomJID}/${selfId}`,
|
|
366
454
|
isMediafile: 'true',
|
|
367
|
-
fileName:
|
|
455
|
+
fileName: first?.name,
|
|
368
456
|
location: normalizedFileUri,
|
|
369
457
|
locationPreview: normalizedFileUri,
|
|
370
458
|
mimetype: type,
|
|
371
|
-
originalName:
|
|
459
|
+
originalName: first?.name,
|
|
372
460
|
size: fileSizeStr,
|
|
373
|
-
duration:
|
|
374
|
-
waveForm:
|
|
461
|
+
duration: first?.duration,
|
|
462
|
+
waveForm: first?.waveForm,
|
|
463
|
+
attachments: tiles,
|
|
375
464
|
isReply: isReply ? 'true' : 'false',
|
|
376
465
|
showInChannel: `${isChecked}`,
|
|
377
|
-
mainMessage
|
|
466
|
+
mainMessage,
|
|
467
|
+
...(captionFields ? {
|
|
468
|
+
caption: captionFields.caption,
|
|
469
|
+
captionMentions: captionFields.mentions
|
|
470
|
+
} : {})
|
|
378
471
|
}
|
|
379
472
|
}));
|
|
380
473
|
dispatch((0, _roomHeapSlice.addMessageToHeap)({
|
|
@@ -395,31 +488,25 @@ const useSendMessage = _configOverride => {
|
|
|
395
488
|
}));
|
|
396
489
|
}
|
|
397
490
|
|
|
398
|
-
// Silent-failure watchdog for media-send (bug #18).
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
|
|
402
|
-
|
|
491
|
+
// Silent-failure watchdog for media-send (bug #18). Re-armed on every
|
|
492
|
+
// retry, so a retried send gets its own window. While files are still
|
|
493
|
+
// going up it is not a failure: it waits one more window instead.
|
|
494
|
+
const armWatchdog = () => setTimeout(() => {
|
|
495
|
+
if (running) {
|
|
496
|
+
mediaWatchdog = armWatchdog();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
403
499
|
const state = reduxStore.getState();
|
|
404
500
|
const roomMsgs = state.rooms?.rooms?.[activeRoomJID]?.messages || [];
|
|
405
501
|
const stillPending = roomMsgs.find(m => m.id === id && m.pending);
|
|
406
502
|
const alreadyFailed = state.roomHeapSlice?.failedMessages?.[id];
|
|
407
503
|
if (stillPending && !alreadyFailed) {
|
|
408
|
-
console.warn(`Media-send watchdog fired
|
|
504
|
+
console.warn(`Media-send watchdog fired - ${id} stuck pending > ${MEDIA_PENDING_WATCHDOG_MS}ms; marking failed`);
|
|
409
505
|
// See the text-send watchdog above: drop the buffered replay so
|
|
410
506
|
// a later onOnline flush can't silently resend behind the
|
|
411
507
|
// "failed / tap to retry" bubble.
|
|
412
508
|
(0, _outboundQueue.removeOutboundSend)(id);
|
|
413
|
-
dispatch((0, _roomHeapSlice.markMessageFailed)(
|
|
414
|
-
kind: 'media',
|
|
415
|
-
id,
|
|
416
|
-
roomJID: activeRoomJID,
|
|
417
|
-
data,
|
|
418
|
-
type,
|
|
419
|
-
isReply,
|
|
420
|
-
isChecked,
|
|
421
|
-
mainMessage
|
|
422
|
-
}));
|
|
509
|
+
dispatch((0, _roomHeapSlice.markMessageFailed)(failedPayload()));
|
|
423
510
|
handleMessageFailed({
|
|
424
511
|
message: 'media',
|
|
425
512
|
roomJID: activeRoomJID,
|
|
@@ -428,138 +515,220 @@ const useSendMessage = _configOverride => {
|
|
|
428
515
|
});
|
|
429
516
|
}
|
|
430
517
|
}, MEDIA_PENDING_WATCHDOG_MS);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
518
|
+
const uploaded = files.map(() => undefined);
|
|
519
|
+
const rawResults = files.map(() => undefined);
|
|
520
|
+
const sealedUploads = files.map(() => undefined);
|
|
521
|
+
// Per-file key material, kept apart from the sealed upload: the upload
|
|
522
|
+
// is disposed once the message is assembled, but a send that fails after
|
|
523
|
+
// that point is retried and must still carry every key.
|
|
524
|
+
const keyMaterials = files.map(() => undefined);
|
|
525
|
+
let delivered = false;
|
|
526
|
+
let running = false;
|
|
527
|
+
const concurrency = isE2ee ? MEDIA_E2EE_UPLOAD_CONCURRENCY : MEDIA_UPLOAD_CONCURRENCY;
|
|
528
|
+
let mediaWatchdog = armWatchdog();
|
|
529
|
+
const publishTile = (index, patch) => {
|
|
530
|
+
const attachmentId = tiles[index]?.attachmentId;
|
|
531
|
+
if (config?.disableSentLogic || !attachmentId) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
dispatch((0, _roomsSlice.setMediaUploadState)({
|
|
535
|
+
roomJID: activeRoomJID,
|
|
536
|
+
messageId: id,
|
|
537
|
+
attachmentId,
|
|
538
|
+
...patch
|
|
539
|
+
}));
|
|
441
540
|
};
|
|
442
|
-
|
|
443
|
-
const
|
|
444
|
-
|
|
541
|
+
const missingIndices = () => uploaded.reduce((acc, item, index) => item ? acc : [...acc, index], []);
|
|
542
|
+
const uploadOne = async index => {
|
|
543
|
+
const file = files[index];
|
|
544
|
+
publishTile(index, {
|
|
545
|
+
uploadStatus: 'uploading',
|
|
546
|
+
uploadProgress: 0
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
// Helps RN's FormData polyfill build a proper multipart/file part
|
|
550
|
+
// (instead of serialising the JS object as JSON). On iOS the picker
|
|
551
|
+
// can return ph:// or assets-library:// URIs; coerce to file:// when
|
|
552
|
+
// possible so the body is a real blob.
|
|
553
|
+
const fileBlob = {
|
|
554
|
+
uri: normalizeFileUri(file?.uri) || file?.uri,
|
|
555
|
+
type: file?.type || file?.mimeType || type || 'application/octet-stream',
|
|
556
|
+
name: file?.name || file?.fileName || `media_${Date.now()}_${index}`
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
// In an e2ee room each file is sealed before it leaves the device:
|
|
560
|
+
// the server only ever sees opaque bytes under a random name. The
|
|
561
|
+
// per-file keys ride in the encrypted <body> (see sendMediaMessage).
|
|
562
|
+
if (isE2ee) {
|
|
563
|
+
sealedUploads[index]?.dispose();
|
|
564
|
+
sealedUploads[index] = undefined;
|
|
445
565
|
const {
|
|
446
566
|
sealPickedFile
|
|
447
567
|
} = require('../e2ee/sealedFiles');
|
|
448
|
-
|
|
568
|
+
sealedUploads[index] = await sealPickedFile({
|
|
449
569
|
uri: fileBlob.uri,
|
|
450
570
|
name: fileBlob.name,
|
|
451
571
|
type: fileBlob.type,
|
|
452
|
-
size: typeof
|
|
572
|
+
size: typeof file?.size === 'number' ? file.size : undefined
|
|
453
573
|
});
|
|
454
574
|
}
|
|
575
|
+
const sealed = sealedUploads[index];
|
|
576
|
+
if (sealed) {
|
|
577
|
+
keyMaterials[index] = sealed.keyMaterial;
|
|
578
|
+
}
|
|
455
579
|
const part = sealed ? {
|
|
456
580
|
uri: sealed.uri,
|
|
457
581
|
type: 'application/octet-stream',
|
|
458
582
|
name: sealed.name
|
|
459
583
|
} : fileBlob;
|
|
460
584
|
const options = {
|
|
461
|
-
clientEncrypted: !!sealed
|
|
585
|
+
clientEncrypted: !!sealed,
|
|
586
|
+
onProgress: percent => publishTile(index, {
|
|
587
|
+
uploadProgress: percent
|
|
588
|
+
})
|
|
589
|
+
};
|
|
590
|
+
const post = field => {
|
|
591
|
+
const fd = new FormData();
|
|
592
|
+
fd.append(field, part);
|
|
593
|
+
return (0, _auth.uploadFileV2)(fd, activeRoomJID, options);
|
|
462
594
|
};
|
|
463
|
-
|
|
464
|
-
fd.append('files', part);
|
|
595
|
+
let response;
|
|
465
596
|
try {
|
|
466
|
-
|
|
597
|
+
response = await post('files');
|
|
467
598
|
} catch (err) {
|
|
468
|
-
if (err?.response?.status
|
|
469
|
-
|
|
470
|
-
name: part.name,
|
|
471
|
-
type: part.type
|
|
472
|
-
});
|
|
473
|
-
const fd2 = new FormData();
|
|
474
|
-
fd2.append('file', part);
|
|
475
|
-
return await (0, _auth.uploadFileV2)(fd2, activeRoomJID, options);
|
|
599
|
+
if (err?.response?.status !== 500) {
|
|
600
|
+
throw err;
|
|
476
601
|
}
|
|
477
|
-
|
|
602
|
+
console.warn('upload "files" field returned 500 - retrying with "file" (singular)', {
|
|
603
|
+
name: part.name,
|
|
604
|
+
type: part.type
|
|
605
|
+
});
|
|
606
|
+
response = await post('file');
|
|
607
|
+
}
|
|
608
|
+
const raw = Array.isArray(response?.data?.results) ? response.data.results[0] : undefined;
|
|
609
|
+
if (!raw) {
|
|
610
|
+
throw new Error('media_upload_empty_response');
|
|
478
611
|
}
|
|
612
|
+
uploaded[index] = (0, _attachments.toUploadedAttachment)(raw);
|
|
613
|
+
rawResults[index] = raw;
|
|
614
|
+
// The bytes are up; the message waits for its siblings.
|
|
615
|
+
publishTile(index, {
|
|
616
|
+
uploadStatus: 'uploading',
|
|
617
|
+
uploadProgress: 100
|
|
618
|
+
});
|
|
479
619
|
};
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
620
|
+
const sendAssembled = async () => {
|
|
621
|
+
const raws = rawResults;
|
|
622
|
+
const attachments = uploaded;
|
|
623
|
+
const head = raws[0];
|
|
624
|
+
const messagePayload = {
|
|
625
|
+
firstName: user.firstName,
|
|
626
|
+
lastName: user.lastName,
|
|
627
|
+
walletAddress: user.walletAddress,
|
|
628
|
+
createdAt: head.createdAt,
|
|
629
|
+
expiresAt: head.expiresAt,
|
|
630
|
+
fileName: head.filename,
|
|
631
|
+
isVisible: head?.isVisible,
|
|
632
|
+
location: head.location,
|
|
633
|
+
locationPreview: head.locationPreview,
|
|
634
|
+
mimetype: head.mimetype,
|
|
635
|
+
originalName: head?.originalname,
|
|
636
|
+
ownerKey: head?.ownerKey,
|
|
637
|
+
size: head.size,
|
|
638
|
+
duration: head?.duration ?? first?.duration,
|
|
639
|
+
waveForm: first?.waveForm,
|
|
640
|
+
updatedAt: head?.updatedAt,
|
|
641
|
+
userId: head?.userId,
|
|
642
|
+
attachmentId: head?._id,
|
|
643
|
+
// Only when there is more than one file: sendMediaMessage stamps
|
|
644
|
+
// the list on <data> and leaves a single-file stanza untouched.
|
|
645
|
+
attachments: attachments.length > 1 ? attachments : undefined,
|
|
646
|
+
caption: captionFields?.caption,
|
|
647
|
+
captionMentions: captionFields?.mentions,
|
|
648
|
+
wrappable: true,
|
|
649
|
+
roomJid: activeRoomJID,
|
|
650
|
+
showInChannel: isChecked,
|
|
651
|
+
isReply,
|
|
652
|
+
mainMessage,
|
|
653
|
+
isPrivate: head?.isPrivate,
|
|
654
|
+
__v: head.__v,
|
|
655
|
+
// One key per sealed file, in selection order.
|
|
656
|
+
e2eeKeys: isE2ee ? keyMaterials : undefined
|
|
657
|
+
};
|
|
487
658
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
isVisible: item?.isVisible,
|
|
497
|
-
location: item.location,
|
|
498
|
-
locationPreview: item.locationPreview,
|
|
499
|
-
mimetype: item.mimetype,
|
|
500
|
-
originalName: item?.originalname,
|
|
501
|
-
ownerKey: item?.ownerKey,
|
|
502
|
-
size: item.size,
|
|
503
|
-
duration: item?.duration ?? data?.duration,
|
|
504
|
-
waveForm: data?.waveForm,
|
|
505
|
-
updatedAt: item?.updatedAt,
|
|
506
|
-
userId: item?.userId,
|
|
507
|
-
attachmentId: item?._id,
|
|
508
|
-
wrappable: true,
|
|
509
|
-
roomJid: activeRoomJID,
|
|
510
|
-
showInChannel: isChecked,
|
|
511
|
-
isReply,
|
|
512
|
-
mainMessage,
|
|
513
|
-
isPrivate: item?.isPrivate,
|
|
514
|
-
__v: item.__v,
|
|
515
|
-
e2eeKeys: sealed ? [sealed.keyMaterial] : undefined
|
|
516
|
-
};
|
|
517
|
-
if (sealed) {
|
|
659
|
+
// The local copies of sealed files are remembered for the sender and
|
|
660
|
+
// the scratch ciphertext is dropped.
|
|
661
|
+
if (isE2ee) {
|
|
662
|
+
const {
|
|
663
|
+
rememberOpened
|
|
664
|
+
} = require('../e2ee/sealedFiles');
|
|
665
|
+
for (let index = 0; index < files.length; index++) {
|
|
666
|
+
const item = attachments[index];
|
|
518
667
|
try {
|
|
519
|
-
const {
|
|
520
|
-
rememberOpened
|
|
521
|
-
} = require('../e2ee/sealedFiles');
|
|
522
668
|
await rememberOpened(item.location, {
|
|
523
|
-
uri:
|
|
524
|
-
name:
|
|
525
|
-
type:
|
|
526
|
-
size: typeof
|
|
669
|
+
uri: normalizeFileUri(files[index]?.uri) || files[index]?.uri,
|
|
670
|
+
name: files[index]?.name,
|
|
671
|
+
type: files[index]?.type || files[index]?.mimeType || type,
|
|
672
|
+
size: typeof files[index]?.size === 'number' ? files[index].size : undefined
|
|
527
673
|
});
|
|
528
674
|
} catch (err) {
|
|
529
675
|
console.warn('could not keep the sent attachment', err);
|
|
530
676
|
}
|
|
531
|
-
|
|
677
|
+
sealedUploads[index]?.dispose();
|
|
678
|
+
sealedUploads[index] = undefined;
|
|
532
679
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Replace the optimistic tiles with the uploaded files. A sealed
|
|
683
|
+
// message keeps its local tiles (the server copies are ciphertext) and
|
|
684
|
+
// only drops the upload state. `pending` is left alone: only the
|
|
685
|
+
// server echo confirms the message.
|
|
686
|
+
if (!config?.disableSentLogic) {
|
|
687
|
+
dispatch((0, _roomsSlice.setMessageAttachments)({
|
|
688
|
+
roomJID: activeRoomJID,
|
|
689
|
+
messageId: id,
|
|
690
|
+
attachments: isE2ee ? tiles.map(withoutUploadState) : attachments.map((attachment, index) => {
|
|
691
|
+
const localUrl = tiles[index]?.localUrl;
|
|
692
|
+
return localUrl ? {
|
|
693
|
+
...attachment,
|
|
694
|
+
localUrl
|
|
695
|
+
} : attachment;
|
|
696
|
+
})
|
|
697
|
+
}));
|
|
698
|
+
}
|
|
699
|
+
const effectiveMediaClient = [client, (0, _clientRegistry.getGlobalXmppClient)(), _roomStore.store.getState()?.chatSettingStore?.client].find(c => c && c.status === 'online');
|
|
700
|
+
if (effectiveMediaClient) {
|
|
701
|
+
effectiveMediaClient.setActiveRoomJid?.(activeRoomJID);
|
|
702
|
+
await Promise.resolve(effectiveMediaClient.prioritizeRoomPresence?.(activeRoomJID)).catch(() => false);
|
|
703
|
+
effectiveMediaClient.sendMediaMessageStanza(activeRoomJID, messagePayload, id);
|
|
704
|
+
try {
|
|
705
|
+
effectiveMediaClient.ensureStreamAlive?.();
|
|
706
|
+
} catch {}
|
|
707
|
+
} else {
|
|
536
708
|
// Same online-only guard as the text path: a surviving-but-offline
|
|
537
|
-
// client must NOT be used
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
} catch {}
|
|
552
|
-
(0, _outboundQueue.enqueueOutboundSend)({
|
|
553
|
-
optimisticId: id,
|
|
554
|
-
roomJID: activeRoomJID,
|
|
555
|
-
enqueuedAt: Date.now(),
|
|
556
|
-
// Match the media watchdog so a reconnect within the (longer)
|
|
557
|
-
// media window still auto-replays the buffered stanza.
|
|
558
|
-
ttlMs: MEDIA_PENDING_WATCHDOG_MS,
|
|
559
|
-
send: c => c.sendMediaMessageStanza(activeRoomJID, messagePayload, id)
|
|
560
|
-
});
|
|
561
|
-
}
|
|
709
|
+
// client must NOT be used. Buffer the stanza for the reconnect flush.
|
|
710
|
+
const anyMediaClient = client || (0, _clientRegistry.getGlobalXmppClient)() || _roomStore.store.getState()?.chatSettingStore?.client;
|
|
711
|
+
try {
|
|
712
|
+
anyMediaClient?.forceReconnect?.();
|
|
713
|
+
} catch {}
|
|
714
|
+
(0, _outboundQueue.enqueueOutboundSend)({
|
|
715
|
+
optimisticId: id,
|
|
716
|
+
roomJID: activeRoomJID,
|
|
717
|
+
enqueuedAt: Date.now(),
|
|
718
|
+
// Match the media watchdog so a reconnect within the (longer)
|
|
719
|
+
// media window still auto-replays the buffered stanza.
|
|
720
|
+
ttlMs: MEDIA_PENDING_WATCHDOG_MS,
|
|
721
|
+
send: c => c.sendMediaMessageStanza(activeRoomJID, messagePayload, id)
|
|
722
|
+
});
|
|
562
723
|
}
|
|
724
|
+
|
|
725
|
+
// The upload time is spent: the wait for the server echo gets a full
|
|
726
|
+
// watchdog window of its own, not what was left of the upload's.
|
|
727
|
+
clearTimeout(mediaWatchdog);
|
|
728
|
+
mediaWatchdog = armWatchdog();
|
|
729
|
+
delivered = true;
|
|
730
|
+
(0, _mediaSendRetry.unregisterMediaRetry)(id);
|
|
731
|
+
dispatch((0, _roomHeapSlice.clearMessageFailure)(id));
|
|
563
732
|
await handleMessageSent({
|
|
564
733
|
message: 'media',
|
|
565
734
|
roomJID: activeRoomJID,
|
|
@@ -572,59 +741,73 @@ const useSendMessage = _configOverride => {
|
|
|
572
741
|
fileData: data,
|
|
573
742
|
fileType: type,
|
|
574
743
|
messageId: id,
|
|
575
|
-
uploadResults:
|
|
744
|
+
uploadResults: raws
|
|
576
745
|
}
|
|
577
746
|
});
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
// was rejected (axios collapses the message to "Request failed
|
|
585
|
-
// with status code N"; the actual reason lives in
|
|
586
|
-
// `error.response.data`).
|
|
587
|
-
const uriStr = typeof data?.uri === 'string' ? data.uri : '';
|
|
588
|
-
const uriScheme = uriStr.match(/^([a-z]+):/i)?.[1] ?? 'unknown';
|
|
589
|
-
console.error('upload failed', {
|
|
590
|
-
status: error?.response?.status,
|
|
591
|
-
statusText: error?.response?.statusText,
|
|
592
|
-
serverBody: error?.response?.data,
|
|
593
|
-
requestUrl: error?.config?.url,
|
|
594
|
-
axiosMessage: error?.message,
|
|
595
|
-
axiosCode: error?.code,
|
|
596
|
-
axiosCauseMessage: error?.cause?.message,
|
|
597
|
-
uri: uriStr,
|
|
598
|
-
uriScheme,
|
|
599
|
-
mime: fileBlob.type,
|
|
600
|
-
fileSizeBytes: data?.size ?? null,
|
|
601
|
-
fileName: fileBlob.name,
|
|
602
|
-
platformOS: _reactNative.Platform.OS,
|
|
603
|
-
platformVersion: _reactNative.Platform.Version
|
|
604
|
-
});
|
|
605
|
-
dispatch((0, _roomHeapSlice.markMessageFailed)({
|
|
606
|
-
kind: 'media',
|
|
607
|
-
id,
|
|
608
|
-
roomJID: activeRoomJID,
|
|
609
|
-
data,
|
|
610
|
-
type,
|
|
611
|
-
isReply,
|
|
612
|
-
isChecked,
|
|
613
|
-
mainMessage
|
|
614
|
-
}));
|
|
747
|
+
};
|
|
748
|
+
const failMessage = error => {
|
|
749
|
+
console.error('Media send failed:', error);
|
|
750
|
+
// Every file stays held: the bubble shows Failed, and Retry replays
|
|
751
|
+
// the files that did not make it (in-session) or the whole list.
|
|
752
|
+
dispatch((0, _roomHeapSlice.markMessageFailed)(failedPayload()));
|
|
615
753
|
handleMessageFailed({
|
|
616
754
|
message: 'media',
|
|
617
755
|
roomJID: activeRoomJID,
|
|
618
756
|
error: error,
|
|
619
757
|
messageType: 'media'
|
|
620
758
|
});
|
|
621
|
-
}
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Uploads `indices` (a retry passes only the files that failed), then
|
|
763
|
+
* sends once nothing is missing. Any failure leaves the message failed
|
|
764
|
+
* with its tiles marked, ready for a retry.
|
|
765
|
+
*/
|
|
766
|
+
const run = async indices => {
|
|
767
|
+
if (delivered || running) {
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
running = true;
|
|
771
|
+
clearTimeout(mediaWatchdog);
|
|
772
|
+
mediaWatchdog = armWatchdog();
|
|
773
|
+
try {
|
|
774
|
+
await (0, _mapWithConcurrency.mapWithConcurrency)(indices, concurrency, async index => {
|
|
775
|
+
try {
|
|
776
|
+
await uploadOne(index);
|
|
777
|
+
} catch (error) {
|
|
778
|
+
console.error('upload failed', {
|
|
779
|
+
status: error?.response?.status,
|
|
780
|
+
serverBody: error?.response?.data,
|
|
781
|
+
axiosMessage: error?.message,
|
|
782
|
+
fileName: files[index]?.name,
|
|
783
|
+
fileSizeBytes: files[index]?.size ?? null,
|
|
784
|
+
platformOS: _reactNative.Platform.OS
|
|
785
|
+
});
|
|
786
|
+
publishTile(index, {
|
|
787
|
+
uploadStatus: 'failed',
|
|
788
|
+
uploadProgress: 0
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
if (missingIndices().length > 0) {
|
|
793
|
+
throw new Error('media_upload_failed');
|
|
794
|
+
}
|
|
795
|
+
await sendAssembled();
|
|
796
|
+
return true;
|
|
797
|
+
} catch (error) {
|
|
798
|
+
failMessage(error);
|
|
799
|
+
return false;
|
|
800
|
+
} finally {
|
|
801
|
+
running = false;
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
(0, _mediaSendRetry.registerMediaRetry)(id, indices => run(missingIndices().filter(position => indices === undefined || indices.includes(position))));
|
|
805
|
+
return run(files.map((_, index) => index));
|
|
622
806
|
}, [client, config, user, dispatch, handleMessageSent, handleMessageFailed, reduxStore]);
|
|
623
807
|
|
|
624
|
-
// Retry a previously-failed send
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
// it. No-op when the id isn't in the failed map.
|
|
808
|
+
// Retry a previously-failed send. An in-session send re-runs only the files
|
|
809
|
+
// still missing (its runner is still registered); after a restart the
|
|
810
|
+
// saved payload is replayed as a whole. No-op when the id isn't failed.
|
|
628
811
|
const retryMessage = (0, _react.useCallback)(async failedId => {
|
|
629
812
|
const payload = reduxStore.getState().roomHeapSlice?.failedMessages?.[failedId];
|
|
630
813
|
if (!payload) {
|
|
@@ -653,9 +836,17 @@ const useSendMessage = _configOverride => {
|
|
|
653
836
|
// Re-use the failed message's id so the retry resends in place
|
|
654
837
|
// instead of spawning a duplicate bubble.
|
|
655
838
|
failedId);
|
|
656
|
-
|
|
657
|
-
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
if ((0, _mediaSendRetry.hasMediaRetry)(failedId)) {
|
|
842
|
+
await (0, _mediaSendRetry.retryMediaSend)(failedId);
|
|
843
|
+
return;
|
|
658
844
|
}
|
|
845
|
+
const list = Array.isArray(payload.files) && payload.files.length > 0 ? payload.files : payload.data;
|
|
846
|
+
await sendMedia(list, payload.type, payload.roomJID, payload.isReply, payload.isChecked, payload.mainMessage, failedId, payload.caption ? {
|
|
847
|
+
text: payload.caption,
|
|
848
|
+
mentions: payload.captionMentions
|
|
849
|
+
} : undefined);
|
|
659
850
|
}, [reduxStore, dispatch, handleMessageRetry, sendMessage, sendMedia]);
|
|
660
851
|
|
|
661
852
|
// ChatRoom/ThreadWrapper consume this as the "edit branch" of send.
|